继《wxWidgets窗体:掌握wxFrame创建与使用技巧》之后,我们将关注wxWidget窗体wxFrame的交互性设计相关的内容。wxWidgets教程完整目录
菜单与菜单栏是传统窗口程序的界面元素之一,交互式设计的重要用户接口。
一、类图
在wxWidgets中,菜单与菜单栏的类图结构如下:

菜单栏wxMenuBar是菜单wxMenu的容器,wxMenu是菜单项wxMenuItem的容器。菜单栏通常位于窗口顶部,响应菜单选择。
菜单会触发事件wxMenuEvent,wxMenu和wxMenuBar都派生自wxEvtHandler,具有事件处理能力。
二、窗体口添加菜单
(一)创建菜单栏
可以使用wxMenuBar(long style=0)创建一个空白的菜单栏,然后再依据需要逐个创建菜单wxMenu并调用wxMenuBar::Append()添加至菜单栏中。
示例如下:
MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
: wxFrame(NULL, wxID_ANY, title, pos, size){
...
//创建菜单File
wxMenu *menuFile = new wxMenu;
//在菜单中添加菜单项
menuFile->Append(ID_Hello, "&Hello...\tCtrl-H",
"Help string shown in status bar for this menu item");
//在菜单中添加菜单分隔栏
menuFile->AppendSeparator();
//在菜单中添加预定义菜单“Exit”
menuFile->Append(wxID_EXIT);
//创建菜单Help
wxMenu *menuHelp = new wxMenu;
//创建预定义菜单项“About”
wxMenuItem* item=menuHelp->Append(wxID_ABOUT);
//为预定义菜单项“About”设置图标
wxBitmap* bmpAbout=new wxBitmap(“about.png”,wxBITMAP_TYPE_PNG);
item->SetBitmap(bmpAbout);
//创建菜单栏,依次加入上面创建的菜单
wxMenuBar *menuBar = new wxMenuBar;
menuBar->Append( menuFile, "&File" );
menuBar->Append( menuHelp, "&Help" );
//为窗体设置菜单栏
SetMenuBar( menuBar );
...
}
此外,还可以使用构造函数wxMenuBar (size_t n, wxMenu * menus[], const wxString titles[], long style = 0 )创建,其中:
n:菜单个数;
menus[]:需要装载的菜单对象;
titles[]:menus[]中菜单对象对应的菜单名称;
style:菜单样式,默认为0,在GTK系统中可以设置为wxMB_DOCKABLE,使菜单栏具备停靠功能。
菜单栏创建成功后,通过wxFrame的void SetMenuBar(wxMenuBar *menubar) 将其添加至窗口中。
两种创建菜单栏的方式区别在于创建wxMenuBar之前是否需要全部确定需要装载的菜单。通常第一种方式更灵活,而第二种方式更高效。
(二)上下文菜单
菜单wxMenu是菜单项wxMenuItem的容器。菜单可以在菜单栏中使用,也可以用在上下文菜单中,下面的代码在窗口鼠标右键响应函数中弹出一个上下文菜单。
void MyWindow::OnRightClick(wxMouseEvent& event){
if(contextMenu==nullptr){
contextMenu=new wxMenu;
contextMenu->Append(wxID_TASK_CREATE,
_("Create"),_("Create a transfer task"));
}
...
this->PopupMenu(popMenu,event.GetPosition());
}
三、菜单项
菜单项wxMenuItem是菜单命令的直接执行项,在wxWidgets中通常可以不用直接构建wxMenuItem实例的方式来创建菜单项,wxMenu::Append()提供更快捷的创建方式。下面的代码将创建一个菜单项,并设置菜单项的图标:
wxMenuItem* item=menu->Append(wxID_NEW, wxT("&New...\tCtrl+N"));
item->SetBitmap(bmp);
(一)预定义菜单项
在上面的示例中,wxID_ABOUT和wxID_EXIT是由wxWidgets预定义的,具有特殊含义,因此使用这些id的条目将从OS X下的正常菜单中取出,并插入到系统菜单中(遵循适当的OS X接口指南)
(二)自定义菜单项
自定义菜单项可以是普通项、checkbox项或radiobutton选项。普通项没有任何特殊属性,而checkbox项有一个与之关联的布尔标志,并且在设置该标志时,它们在菜单中显示一个复选标记。wxWidgets在单击项时自动切换标志值,可以使用wxMenu的wxMenu::IsChecked()方法或wxMenuBar本身来检索其值,或者在获取有关项的菜单通知时使用wxEvent::IsChecked()。
wxMenuItem* item=menu->AppendCheckItem(wxID_NEW, wxT("&New...\tCtrl+N"));
radiobutton项与checkbox项类似,只是在检查单选项时,同一个单选组中的所有其他项都未选中。radiogroup由一个连续的radio项目范围构成,即它从这类的第一个项目开始,以另一类的第一个项目(或菜单的结尾)结束。请注意,由于radiogroup是根据项目位置定义的,因此在包含radiogroup菜单中插入或删除项目可能会导致无法正常工作。如下例所示,定义了两个Radio菜单项,通过wxID_ANY的普通菜单项和一个分隔栏分开。如果程序动态删除ID为wxID_ANY或分隔栏的菜单项,则多个radiogroup将合并成一个。
menuFile->AppendSeparator();
menuFile->AppendRadioItem(ID_R0,"R0");
menuFile->AppendRadioItem(ID_R1,"R1");
menuFile->AppendSeparator();
menuFile->AppendRadioItem(ID_R2,"R2");
menuFile->AppendRadioItem(ID_R3,"R3");
menuFile->Append(wxID_ANY,"dive radio group");
menuFile->AppendRadioItem(ID_R9,"R9");
menuFile->AppendRadioItem(ID_RA,"RA");
menuBar->Append(menuFile,"&File");
有时也可以直接创建wxMenuItem来构建菜单。
wxMenuItem(wxMenu *parentMenu = NULL,
int id = wxID_SEPARATOR,
const wxString& text = wxEmptyString,
const wxString& help = wxEmptyString,
wxItemKind kind = wxITEM_NORMAL,
wxMenu *subMenu = NULL)
parentMenu指向包含它的菜单,可以先设置为空,然后再调用wxMenuItem* wxMenu::Append(wxMenuItem* menuItem)将菜单项加入菜单中。
菜单项可以是标准菜单项或自定义菜单项。对于标准菜单项(例如打开文件、退出程序等的命令),只需指定内置ID,其余参数使用默认值即可。一些平台(目前仅wxGTK)也会显示内置菜单项的标准位图。实际上,wxWidgets建议内置菜单项的文本参数text和helpString使用默认值,因为这将使菜单具有用户熟悉的外观和键盘界面(包括标准加速器)。
//使用预定义菜单项
helpMenu->Append(wxID_ABOUT);
//使用预定义菜单项的标签文本与快捷键和自定义帮助字符串
helpMenu->Append(wxID_ABOUT, "", "My custom help string");
//使用预定义菜单项,自定义图标
wxMenuItem *mymenu = new wxMenuItem(helpMenu, wxID_ABOUT);
mymenu->SetBitmap(wxArtProvider::GetBitmap(wxART_WARNING));
//将菜单项添加至菜单中
helpMenu->Append(mymenu);
对于自定义(非内置)菜单项,必须指定text,虽然helpString可能为空,但建议在此参数中传递项描述(当选择菜单项时会自动在状态栏中显示)。
响应菜单事件,需要在包含菜单栏的窗口事件处理表中添加EVT_MENU的处理函数。
enum{
ID_Hello = 1
};
wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(ID_Hello, MyFrame::OnHello)
EVT_MENU(wxID_ABOUT, MyFrame::OnAbout)
wxEND_EVENT_TABLE()
四、事件处理
(一)事件处理函数
菜单项的事件处理函数具有如下两种形式:
void handlerFuncName(wxCommandEvent& event)
void handlerFuncName(wxMenuEvent& event)
(二)事件类型
与菜单相关其它事件宏:
EVT_MENU(func):处理菜单点击事件,用户点击菜单时触发。事件对象wxCommandEvent。
EVT_MENU_RANGE(id1, id2, func):处理id在[id1,id2]范围内的菜单的点击事件,事件对象为wxCommandEvent。
EVT_MENU_OPEN(func):用来处理wxEVT_MENU_OPEN事件,在一个菜单即将被打开的时候产生。在windows平台上主菜单上每次遍历只会导致一次该事件产生。事件对象为wxMenuEvent。
EVT_MENU_CLOSE(func):用来处理wxEVT_MENU_CLOSE事件,它在某个菜单被关闭的时候产生。事件对象为wxMenuEvent。
EVT_MENU_HIGHLIGHT(id, func):用来处理wxEVT_MENU_HIGHLIGHT事件,当某个菜单项被高亮显示的时候产生,通常用来在主程序的状态栏上产生关于这个菜单项的帮助信息。事件对象为wxMenuEvent。
EVT_MENU_HIGHLIGHT_ALL(func):用来处理wxEVT_MENU_HIGHLIGHT事件,在任何一个菜单项被高亮显示的时候产生。事件对象为wxMenuEvent。
菜单项具有与其关联的整数ID,可用于标识所选内容或以某种方式更改菜单项。具有特殊标识符wxID_SEPARATOR分隔符的菜单项是分隔项,没有关联命令,只是在菜单中出现分隔线。
五、总结
示例基于静态绑定的方式演示菜单事件处理,事实上,您也可以采用动态绑定的方法。相关文档可参考《wxWidgets窗体:事件处理之动态绑定》一文。
1425

被折叠的 条评论
为什么被折叠?



