MFC菜单消息漫谈

来源:互联网 发布:linux jar 输出 编辑:程序博客网 时间:2024/05/17 16:16

 首先,在MFC中,具有PopUp属性的菜单是不能用来做命令响应的。

在MFC中:

     当点击一个菜单项的时候,最先接受到菜单项消息的是CMainFrame框架类,CMainFrame框架类将会把菜单项消息交给它的子窗口View类,由View类首先进行处理;如果View类检测到没对该菜单项消息做响应,则View类把菜单项消息交由文档类Doc类进行处理;如果Doc类检测到Doc类中也没对该菜单项消息做响应,则Doc类又把该菜单项消息交还给View类,由View类再交还给CMainFrame类处理。如果CMainFrame类查看到CMainFrame类中也没对该消息做响应,则最终交给App类进行处理。

所以,其消息传递顺序为:View类--Doc类--CMainFrame类--App类。当然,菜单消息一旦在其中一个类中响应则不再在其它类中查找响应函数

 windows消息的分类

(1)标准消息:除WM_COMMAND之外,所有以WM_开头的消息。从CWnd类派生的都可以接收到这些消息。

(2)命令消息:来自菜单、加速键或工具栏按钮的消息。这类消息都以WM_COMMAND呈现。在MFC中,通过菜单项的标识(ID)来区分不同的命令消息;在SDK中,通过消息的wParam参数识别。

(3)通告消息:由控件产生的消息,例如,按钮的单击,列表框的选择等均产生此类消息,为的是向其父窗口(通常是对话框)通知事件的发生。这类消息也是以WM_COMMAND形式呈现。——————从CCmdTarget派生的类,都可以接收到[命令消息]和[通告消息]

在menu操作过程中,几个函数需要了解:

复制代码
1 CMenu* GetMenu( ) ;//CWnd::GetMenu得到窗口菜单栏对象指针。2 CMenu* GetSubMenu( ) ;//CMenu::GetSubMenu获得指向弹出菜单对象指针3 UINT CheckMenuItem( );//CMenu::CheckMenuItem添加(add)check marks(选择标记)或者是删除(remove)check marks,是针对菜单项的作用4 BOOL SetDefaultItem();//CMenu::SetDefaultItem5 BOOL SetMenuItemBitmaps( );//CMenu::SetMenuItemBitmaps 设置位图标题菜单。6 UINT EnableMenuItem();//CMenu::EnableMenuItem使菜单项有效,无效,或变灰。7 BOOL SetMenu( CMenu* pMenu );//CWnd::SetMenu在当前窗口上设置新菜单或移除菜单8 HMENU Detach( );//CMenu::Detach Detaches a Windows menu from a CMenu object and returns the handle. 
复制代码

创建一个menu项的简单过程:

1 CMenu menu;//定义为局部对象2 menu.LoadMenu(IDR_MAINFRAME);3 SetMenu(&menu);4 menu.Detach();//因为局部对象

这里menu对象作为一个局部对象。使用Detach()从menu对象中分离窗口菜单句柄,从而当menu对象析构的时候窗口菜单资源不随之销毁。

 命令更新机制:

菜单项状态的维护是依赖于CN_UPDATE_COMMAND_UI消息,谁捕获CN_UPDATE_COMMAND_UI消息,MFC就在其中创建一个CCmdUI对象。
在后台操作系统发出WM_INITMENUPOPUP消息,然后由MFC的基类如CFrameWnd接管并创建一个CCmdUI对象和第一个菜单项相关联,调用对象成员函数DoUpdate()(注:这个函数在MSDN中没有找到说明)发出CN_UPDATE_COMMAND_UI消息,这条消息带有指向CCmdUI对象的指针。此后同一个CCmdUI对象又设置为与第二个菜单项相关联,这样顺序进行,直到完成所有菜单项。
更新命令UI处理程序仅应用于弹出式菜单项上的项目,不能应用于永久显示的顶级菜单项目。

利用调用TrackPopupMenu函数,创建ContextMenu(右键菜单):

复制代码
1 void CMenu2View::OnRButtonDown(UINT nFlags, CPoint point) 2 {3     CMenu menu;4     menu.LoadMenu(IDR_MENU1);5     CMenu *pPopup = menu.GetSubMenu(0);6     ClientToScreen(&point);//将一个坐标点或一个矩形区域坐标转换成屏幕坐标。7     pPopup->TrackPopupMenu(TPM_LEFTALIGN,point.x,point.y,GetParent());//在指定位置以指定的方式显示弹出菜单。8     CView::OnRButtonDown(nFlags, point);9 }
复制代码

1)用资源管理器添加一个菜单资源
2)在鼠标右键消息响应函数中,加载菜单资源,并获得要显示的子菜单指针,并用该指针调用TrackPopupMenu函数便完成任务(但要注意:鼠标响应函数传进来的坐标是客户区坐标,而TrackPopupMenu函数中使用的是屏幕坐标,在调用TrackPopupMenu前要调用ClientToScreen客户区坐标到屏幕坐标的转换)

3)弹出菜单上的消息,在路由的时候,仍然遵循View-DOC-MainFrame-APP的响应顺序。

动态菜单编程:
一些有关的比较重要的函数:

复制代码
1 CMenu::AppendMenu //Appends a new item to the end of a menu.2 CMenu::CreatePopupMenu //Creates an empty pop-up menu and attaches it to a CMenu object.3 CMenu::InsertMenu 4 //Inserts a new menu item at the position specified by nPosition and moves other items down the menu. 5 CMenu::GetSubMenu //Retrieves a pointer to a pop-up menu.6 CWnd::GetMenu //Retrieves a pointer to the menu for this window.7 CMenu::DeleteMenu //Deletes an item from the menu. 
复制代码
1 CView* GetActiveView( ) const;//获取当前视窗口指针(单文档框架中)
0 0
原创粉丝点击