用 wxWidget 构建跨平台的 GUI (2)
- UID
- 1066743
|
用 wxWidget 构建跨平台的 GUI (2)
定义方法现在,可以开始定义一些方法了。我这里给出了三个简单的方法,第一个是清单 3 中所示的 OnInit() 方法。
清单 3. OnInit() 方法1
2
3
4
5
| bool DemoApp::OnInit() {
DemoFrame *frame = new DemoFrame("DeveloperWorks Demo");
frame->Show(true);
return true;
}
|
该方法的前两行的用途在 GUI 程序的开头部分很常见:它们创建和显示主窗口。第三行对应用程序的其余部分非常重要。如果返回 true,则向 wxWidgets 引擎的其余部分发出一个信号表明初始化已经成功完成,程序可以继续。相反,如果返回 false,则应用程序会停止并退出。
OnInit() 方法为 DemoFrame 引用构造函数。在该方法,可以向框架添加按钮,如清单 4 所示。
清单 4. 向框架添加按钮1
2
3
4
5
6
7
8
| DemoFrame:emoFrame(const wxString& title)
: wxFrame(NULL, wxID_ANY, title) {
wxSizer *sizer = new wxBoxSizer(wxVERTICAL);
this->SetSizer(sizer);
wxButton *button = new wxButton(this, wxID_CLOSE, "Click Me");
sizer->Add(50, 50);
sizer->Add(button, 0, wxALL, 50);
}
|
但是在可以向框架添加按钮之前,需要先创建 sizer。wxWidgets 中的 Sizer 相当于 Java 编程语言中的布局管理器:它们允许您使用预定义的规则在窗口中放置对象,而不需要单独为每个窗口小部件设置大小和位置。本例中使用了 wxBoxSizer,它将窗口小部件布局在一条直线上。一个方框 sizer 可以是垂直的也可以是水平的。创建 sizer 之后,使用 SetSizer() 方法将它附加到了框架。然后创建按钮。按钮构造函数的参数有:
- 父窗口小部件(本例中为框架)
- 一个整型 ID
- 按钮要显示的标签
不必显式地将按钮添加到框架,只要将框架标识为父容器就可以了。但必须将按钮显式地添加到 sizer,以便 sizer 的布局算法知道它。在方法的最后一行实现这一点,但必须是在行的顶部添加了 50 x 50 像素的空白之后。当添加按钮时,sizer 还会用 50 像素的边框围绕按钮。这可以通过使用 wxALL 标志和最后一个参数 50 来实现。
定义事件处理程序最后,需要定义简单的事件处理程序,如清单 5 所示。
清单 5. 一个简单的事件处理程序1
2
3
| void DemoFrame::OnButtonPress(wxCommandEvent& event) {
Close(true);
}
|
这再简单不过了。编译后会得到如图 2 所示的包含有一个按钮的窗口。单击按钮,窗口会关闭。在 wxWidgets,关闭最后一个父框架会自动退出应用程序,所以单击此按钮也会导致完全退出应用程序。
图 2. 示例窗口在本例中还刚刚接触到用 wxWidgets 所能实现的功能的皮毛。进一步的探索请参阅 部分的指南。
wxPythonwxWidgets 确实是一种功能强大的工具包,但并不是所有人都愿意使用 C++ 析构函数、内存管理等等。所幸的是一组优秀的程序员已经创建了到 wxWidgets 库的、可从其他编程语言使用的包装程序绑定。所以,即使所选择使用的编程工具不是 C++ ,仍然可以从 wxWidgets 库获益。
发展得最为成熟和全面的 wxWidgets 绑定是 wxPython, 通过它可以使用 Python 编程语言创建 wxWidgets 程序。有针对 Microsoft® Windows®、Mac 和 Linux® 平台的下载,其用户社区规模也很大并十分活跃。想了解一下它?清单 6 中给出的 Python 程序可以创建与前面在 C++ 中创建的一样的空白窗口。
清单 6. Python 空白窗口应用程序1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| #!/usr/bin/env python
import wx
class DemoApp(wx.App):
def OnInit(self):
frame = DemoFrame(parent=None, id=-1, title='DeveloperWorks')
frame.Show()
return True
class DemoFrame(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title)
sizer = wx.BoxSizer(wx.VERTICAL)
self.SetSizer(sizer)
button = wx.Button(self, wx.ID_CLOSE, "Click Me")
sizer.Add((50, 50))
sizer.Add(button, 0, wx.ALL, 50)
self.Bind(wx.EVT_BUTTON, self.OnButtonClick)
def OnButtonClick(self, event):
self.Close(True)
if __name__ == "__main__":
app = DemoApp()
app.MainLoop()
|
如您所见,在这样一个短小的程序中,在 C++ API 调用和 wxPython 调用之间几乎存在一对一的对应。在两种情况下,都创建了一个应用程序对象和一个框架对象。二者都以 OnInit() 方法开头,并且定义了相似的构造函数和对象处理程序。
本例中最大的不同是事件到处理程序的绑定。C++ 版本使用事件表宏管理该绑定,而 Python 版本则使用 Bind() 方法来管理,这个方法将代表事件类型的 Python 对象和在事件被调用时实际调用的对象作为参数。这种结构利用了 Python 可以将方法视为变量并可以将它们作为参数传递(传递的方式与传递字符串或整数相同)的优势。
wxPython 较 C++ wxWidgets 工具包的优势在更长或更复杂一些的程序中会更明显。即使不将 C++ 和 Python 作为两种编程语言进行专门的对比,wxPython 工具包的一些吸引人的优秀特性仍然非常具有吸引力。使用 Bind() 方法的事件处理机制融合进 wxPython 中比融合进 wxWidgets 中更容易。在 Python 版本中更容易在运行时动态地更新处理程序。一些复杂或复合的窗口小部件,比如树状列表控件或图像单选按钮,是 wxPython 工具包中的标准组件,但在 C++ 版中不是的。而且,wxPython 包含开发工具的 Py 程序包,它使得向 wxPython 程序添加交互式调试变得很简单。
wxEverythingElsePython 并不是惟一一种具有访问 wxWidgets 库的绑定的编程语言。虽然 wxPython 是其中最为成熟的一种,如果更愿意使用某种特定的编程语言,很值得了解一下其余的几个。既然这样,就让我们在 wxWorld 中的几个地方稍作停留吧。请注意这些项目的可靠性和健壮性的评估基于可用资料。在这些项目中,很多都源自一两个专家程序员对其的热爱。如果对某个项目感兴趣,请务必自己查看一下。
wxPerl wxPerl 绑定是在 2006 年 6 月正式发布的。它已重新开始了日常快照的交付,但可用的文档却是几年前编制的。活动邮件列表的范围一般都是一天两个或三个消息。有针对 Win32、Linux 和 Mac OS X 的二进制下载。除了主要的工具包,还有一些附加工具包可用,包括 OpenGL 包装程序和用于创建 Mac OS X 应用程序的程序包。
wxPerl 的主要问题在于如何将 wxWidgets API 翻译成 Perl 中的面向对象编程(OOP)的有些异质的变体。清单 7 中所示的代码片段与前面所给出的框架示例有些相似。
清单 7. 一个 wxPerl 窗口示例1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| package MyFrame;
use base 'Wx::Frame';
use Wx::Event qw(EVT_BUTTON);
sub new {
my $class = shift;
my $self = $class->SUPER::new(undef, -1, 'Trying wxPerl',
[-1, -1], [250, 200]);
my $sizer = Wx::BoxSizer->new(wxVERTICAL);
my $button = Wx::Button->new($self, -1, 'Click me!', [-1, -1],
[-1, -1]);
EVT_BUTTON($self, $button, \&OnButtonClick);
$sizer->Add($button);
$self->SetSizer($sizer);
return $self;
}
sub OnButtonClick {
my($self, $event) = @_;
$self->SetTitle('You Did It');
}
|
这段代码基本上是前面已经见过的 C++ 和 Python 代码的逐行翻译。在本例中,wxWidgets 库是 Perl 程序包的形式,而且使用了 EVT_BUTTON 函数调用,这看起来很像 C++ 版本中的宏定义。
wxRubywxRuby 项目现在的情况比较复杂。在最早的版本中,到 wxWidgets API 的绑定是手工创建的。该工具最近的版本于 2004 年 11 月发布,但从那时开始,对新的版本的开发就时断时续,新版本利用更强大的 Simplified Wrapper and Interface Generator(SWIG)工具包来生成 Ruby 和 wxWidgets 之间的绑定。在其邮件列表中对新版本发布时间的陈述常常是 “很快但也可能要几个月以后”。
wxRuby 另一个有趣的方面是,与大多数其他的 wxWidgets 绑定不同,开发人员大都选择对 wxWidgets API 调用的名称进行调整以更符合 Ruby 命名约定(具体来说,要采用 lower_case_with_underscores 而非 wxWidgets 的 UpperCaseWithCamelCase)。所以,上述所有代码示例使用 SetSizer() 函数,在 wxRuby 中会称为 set_sizer()。 除此之外,涉及到 wxWidgets API 的大部分 wxRuby 程序都将与前面已经给出的示例相似。
wxWidgets 的世界其他 wxWidgets 端口完成与否的程度各不相同。以下是关于其余 wxWidgets 的概括:
- wxBasic 既是一种基本语言解释程序又是一个 wxWidgets 绑定的集合。其新版本的发布正在准备中(最近的测试版是在 2006 年 5 月发布的)。
- wxEuphoria 最近的版本于 2005 年 12 月发布,是 Euphoria 编程语言的一种绑定。
- wxJS 是 wxWidgets 的 JavaScript 端口。只在 Windows 系统被测试过,包含有一个可执行文件来运行 JavaScript 脚本。它最近的版本也是在 2006 年 5 月发布的。其开发人员称下个版本会增加对 Linux 的支持。
- wxLua 是 Lua 编程语言的一种绑定。它支持跨平台,内存占用相对较小,最近的版本于 2006 年 3 月发布。
- wx.NET 项目绑定 C# 到 wxWidgets。其最近的一次发布时间是 2005 年 7 月。
结束语wxWidgets 可以为各类程序员提供大量的可用功能。其基本工具包非常灵活,能够处理您的大多数 GUI 需求。多种语言绑定让大多数程序员都能得心应手地使用 wxWidgets。充分了解所选择的语言中的 wxWidgets 工具包将有助于您在自己的应用程序中构建优秀的界面。 |
|
|
|
|
|