第6章 菜单
1.MFC中把设置为Pop-up类型的菜单称为弹出式菜单,Visual C++默认顶层菜单为弹出式菜单。这种菜单不能响应命令。
2.菜单命令的路由
程序类对菜单命令的响应顺序依次是:视类、文档类、框架类、应用程序类;
Windows消息的分类:
①标准消息(窗口消息):除WM_COMMAND之外,所有以WM_开头的消息都是标准消息。从CWnd派生的类都可以接收到这类消息。
②命令消息:来自菜单、加速键或者工具栏按钮的消息。这类消息都以WM_COMMAND形式呈现。在MFC中,通过菜单项的标识(ID)来区分不同的命令消息;在SDK中,通过消息的wParam参数识别。从CCmdTarget派生的类都可以接收到这类消息。
③通告消息(控件消息):由控件产生的消息,目的是向其父窗口(通常是对话框)通知事件的发生。这类消息也是以WM_COMMAND形式呈现的。从CCmdTarget派生的类都可以接收到这类消息。
因为CWnd派生于CCmdTarget类,也就是说,凡是从CWnd派生的类,它们既可以接收标准消息,也可以接收命令消息和通告消息,而对于那些从CCmdTarget派生的类,则只能接收命令消息和通告消息,不能接收标准消息。
菜单命令消息路由的具体过程:当点击某个菜单项时,最先收到这个菜单命令消息的是框架类。框架类将把这个消息交给视类,视类首先进行处理。视类根据命令消息映射机制查找自身是否对此消息进行了响应,如果响应了就调用相应响应函数对这个消息进行处理,消息路由结束;如果视类没有对此命令消息做出响应,就交由文档类,文档类同样查找消息映射,若进行了响应则消息路由结束,否则将这个消息交还给视类,视类再将该消息交还给框架类。框架类查找自身有无消息响应函数,如果没有则将该命令消息交给应用程序类。
3.基本菜单操作:
如果要访问某个菜单项,既可以通过该菜单项的标识ID,也可以通过其位置索引来实现访问。但对于子菜单来说,只能通过索引号进行访问,因为子菜单是没有标识号的。分隔栏在子菜单中是占据索引位置的。
因为程序的主菜单属于框架窗口,所以需要在框架类窗口创建完成之后再去访问菜单对象。可以在框架类CMainFrame的OnCreate函数的最后(但一定要在return语句之前)添加实现这个功能的语句。
①标记菜单
GetMenu()->GetSubMenu(0)->CheckMenuItem(ID_FILE_NEW,MF_BYCOMMAND | MF_UNCHECKED);
CWnd::GetMenu函数返回一个指向CMenu类对象的指针。
CMenu::GetSubMenu函数返回一个由索引指定的子菜单的CMenu指针。
CMenu::CheckMenuItem函数为菜单项添加一个标记,或者移除菜单项的标记。第一个参数指定需要处理的菜单项,它的取值取决于第二个参数的取值。
②默认菜单项
GetMenu()->GetSubMenu(0)->SetDefaultItem(1,TRUE);
CMenu::SetDefaultItem
BOOL SetDefaultItem( UINT uItem, BOOL fByPos = FALSE );
一个子菜单只能有一个默认菜单项。
③图形标记菜单
m_bitmap.LoadBitmap(IDB_BITMAP1);
GetMenu()->GetSubMenu(0)->SetMenuItemBitmaps(0,MF_BYPOSITION,&m_bitmap,&m_bitmap);
CMenu::SetMenuItemBitmaps
BOOL SetMenuItemBitmaps( UINT nPosition, UINT nFlags, const CBitmap* pBmpUnchecked, const CBitmap* pBmpChecked );
图形标记菜单上显示的位图的尺寸有固定的标准,通过int GetSystemMetrics(int nIndex)函数可以得到位图的尺寸:
int x=GetSystemMetrics(SM_XMENUCHECK);
int y=GetSystemMetrics(SM_CYMENUCHECK);
④禁用菜单项
GetMenu()->GetSubMenu(0)->EnableMenuItem(ID_FILE_NEW,MF_BYCOMMAND | MF_DISABLED);
MFC为菜单提供了一种命令更新的机制,程序在运行时根据此机制去判断哪个菜单可以使用,哪个菜单不能够使用,然后显示其相应的状态。默认情况下所有菜单项的更新都是由MFC的命令更新机制完成的。如果想自己更改菜单项的状态,就必须把m_bAutoMenuEnable变量设置为FALSE,之后我们自己对菜单项的状态更新才能起作用。
⑤移除和装载菜单
CWnd:: BOOL SetMenu( CMenu* pMenu );
SetMenu(NULL); //移除菜单
CMenu menu;
menu.LoadMenu(IDR_MAINFRAME);
SetMenu(&menu);//装载菜单
menu.Detach();
在设置窗口菜单时,如果定义的是局部菜单对象,则一定要在调用SetMenu函数设置窗口菜单后立即调用菜单对象的Detach函数将菜单句柄与菜单对象分离。
CMenu:: HMENU Detach( );
Return Value:The handle, of type HMENU, to a Windows menu, if successful; otherwise NULL.
Remarks:Detaches a Windows menu from a CMenu object and returns the handle. The m_hMenu data member is set to NULL.
⑥MFC菜单命令更新机制
如果要在程序中设置某个菜单项的状态,首先通过ClassWizard为这个菜单项添加UPDATE_COMMAND_UI消息响应函数,然后在这个函数中进行状态的设置即可,如为“新建”菜单项添加UPDATE_COMMAND_UI消息响应函数:
void CMainFrame::OnUpdateFileNew(CCmdUI* pCmdUI)
{
pCmdUI->Enable(FALSE); //使“新建”菜单项失效
}
UPDATE_COMMAND_UI消息的响应只能应用于菜单项,不能应用于永久显示的顶级菜单,即弹出式菜单项目。
如果要把工具栏上的一个工具按钮与菜单栏中的某个菜单项相关联,只要将它们的ID设置为同一个标识就可以了。因为菜单项和工具按钮的位置索引计算方式不同,为了保持二者状态一致,最好采用菜单项标识或工具栏按钮标识的方式来进行设置。
⑦快捷菜单
插入快捷菜单:【Project】->【Add To Project】->【Components and Controls…】->Pop-up Menu;
插入快捷菜单之后添加了两处内容:
第一处,在ResourceView选项卡的Menu分支下多了一个标识为CG_IDR_POPUP_MENU_VIEW的菜单资源,这个菜单只有一个顶层菜单项:_POPUP_,其下有Cut、Copy、Paste三个菜单项。
第二处,为CMenuView类添加了一个函数:OnContextMenu。在程序运行时,当用鼠标右键单击窗口时,程序就会调用这个函数,该函数内部使用TrackPopupMenu函数来显示快捷菜单。
由此可以在鼠标右击响应函数中定义实现自己的快捷菜单:
void CMenuView::OnRButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CMenu menu;
menu.LoadMenu(IDR_MENU1);
CMenu *pPopup = menu.GetSubMenu(0);
ClientToScreen(&point); //将一个坐标点或矩形区域坐标转换成屏幕坐标。
pPopup->TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON,
point.x, point.y,this);//在指定位置以指定的方式显示弹出菜单。
CView::OnRButtonDown(nFlags, point);
}
对于快捷菜单,只有将其拥有者窗口设置为框架类窗口,框架类窗口才有机会获得对该快捷菜单中菜单项命令的响应,否则就只能由视类窗口做出响应。
4.动态菜单操作
①添加菜单项目
CMenu menu; //创建一个菜单
menu.CreatePopupMenu();
GetMenu()->AppendMenu(MF_POPUP,(UINT)menu.m_hMenu,"AppednMenu");
//MF_POPUP创建一个弹出菜单,(UINT)menu.m_hMenu 是菜单句柄
menu.Detach(); //将句柄与CMenu对象断开
②插入菜单项目
GetMenu()->InsertMenu(2,MF_BYPOSITION|MF_POPUP,
(UINT)menu.m_hMenu,"InsertMenu"); //插入一个子菜单
menu.AppendMenu(MF_STRING,IDM_HELLO/*ID号*/,"Hello");
menu.AppendMenu(MF_STRING,112,"Weixin");
menu.Detach();
GetMenu()->GetSubMenu(0)->InsertMenu(ID_FILE_OPEN,
MF_BYCOMMAND | MF_STRING,115,"维新(&p) Ctrl+P");
//在“文件->打开”之前插入一个叫“维新”的菜单项
③删除菜单
GetMenu()->DeleteMenu(1,MF_BYPOSITION); //删除“编辑”子菜单
GetMenu()->GetSubMenu(0)->DeleteMenu(ID_FILE_PRINT, MF_BYCOMMAND); //删除“文件->打印”
④动态添加的菜单项的命令响应
在Header Files目录下的Resource.h文件中定义了当前程序使用的一些资源ID,可以手工为菜单项添加一个ID,然后遵照MFC消息映射机制,即需要添加三处代码来实现命令消息的响应。
本文深入探讨了MFC菜单系统的概念、组件及其在实际应用中的操作方法,包括弹出式菜单、命令消息路由、基本菜单操作、快捷菜单、动态菜单等。详细介绍了如何标记、设置默认菜单项、图形标记菜单、禁用菜单项、移除和装载菜单,以及MFC菜单命令更新机制。同时,提供了MFC菜单系统中动态菜单操作的实例,包括添加、插入、删除菜单项目,以及如何实现快捷菜单。文章旨在为开发者提供全面的MFC菜单系统指导。
4205

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



