参考《VC++深入详解》孙鑫
- 管理者
菜单由CMenu类管理,CMenu类派生于CObject类。
- 使用方式
- 在局部堆栈或全局堆中创建CMenu对象
- 调用CMenu类的成员函数对其进行操作
- 调用CWnd::SetMenu将菜单挂接到某个窗口——此函数将新菜单作为窗口菜单,并立即重新对其进行绘制
- 立即调用CMenu::Detach函数——此函数解除HEMENU与CMenu对象之间的联系
- COMMAND与UPDATE_COMMAND_UI消息的区别
- 响应菜单项命令的顺序
视类->文档类->框架类->应用程序类
- windows消息分类
- 标准消息
- 除WM_COMMAND之外,所有以WM_开头的消息都是标准消息。从CWnd派生的类,都可以接收到这类消息。
- 命令消息
- 来自菜单、加速键或工具栏按钮的消息。这类消息都以WM_COMMAND形式呈现;在MFC中,通过菜单项的ID来区分不同的命令消息;在SDK中,通过消息的wParam参数识别。从CCmdTarget派生的类,都可以接收到这类消息。
- 通告消息
- 由控件产生的消息,例如按钮的单击、列表框的选择等都会产生这类消息,目的是为了向其父窗口(通常是对话框)通知事件的发生。这类消息也是以WM_COMMAND形式呈现的;
- 操作函数
- 基本菜单操作: GetMenu->GetSubMenu(0);
- 标记菜单: GetMenu->GetSubMenu(0)->CheckMenuItem(0, MF_BYPOSITION|MF_CHECKED);
- 默认菜单项: GetMenu->GetSubMenu(0)->SetDefaultItem(1,TRUE);
- 图形标记菜单: SetMenuItemBitmaps()
- 第三个参数pBmpUnchecked: 取消菜单项选中状态时的位图
- 第四个参数pBmpChecked: 选中菜单项时显示的位图
- GetSystemMetric函数:可以获得图形标记菜单上显示的位图的尺寸
- 禁用菜单项: EnableMenuItem函数(如果想自己更改菜单项的状态,必须先把m_bAutoMenuEnable变量设置为FALSE,之后自己对菜单项状态的更新才起作用)
- 移除和装载菜单
- 移除: SetMenu(NULL);
- 装载:
- CMenu menu;
- menu.LoadMenu(IDR_MAINFRAME);
- SetMenu(&menu);
- menu.Detach();
- 加载菜单后因为菜单是局部对象出现问题的解决方案
- 把menu定义为CMainFrame的成员变量
- 调用SetMenu函数把此对象设置为窗口的菜单之后,立即调用CMenu类的另一个成员函数Detach,以便把菜单句柄与这个菜单对象分离
- 说明:Detach函数会把菜单句柄与这个菜单对象分离,这样当这个局部对象声明周期结束时,它不会去销毁一个它不再拥有的菜单,这个菜单在窗口销毁时会自动销毁。
- MFC菜单命令更新机制
- 当要显示菜单时,操作系统发出WM_INITMENUPOPUP消息,然后由程序窗口的基类如CFrameWnd接管;它会创建一个CCmdUI对象,并与程序的第一个菜单项相关联,调用该对象的一个成员函数DoUpdate(),这个函数发出CN_UPDATE_COMMAND_UI消息,这条消息带有一个指向CCmdUI对象的指针;这时,系统会判断是否存在一个ON_UPDATE_COMMAND_UI宏去捕捉这个菜单项消息,如果找到这样一个宏,就调用相应的消息响应函数进行处理,在这个函数中,可以利用传递过来的CCmdUI对象去调用相应的函数,使该菜单项可以使用或禁用该菜单项;当更新完第一个菜单项后,同一个CCmdUI对象就设置为第二个菜单项相关联,依次顺序进行,直到完成所有菜单项的处理。
快捷菜单
- 添加步骤:
- 做一个菜单资源
- 添加右键消息(WM_RBUTTONDOWN)响应函数
- 在响应函数中添加代码
- 加载菜单
- CMenu menu;
- menu.LoadMenu(IDR_XXX);
- CMenu *pMenu = menu.GetSubMenu(1);
- 显示菜单
- ClientToScreen(&point);
- pMenu->TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON, point.x,point.y,GetParent());
- 加载菜单
动态菜单操作
包括针对弹出菜单的动态操作和针对菜单项的动态操作。
- 添加菜单项目
- AppendMenu
- 例子
- CMenu menu;
- menu.CreateMenu();
- GetMenu()->AppendMenu(MF_POPUP,(UINT)menu.m_hMenu,"test");
- menu.Detach();
- 插入菜单项目
- InsertMenu
- 在两个子菜单之间插入一个子菜单
- 在两个菜单项之间插入一个新的菜单项
- 例子
- CMenu menu;
- menu.CreateMenu();
- GetMenu()->InsertMenu(2,MF_POPUP|MF_BYPOSITION,(UINT)menu.m_hMenu,"Test"); //子菜单
- GetMenu()->GetSubMenu(0)->InsertMenu(ID_FILE_OPEN,MF_BYCOMMAND|MF_STRING,115,"VC 编程"); //菜单项
- menu.Detach();
- 删除菜单
- BOOL DeleteMenu(UINT nPosition, UINT nFlags);
- 例子
- GetMenu()->DeleteMenu(1,MF_BYPOSITION);
- GetMenu()->GetSubMenu(0)->DetletMenu(2,MF_BYPOSITION);
- 动态添加菜单项的命令响应
- 方法:通过编辑resource.h,在其中添加动态菜单项的资源ID,然后为此资源添加相应的消息处理机制。
- 具体做法:
- #define IDM_HELLO 111
- 添加函数中修改为:menu.AppendMenu(MF_STRING,IDM_HELLO,"hello");
- 添加消息映射及响应函数
- afx_msg void OnHello();
- ON_COMMAND(IDM_HELLO,OnHello) //无分号
- void CMainFrame::OnHello() {...}