GUI库:使本机应用程序具备Windows窗体的简易性
2010-10-15 09:07:42 来源:Web开发网菜单、快捷方式以及类似项
如果以前进行过 GUI 编程,您应该知道按下菜单命令和按下键都会导致发送 WM_COMMAND。因此,当您收到 WM_COMMAND 时,很难知道该事件是来自控件还是菜单(或者说键盘快捷方式)。eGUI++ 通过直接将菜单放置在窗体(对话框)上来解决此问题的第一方面。如果发送到窗体的命令不是来自按钮,便是来自菜单。
这样可保护菜单命令。现在让我们看一下快捷方式。快捷方式的问题是可以随时键入(例如,在编辑框中时)。键盘快捷方式(加速器)首先路由到即时窗口,然后路由到承载该窗口的窗体,接着路由到窗体的父级,并沿层次结构向上路由直至到达最上面的窗口。您第一次找到该快捷方式的事件处理程序时,处理便停止(给定快捷方式不会由两个或多个窗口处理)。
剩下的就是工具栏 — 它们与菜单和快捷方式紧密相关。当按下工具栏按钮时,该事件会转换成菜单命令并直接路由到承载它的窗体(无论该命令是来自菜单、快捷方式或者工具栏按钮,都无关紧要)。
假设您正在实现一个窗体以处理菜单命令,如下所示:
void on_menu_command( ev::menu&,
menu::some_menu_id) { ... }
要处理 new_file 和 open_file 这两个菜单命令,您需要创建以下处理程序:
void on_menu_command( ev::menu&,
menu::new_file) { ... }
void on_menu_command( ev::menu&,
menu::open_file) { ... }
选项卡控件和窗体
选项卡是极为常用的 GUI 模式。我已扩展了选项卡控件,以允许 tab_type 属性使用标准值或 one_dialog_per_tab 值(在这种情况下,该控件可承载其他窗体)。在后一种情况下,您可以添加新的窗体,如下所示:
tab->add_form<form_type>( new_([args]) );
要添加我前面提到的登录窗体,您应编写:
tab->add_form<login>( new_() );
当添加至少一个窗体后,您便可以指定此选项卡窗体可承载的选项卡的数目:
tab->count = 5;
这里,我需要五个选项卡。这会选用最后添加的窗体,并根据需要多次进行复制。假设以前只有一个选项卡,则需要将第一个选项卡上的窗体另外克隆四次。没错。您可以克隆现有的任何窗口!
到目前为止,我已向您介绍了事件的侵入式处理。换句话说,就是扩展窗口类并最终响应其事件(或者说,在实现窗体时,响应其通知)。但是,您有时需要实现应用于多个窗口(彼此有些不相关)的行为。
例如,调整大小和改变外观。您可以以侵入的方式(创建实现该行为的那些类,然后从那些类派生 GUI 类)实现这类行为。但是,这会使代码复杂化,而且这并非始终可行(以改变外观为例)。通过非侵入方式实现行为,可以在其他应用程序中重用这种行为,也可以轻松关闭它。
例如,创建非侵入式事件处理程序类,再创建其实例,然后注册它。创建完新窗口后,会通知您的处理程序实例,而您可以选择是否监视此实例。如果选择监视,则需要手动指定需要监视的事件,如下所示:
// monitor button clicks
struct btn_handler : non_intrusive_handler {
void on_new_window_create(wnd<> w) {
if ( wnd<button> b = try_cast(w)) {
b->events.on_click += mem_fn(&on_click,this);
}
}
void on_click(button::ev::click&) { ... }
};
注册事件处理程序很容易。只需执行以下代码:
btn_handler bh;
window_base::add_non_intrusive_handler(bh);
可以使用多种方式实现可调整大小行为,具体取决于您的应用程序。例如,您可以在每个窗体上覆盖 on_size 事件并基于新窗体大小更新控件的位置(很笨的方法,工作量大)。或者,可在每个窗体上创建控件间的关系,如“a.x = b.x + b.width + 4;”(此方法非常灵活,但工作量也很大)。
或者,可在每个窗体上将控件标记为在每个轴上可调整大小或可移动。如果将控件标记为在某轴上可调整大小,则当窗体大小更改时,控件大小将更新;如果将控件标记为在某轴上可移动,则当窗体大小更改时,控件将移动。这对于大多数应用程序已经足够了。我从 WTL 的 CResizeWindow 借用了这一理念,并使用非侵入式处理程序实现了它。假设您有一个类似图 11 的对话框。如果您希望在调整大小后使其外观类似图 12 中的样子,则需要使用下面的代码:
resize(name, axis::x, sizeable);
resize(desc, axis::x | axis::y, sizeable);
resize(ok, axis::x | axis::y, moveable);
resize(cancel, axis::x | axis::y, moveable);
图 11 对话框
图 12 调整大小后的对话框
更多精彩
赞助商链接