wxWidgets是一个使用C++语言实现的GUI框架,这意味着它是一系列C++类,其中风装了很多特性。虽然wxWidgets主要用来开发UI应用程序,但是它也包含了很多C++程序员可以使用的特性,包括ANSI C++中不支持的数据结构的实现,例如字符串,HashTable,另外也包含诸如网络套接字和线程等系统特性的接口。由于这些特性已经存在于Python语言或者python标准库中了,所以这些wxWidgets类的包装器wxPython并没有提供,你应该使用Python中的对等对象。
wxWidgets的目的是允许一个C++程序从一个平台迁移到另外一个平台的时候为了编译和运行只需要修改很少的代码,并且能够在不同的平台间保持一个的观感。
一下是一个C++ wxWidgets程序,这个程序来自于wxWidgets网站上Robert Roebling的教程。这个程序创建了一个带有两个元素(退出和关于)的菜单的空白窗口,展示这些内容的主要原因是为了与Python代码进行比较:
#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++的程序原来说可能会存在一定困惑,为什么没有main()函数?
在wxWidgets中,宏IMPLEMENT_APP(MyApp)自动建立一个默认的main方法,这个方法管理wxWidgets程序的初始化。
与大部分跨平台的接口工具包一样,对程序元可见的类和方法实际上都是一些列子类的代理。通常情况下wxWidgets可以运行的每一个平台都有一个子类(是否还记得Abstract Factory Pattern?),与当前平台相关的子类会自动被使用,现在wxWidget主要支持一下一些平台:
- Microsoft Windows
- Mac OS
- Gnome Toolkit(GTK+)在大部分现代Unix系统中都可以使用
在每一个平台下,wxWidgets尝试使用合适的本地部件和特性,通常尽量模仿本地观感。
如果你说西大型的,面向对象的接口工具包,例如MFC或者Java Swing,你会感觉到wxWidgets的基本结构很相似。唯一不同的地方是wxWidget并没有明确区分部件和包含其他部件的容器(例如Java Swing中的JComponent和JContainer)。也就是说可以前在地在任何部件上追加部件,不管它们是不是所谓的容器。
wxWidgets起源与1992年,由Julian Smart在University of Edinburgh’s Artificial Intelligence Applications Institute创建。当时Smart需要一种机能在Unix又能在Windows下运行的软件,现有的商用工具包都特别贵,所以他编写了自己的工具包。其中wx的含义分别是Windows中的w和Unix中的x。
wxWidgets除了支持Python开发之外,还支持Ada, Basic, C#, Eiffel, Euphoria, Haskell, Java, JavaScript, Lua, Perl 和 Ruby。
Python + wxWidgets:
python使得wxWidgets的开发不像C++那么困难。
而wxWidgets使得Python的GUI不但具有了本地话的观感而且具有了本地化的速度。
C++ 环境 | Python 环境 |
程序员负责内存管理 | Python负责内存管理 |
静态类型,多态困难 | 动态类型,多态很容易 |
程序反射非常有限 | 程序反射容易,允许强大的抽象 |
不能很容易地使用函数作为参数(函数式编程) | 函数可以像其他参数一样传递 |
每次运行之前需要编译 | 运行时解析 |
以下是使用wxPython完成的相同的程序,详细参看代码:
#!/usr/bin/env python import wx 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 Python!") 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) class MyApp(wx.App): def OnInit(self): frame = MyFrame("Hello World!", (50, 60), (450, 340)) frame.Show() self.SetTopWindow(frame) return True if __name__ == "__main__": app = MyApp(False) app.MainLoop()
相对于wxidget C++程序来说有两点内容需要说明:
- wxPython没有自动的宏来生成main函数,因此我们必须自己声明main方法
- python允许方便地传递函数,所以可以直接是哟功能wx.Bind()方法,而C++必须使用DECLARE_EVENT_TABLE和BEGIN_EVENT_TABLE两个宏