在前面的文章中我们讲述了WxPython可以作什么。在这篇文章中我们将详细讨论WxPython是如何工作的。实际上WxPython是一套封装了C ++接口的wxWidgets(窗口小部件)。wxWidgets项目的发展已经有很长时间了,WxPython中几乎所有的功能都是由它实现的。通过 WxPython你可以通过Python而不是C++适用wxWidgets中的大部分功能。WxPython集成了这两个软件的功能,另外 WxPython本省也提供了更多的功能。为了让WxPython运行一个称为SWIG的工具用于产生封装的函数功能,它允许Python程序调用C++ wxWidget函数库。尽管SWIG已经完成了大部分工作,我们还是需要一些工具来使WxPython对象像其它Python库那样被Python调 用。还有一些非C++库的WxPython的专业工具包,你会在随后的讲述中了解到他们的使用。在这篇文章中我们讲大概的讲述一下Python语言和C+ + wxWidget工具箱。
Python 语言 Python语言非常易于适用他有类似与Perl的脚本语言的特性,同时对于大型应用的开发由具备C++和Java语言的特性。利用简单整洁的语法结构和 简洁的语义模式,Python语言可以把多个简单的模块结合成复杂的应用。在后续的文章中我假定读者已经了解Python语言并明白Python的基本概 念,诸如如何导入包和类等的方法。当然你不必是一个Python语言的专家,但是你应该能够读懂本文随后讲解中的例子。如果你想了解Python语言的详 细内容你可以在Python的网站上找到文档以及教程www.python.org/doc。
Python中一个很重要的功能是动态解析,这对于语言的学习和调试非常有用。安装完Python之后需要设置环境变量,然后在命令行中键入python 命令。你会看到一个>>>符号,这是Python的命令行模式。在这里你可以输入Python表达式,它的值会立刻显示到屏幕上。比 如:
$ python
Python 2.3.3c1 (#50, Dec 4 2003, 21:27:34) [MSC v.1200 32 bit (Intel)] on
win32
Type "help", "copyright", "credits" or "license" for more information.
>>> 2 + 2
4
>>> 10 / 3
3
>>> zip(['a', 'b', 'c'], [1, 2, 3])
[('a', 1), ('b', 2), ('c', 3)]
>>>
在上面的简短描述中,我们列示了一些简单的用法,使用Python内置的zip函数将两个列表对象压缩到一个列表对象中。你可以在交互模式下完成很多工作,比如导入包,定义函数,定义类等等。
wxWidget工具箱
wxPython中的另一个重要的部分是wxWidget工具箱。实质上,wxWidget是一个由C++实现的GUI框架,这意味着它是一套封装了C+ +类工具包。尽管wxWidget主要用于GUI应用程序,它还是包含了很多对于C++程序员非常有用的功能,包括很多ANSIC++未提供的数据结构实 现等,比如字符串、哈希表,以及一些与系统有关的实现比如socket和线程。由于这些功能已经在Python 中实现或者Python标注库中已经提供。因此wxWidget的封装中并不提供以上提到的支持。WxPython一般只提供wxWidget中GUI的 支持,wxWidget的设计目标是为C++提供通用的GUI支持,通过wxWidget编写的C++GUI程序在不同的平台下只要作很少的修改就可以编 译运行。
下面是一个简单的C++ wxWidget程序,这个程序摘自Robert Roebling有关wxWidget指南的站点。这个程序创建了一个空白窗口,窗口上有一个包含连个项目的菜单。这个例子主要为了比较本文中C++实现与Python实现的不同之处。
例子:WxWidget的C++实现 |
#include "wx/wx.h" class MyApp: public wxApp {
virtual bool OnInit();
}; class MyFrame: public wxFrame {
public:
MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size); void OnQuit(wxCommandEvent& event); void OnAbout(wxCommandEvent& event); DECLARE_EVENT_TABLE()
}; enum {
ID_Quit = 1, ID_About,
};
BEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_MENU(ID_Quit, MyFrame::OnQuit) EVT_MENU(ID_About, MyFrame::OnAbout) END_EVENT_TABLE() IMPLEMENT_APP(MyApp)
bool MyApp::OnInit() { MyFrame *frame = new MyFrame("Hello World", wxPoint(50,50), wxSize(450,340)); frame->Show(TRUE); SetTopWindow(frame); return TRUE; }
MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) : wxFrame((wxFrame *)NULL, -1, title, pos, size) {
wxMenu *menuFile = new wxMenu; menuFile->Append( ID_About, "&About..." ); menuFile->AppendSeparator(); menuFile->Append( ID_Quit, "E&xit" ); wxMenuBar *menuBar = new wxMenuBar; menuBar->Append( menuFile, "&File" ); SetMenuBar( menuBar ); CreateStatusBar(); SetStatusText( "Welcome to wxWidgets!" );
} void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) {
Close(TRUE);
} void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) { wxMessageBox("This is a wxWidgets Hello world sample", "About Hello World", wxOK | wxICON_INFORMATION, this); } |
如果你熟悉C++你会发现上面的代码少了些东西,通常C++程序都有一个main()函数,这是程序的开始位置。在wxWidget程序中宏 IMPLEMENT_APP(MyApp)自动构建了一个main函数,这个函数负责了wxWidget程序的初始化。
像大多数平台中立的工具一样,展现在程序员面前的类实际上是一系列子类。一般来说针对不同的平台wxWidget都会提供一个子类,子类会根据不同的平台自动加载。在写这篇文章的时候目前支持以下几个平台:
- Microsoft Windows
- Mac OS
- GTK,大多是Unix平台都支持。
对于不同的平台wxWidget都会试图适用本地的窗口和功能,并模仿本地GUI的样子。如果你熟悉其它大型的面向对象的接口工具箱,比如MFC或者 Java 的Swing,wxWidget和他们非常类似。与这些工具的一个不同之处是wxWidget不会创建一个包含组件的容器类(比如Java Swing中会创建JComponent和JContainer类),wxWidget增加子对象的方法是将所有的对象加到wxWindow基类上。
wxWidget的开发很早之前就开始了,项目最早由爱丁堡大学的人工智能项目的Julian Smart于1992年创建。Smart试图创建一个可以在Unix和Windows下运行的程序。wxWidget的名称来自于这两个操作系统w来自 Windows而x来自Unix。最初版本中对于Windows平台是利用MFC写成的,而Unix是XView。但是,很快XView被Motif工具 箱代替,而MFC被代替未Windows API.。到了1997年整个系统中建立了大量丰富的API,随后GTK+成了Unix上的标准。之后Macintosh版本的也于下一年发布了。
Python不是唯一与wxWidgets绑定的语言,虽然它有很大的用户群。wxWidgets站点上的链接指出目前支持的语言有Ada, Basic, C#, Eiffel, Euphoria, Haskell,Java, JavaScript, Lua, Perl, 以及Ruby。
wxWidget和Python都非常优秀。灵活的Python语言使WxPython比起C++开发wxWidget更加简单。下表列出了wxPython环境和C++环境开发的不同之处。
C++环境 |
wxPython环境 |
内存控制由程序员负责 |
内存控制由Python语言负责 |
静态类型造成多态实现复杂 |
动态类型更容易实现多态 |
程序引用非常有限 |
程序引用简单,提供强大的抽象功能 |
函数无法当作参数使用 |
函数可以像其它变量一样当作参数传递 |
程序运行之前必须编译 |
程序可以动态解析 |
之前我们用C++完成了一个hell world程序,下面是一个wxPython版本的程序:
wxPython写的hello world程序 |
import wx class MyApp(wx.App):
def OnInit(self):
frame = MyFrame("Hello World", (50, 60), (450, 340)) frame.Show() self.SetTopWindow(frame) return True
class MyFrame(wx.Frame):
def __init__(self, title, pos, size):
wx.Frame.__init__(self, None, -1, title, pos, size) menuFile = wx.Menu() menuFile.Append(1, "&About...") menuFile.AppendSeparator() menuFile.Append(2, "E&xit") menuBar = wx.MenuBar() menuBar.Append(menuFile, "&File") self.SetMenuBar(menuBar) self.CreateStatusBar() self.SetStatusText("Welcome to wxPython!") self.Bind(wx.EVT_MENU, self.OnAbout, id=1) self.Bind(wx.EVT_MENU, self.OnQuit, id=2)
def OnQuit(self, event):
self.Close()
def OnAbout(self, event):
wx.MessageBox("This is a wxPython Hello world sample", "About Hello World", wx.OK | wx.ICON_INFORMATION, self)
if __name__ == '__main__':
app = MyApp(False) app.MainLoop()
|
这里有两个与C++程序比较中不同的地方需要提出来。首先wxPython不需要一个宏来创建main函数,而是在模块的最后自己声明。其次两个程序的运 行机制是不同的,wxPython通过wx.Bind()来动态进行事件处理的传输。而C++需要通过DECLARE_EVENT_TABLE 和BEGIN_EVENT_TABLE宏来完成。除了上面的区别,你会发现Python程序非常清晰易读。Python语言提供了简单的语法以及自动的垃 圾回收机制。它还是一个平台独立的运行环境,对于快速开发GUI应用来说非常有效。
wxPython和wxWidget还在不断的发展,未来还将提供移动设备和多媒体的支持。更多有关wxPython版本信息可以查看www.wxpython.org站点。