使用WxPython进行Win32下Python编程

 

1
另一种可供Python使用的GUI工具包叫做wxPython。目前这个工具对于Python环境来说还是陌生的,但正在Python开发者中间快速地流行起来。wxPython是Python扩展模块,它封装了wxWindows C++类库。wxPython是一个为Python提供的交叉平台GUI框架工具,它在Windows平台上相当成熟。它是基于流行的wxWindows C++框架的Python,为GUI开发者提供了一种有吸引力的替代工具。

wxWindows

  wxWindows是一个自由C++编程框架,被设计用来实现跨平台编程。wxWindows 2.0支持Windows 3.1/95/98/NT,Unix下支持GTK/Motif/Lesstif,还有正在开发中的Mac版本。其它系统正在考虑中。wxWindows是一套库函数,允许C++应用程序只需要微量的源代码改动,就可在几种不同类型的机构上编译和运行。每一种支持的GUI都有一个对应的库( 象Motif或Windows)。同时为了实现GUI功能提供了通用的API,还为了处理一些通常要用到的操作系统设备提供了功能,应用程序可以根据需要使用或替换,这样就会节省大量的编码工作。基本数据结构,象字符串,链表,和哈希表也提供了。控件的本地版本,通用对话框,和其它的窗口类型被用在支持它们的平台上。对于其它的平台,相适应的替代品使用wxWindows自身来生成。例如,在W in32平台上,使用了本地的列表控件,但是在GTK,具有相似功能的通用列表控件则是使用wxWindows类库创建的。
  有经验的Windows程序员对于wxWindows对象模型会感到象是在家一样。类和原则的许多地方都很相似。例如,多文档界面,用GDI对象,如刷子,笔,在上下文设置上绘图,等等。

wxWdinws + Python = wxPython

  wxPython是一个Python扩展模块,它提供了一套从wxWindows库到Python语言的绑定。换句话说,扩展模块允许Python程序员创建wxWindows类的实例,并且调用这些类的方法。wxPython扩展模块试图近可能的将wxWindows的类的层次也镜像下来。这就是说在wxPython中有一个wxFrame的类,看上去,闻上去,尝上

去和行为上几乎同C ++版本中的wxFrame一样。wxPython与C++版本如此接近,这样wxPython文档的大多数实际上是对C++文档中,wxPython与之不同地方的注解。其中还包含了一系列的例子程序,和一系列帮助程序员开始使用w xPython的文档页

 

2

哪里可以得到wxPython

  wxPython的最新版本可以在http://alldunn.com/wxPython/上找到。你可以从这个站点下载一个Win32系统的自安装软件,其中包含一个已经生成好的扩展模块,H TML帮助格式文档,和一组示例程序。也可以从这个站点获得Linux RPM,wxPython源码,原始的HTML文档,和其它站点的链接,邮件列表,wxPython FAQ,等等。如果你想自已从源代码创建wxPython,你也需要wxWindows源代码,可以从http://www.wxwindows.org/得到。

下一步去哪里?

  实践证明,学习的最好方法就是动手,接着做实验,观察得到的结果。所以你应该下载和安装wxPython,启动你常用的文本编辑器,准备执行在下面几节所读到的东西。

一个简单的例子

  应该对下面的小wxPython程序进行熟悉,当读到跟着的解释时,可以回过头来进行参考:

from wxPython.wx import *

class MyApp(wxApp):
    def OnInit(self):
        frame = wxFrame(NULL, -1, "Hello from wxPython")
        frame.Show(true)
        self.SetTopWindow(frame)
        return true

app = MyApp(0)
app.MainLoop()

  一个基本的wxPython程序要做的第一件事情就是导入整个wxPython库,使用 from wxPython import * 语句。这是编wxPython程序的通常习惯,但是你可以根据需要明确地执行更多限制的导入。每一个wxPython应用程序需要从wxApp派生出一个类,并且为其提供一个OnInit 方法。框架(即窗口)会调用这个方法作为自身初始化序列的一部分。Oninit通常是用来创建窗口,和对于程序开始运行完全必需的操作。在例子中,你创建了一个没有父亲的框架,标题是“Hello from wxPython ”,然后显示它。我们也可以在它的构造函数中为框架指定位置和大小,但是因为没有,所以这里使用了缺省值。OnInit方法的最后两行可能对于所有应用程序来说都是一样的。SetTopWindow方法告诉wxWindows ,这个框架是应用程序主框架其中之一(在这个例子中只有一个),并且你返回true来表明成功。当所有项层窗口实关闭,应用程序结束。脚本的最后两行可能又是对于所有的wxPython应用程序是一样的。你创建了一个应用程序类的实例,并且调用它的MainLoop方法。MainLoop是应用程序的心脏:在这里事情被处理,并且被发送到各个窗口,当最后一个窗口关闭后,它返回。幸运的是,wxWindows对你屏蔽了各种GUI工具包在事件处理上的不同。

 
3

 大多数情况下,你会想要定制应用程序的主框架,所以使用普通的wxFrame是不够的。你可能希望,从wxFrame派生出自已的类进行定制。下一个例子定义了一个框架类,并且在应用程序中的OnInit方法中创建了一个实例。注意除了在OnInit中创建的类的名字,MyApp代码的其它部分同以前的例子是一样的。

from wxPython.wx import *

ID_ABOUT = 101
ID_EXIT = 102


class MyFrame(wxFrame):
    def __init__(self, parent, ID, title):
        wxFrame.__init__(self, parent, ID, title,wxDefaultPosition, wxSize(200, 150))
        self.CreateStatusBar()
        self.SetStatusText("This is the statusbar")
        menu = wxMenu()
        menu.Append(ID_ABOUT, "&About","More information about this program")
        menu.AppendSeparator()
        menu.Append(ID_EXIT, "E&xit", "Terminate the program")
        menuBar = wxMenuBar()
        menuBar.Append(menu, "&File");
        self.SetMenuBar(menuBar)

class MyApp(wxApp):
    def OnInit(self):
        frame = MyFrame(NULL, -1, "Hello from wxPython")
        frame.Show(true)
        self.SetTopWindow(frame)
        return true

app = MyApp(0)
app.MainLoop()

  这个例子显示了一些wxFrame内建的一些功能。例如,为框架创建一个状态条只要简单地调用一个方法。框架本身会自动地管理它的位置,大小,和绘制。另一方面,如果你想定制状态条,从你自已的wxStatusBar派生类创建实例,并将其附加到框架上。
  在这个例子中也演示了创建一个简单的菜单条和一个下拉菜单。期待的菜单功能全部都支持:层叠子菜单,可核选的项,弹出菜单等等;你要做的只是创建一个菜单对象,向它追加菜单项。菜单项可以是象这里显示的文本,或其它的菜单。每一项你可以有选择地指定一些简单的帮助性文本,就象我们所做的。当菜单项被选中,这些文本会自动地显示在状态条上。

 

4
  在wxPython中的事件上一个例子没有做的一件事情就是:展示如何让菜单自动做一些事情。如果你运行这个例子,并且从菜单中选中Exit,什么都没有发生。下一个例子改正了这个小问题。为了在wxPython中处理事件,任何方法(或同样方式的独立函数)都可以使用工具包中的帮助性函数与任意事件相连。wxPython也提供了一个wxEvent 类,和一整串派生类,包含了事件的细节。每次当发生一个事件,一个方法被调用,一个从wxEvent 派生的对象被做为一参数传递,事件对象的实际类型要依赖于事件的类型。wxSizeEvent用于当窗口改变大小,wxCommandEvent用于菜单选择和按钮点击,wxMouseEvent用于(可以猜到)鼠标的移动,等等。
  为了解决上一个例子中的小问题,你要做的就是,在MyFrame构造函数中增加两行,并且增加处理事件的一些方法。我们也演示了一个通用对话框,w xMessageDialog。下面就是代码。


from wxPython.wx import *

ID_ABOUT = 101
ID_EXIT = 102


class MyFrame(wxFrame):
    def __init__(self, parent, ID, title):
        wxFrame.__init__(self, parent, ID, title,wxDefaultPosition, wxSize(200, 150))
        self.CreateStatusBar()
        self.SetStatusText("This is the statusbar")
        menu = wxMenu()
        menu.Append(ID_ABOUT, "&About","More information about this program")
        menu.AppendSeparator()
        menu.Append(ID_EXIT, "E&xit", "Terminate the program")
        menuBar = wxMenuBar()
        menuBar.Append(menu, "&File");
        self.SetMenuBar(menuBar)

        EVT_MENU(self, ID_ABOUT, self.OnAbout)
        EVT_MENU(self, ID_EXIT, self.TimeToQuit)

    def OnAbout(self, event):
        dlg = wxMessageDialog(self, "This sample program shows off\n"
                                "frames, menus, statusbars, and this\n""message dialog.",
                                 "About Me", wxOK | wxICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()

    def TimeToQuit(self, event):
        self.Close(true)

class MyApp(wxApp):
    def OnInit(self):
        frame = MyFrame(NULL, -1, "Hello from wxPython")
        frame.Show(true)
        self.SetTopWindow(frame)
        return true

app = MyApp(0)
app.MainLoop()

  在这里调用的EVT_MENU函数是一个帮助性函数,是为了将事件与方法连在一起。有时候,如果你将函数调用翻译成英语,它可以帮助我们理解发生了什么。第一个说的是,“对于任一个菜单项选中事件,发送窗口本身和一个ID_ABOUT的ID号,调用self.OnAbout方法。”
    有很多EVT_*帮助性函数,所有的都对应某个事件类型,或事件。下面将常用的一些事件列出。
    请参阅wxPython文档了解更多的细节。常见wxPython事件函数事件函数事件描述

EVT_SIZE
由于用户干预或由程序实现,当一个窗口大小发生改变时发送给窗口。

EVT_MOVE
由于用户干预或由程序实现,当一个窗口被移动时发送给窗口。

EVT_CLOSE
当一个框架被要求关闭时发送给框架。除非关闭是强制性的,否则可以调用event.Veto(true)来取消关闭。

EVT_PAINT
无论何时当窗口的一部分需要重绘时发送给窗口。

EVT_CHAR
当窗口拥有输入焦点时,每产生非修改性(Shift键等等)按键时发送。

EVT_IDLE
这个事件会当系统没有处理其它事件时定期的发送。

EVT_LEFT_DOWN
鼠标左键按下。

EVT_LEFT_UP
鼠标左键抬起。

EVT_LEFT_DCLICK
鼠标左键双击。

EVT_MOTION
鼠标在移动。

EVT_SCROLL
滚动条被操作。这个事件其实是一组事件的集合,如果需要可以被单独捕捉。

EVT_BUTTON
按钮被点击。

EVT_MENU
菜单被选中

 

5

用Python创建一个Doubletalk浏览器

  Ok, 现在让我们做些有用的东西,用这种方法学习更多关于wxPython框架的知识。就象其它的GUI工具包所展示的,我们将创建一个小型的应用程序,围绕着Doubletalk类库(它允许浏览和编辑交易)。

MDI框架:我们打算实现一个多文档界面(译注,即MDI),子框架除了为独立的“文档”外,其中还包含着交易数据的不同视图。如同前面的例子,要做的第一件事就是创建一个应用程序类,并且在它的O nInit方法中创建一个主框架:

from wxPython.wx import *

class DoubleTalkBrowserApp(wxApp):
    def OnInit(self):
        frame = MainFrame(NULL)
        frame.Show(true)
        self.SetTopWindow(frame)
        return true

app = DoubleTalkBrowserApp(0)
app.MainLoop()


  因为我们正在使用MDI,所以需要一个特别的类用来做为框架的基本类。这里的给出主程序框架的初始化方法的代码:

class MainFrame(wxMDIParentFrame):
    title = "Doubletalk Browser - wxPython Edition"

    def __init__(self, parent):
        wxMDIParentFrame.__init__(self, parent, -1, self.title)
        self.bookset = None
        self.views = []
        if wxPlatform == ’__WXMSW__’:
            self.icon = wxIcon(’chart7.ico’, wxBITMAP_TYPE_ICO)
            self.SetIcon(self.icon)

# 创建一个状态条,在右边显示时间和日期
        sb = self.CreateStatusBar(2)
        sb.SetStatusWidths([-1, 150])
        self.timer = wxPyTimer(self.Notify)
        self.timer.Start(1000)
        self.Notify()
        menu = self.MakeMenu(false)
        self.SetMenuBar(menu)
        menu.EnableTop(1, false)

        EVT_MENU(self, ID_OPEN, self.OnMenuOpen)
        EVT_MENU(self, ID_CLOSE, self.OnMenuClose)
        EVT_MENU(self, ID_SAVE, self.OnMenuSave)
        EVT_MENU(self, ID_SAVEAS,self.OnMenuSaveAs)
        EVT_MENU(self, ID_EXIT, self.OnMenuExit)
        EVT_MENU(self, ID_ABOUT, self.OnMenuAbout)
        EVT_MENU(self, ID_ADD, self.OnAddTrans)
        EVT_MENU(self, ID_JRNL, self.OnViewJournal)
        EVT_MENU(self, ID_DTAIL, self.OnViewDetail)
        EVT_CLOSE(self, self.OnCloseWindow)

  很明显,我们没有展示全部的代码,但是随着我们一点一点地学习,我们将最终将其变得完整。
  注意,使用wxMDIParentFrame作为MainFrame的基类。通过使用这个类,你会自动地获得为实现MDI应用程序的所有需要的东西,不需要关心在外表后面发生了什么。wxMDIParentFrame 类有着与wxFrame类同样的接口,只是拥有一些额外的方法。通常将一个单文档接口程序改为一个多文档程序只是象改变应用程序派生类的基类一样容易。对于wxMDIParentFrame 类,存在相对应的wxMDIChildFrame类,用于作文档窗口,

在后面就会看到。如果你需要处理MDI父窗口的客户区域(或背景区域),你可以使用 wxMDIClientWindow类。你可以使用它来在所有子窗口的后面放置一个背景图像。
   在文件对话框成功完成之后,要做的第一件事就是询问对话框被选中的路径名是什么,然后使用这个路径来修改框架的标题,然后打开一个BookSet文件。
  看一下后面一行。它重新使BookSet菜单有效,因为现在已经存在一个打开文件了。它实际是两行语句合成一句,相当于这两行:

menu = self.GetMenuBar()
menu.EnableTop(1, true)

  因为当用户打开一个文件时,让他们确实地看到一些东西是有意义的,你应该创建并且显示其中一个视图,用上面的OnMenuOpen处理函数中最后几行代码。在下面,我们会看到。


wxListCtrl

  日志视图是由wxListCtrl组成,其中每一个交易都有一个单行的小计。这个控件放置在wxMDIChildFrame中,并且因为它是框架中唯一的东西,所以不用担心设置或维护大小,框架会自动维护它。(不幸地是,因为某些平台在不同的时间发送第一个改变大小(resize)事件,有时候窗口显示时,它的子窗口大小会不正确。)

class JournalView(wxMDIChildFrame):
    def __init__(self, parent, bookset, editID):
        wxMDIChildFrame.__init__(self, parent, -1, "")
        self.bookset = bookset
        self.parent = parent
        tID = wxNewId()
        self.lc = wxListCtrl(self, tID, wxDefaultPosition,
wxDefaultSize, wxLC_REPORT)

## Forces a resize event to get around a minor bug...
        self.SetSize(self.GetSize())
        self.lc.InsertColumn(0, "Date")
        self.lc.InsertColumn(1, "Comment")
        self.lc.InsertColumn(2, "Amount")
        self.currentItem = 0
      
        EVT_LIST_ITEM_SELECTED(self, tID, self.OnItemSelected)
        EVT_LEFT_DCLICK(self.lc, self.OnDoubleClick)
      
        menu = parent.MakeMenu(true)
        self.SetMenuBar(menu)
      
        EVT_MENU(self, editID, self.OnEdit)
        EVT_CLOSE(self, self.OnCloseWindow)

        self.UpdateView()

你可能感兴趣的:(使用WxPython进行Win32下Python编程)