GUI库:使本机应用程序具备Windows窗体的简易性
2010-10-15 09:07:42 来源:Web开发网处理每个窗口
通常是您(编程人员)决定对象存在多长时间。但是,GUI 编程中一个很大的问题是可视窗口和窗口对象之间存在区别 — 决定何时关闭窗口的是用户。因此,在您的代码中,您可以设置指向窗口已被用户销毁的窗口对象的有效指针或对它的引用。由于这使维护一对一对应关系(也就是说屏幕上的一个窗口代表一个对象实例,反之亦然)变得困难,所以由此方案产生的一个明确限制就是您无法拥有本地窗口实例(当作用域存在时将被销毁):
{
form f(...);
f.show();
...
}
假定您的窗体 f 显示在屏幕上。当您退出 f 的作用域时,会发生什么?您有两种选择:在销毁与该窗体对应的 C++ 实例时,销毁该(屏幕上)窗体或将其留在屏幕上。两个选择都是不合理的。在第一种情况下,用户可能会感到迷惑,不知道该窗体哪里去了。在第二种情况下,虽然您将窗体留在屏幕上,但因为其对应的 C++ 实例不在了,所以它不会响应任何事件。此外,用户可能已在当 f 位于作用域中时关闭了此屏幕上窗体。因此您应中止对不存在于屏幕上的对象的处理。
解决方案:始终通过(间接)指针访问窗口。然后,当此用户关闭屏幕上窗口时,相应的 C++ 实例会标记为无效;如果您尝试访问它,将引发异常。您总是可以了解某窗口是否有效,并可以自行销毁该窗口,如下所示:
wnd<> w = ...;
// is window valid?
if ( is_valid(w) ) w->do_something();
// is window valid?
if ( w) w->do_something();
// destroy the window
delete_(w);
由于屏幕上的每个窗口都有一个相应的 C++ 实例,您将使用 wnd<> 模板类处理窗口,该类代表指向窗口的共享(引用计数)指针。wnd<> 类具有一个可选参数:窗口类型。这基本上在您预想之中。默认情况下,此参数为 window_base。它也可以是文本、标签、rebar、编辑等窗口类。图 3 显示了几个使用多种窗口对象并在它们之间进行转换的示例。
图 3 创建窗口对象并转换
// when constructing a window, you can specify its type
wnd<> w = new_<form>(parent);
w->bg_color( rgb(0,0,0));
// when constructing a window, if you don't specify its type,
// it will guess it, based on who you assign it to
wnd<button> b = new_(w, rect(10,10,200,20) );
b->events.click += &my_func;
// destroying a window
delete_(b);
// casting - if it fails, it throws
wnd<form> f = wnd_cast(w);
// casting - if it fails, returns null
if ( wnd<edit> e = try_wnd_cast(e) )
e->text = "not nullio";
请注意,使用 new_ 函数创建窗口,使用 delete_ 函数删除窗口(同样,通常是由用户关闭窗口)。另外,如果您拥有一个类型为 X(默认为 window_base)的窗口,并希望知道它是否也属于类型 Y,就可以使用转换。转换始终是显式的。转换可以分为两类:wnd_cast,如果失败,将引发异常;try_wnd_cast,如果失败,将返回空窗口。
开发 eGUI++ 类时,除从其基类派生的行为之外,您有时希望继承一些其他行为,例如调整大小、更换外观等。在这种情况下,您可以创建多个可再用的行为类,然后从这些行为类派生其他行为类。
直观的代码
看到 GUI 代码易于编写和阅读是很让人兴奋的。我在此书中用尽各种办法来确保代码补全功能提供尽可能多的帮助。处理大型 GUI 库时,总会有一些容易遗忘的内容:属性名、事件名称、标志等。我已对其一一进行处理。我曾经使用 doxygen 处理文档;效果很好。我越常使用,就越喜欢它。
浏览文档变得非常简单。要查看属性名,只需键入 w->,便可以看到方法和属性,如图 4 所示(属性显示为成员变量,以便于区分)。对于事件名称,记住类可以处理的事件是很容易的;只需键入 class_name::ev:: 和范围运算符,之后代码补全功能便会启动并向您显示事件。但处理标志才是 eGUI++ 真正的亮点所在。对于每个可由标志组成的属性,要找出可用的标志选项,只需向该标志属性添加“.”,这样代码补全功能就再次派上用场了。作为补充,我还为属性添加了运算符重载。因此,以下代码是有效的:
w->text = "hello";
w->text += " world";
w->style |= w->style.tiled;
图 4 代码补全功能
为了防止忘记您可以自由支配的控件列表,我已专门为该列表添加了名为 egui::ctrl 的命名空间。
赞助商链接