内容发布更新时间 : 2024/12/22 21:21:14星期一 下面是文章的全部内容请认真阅读。
一、消息路由
1、消息的路由:MFC在后台把窗口过程函数替换成了AfxWndProc函数,由这个函数对所有的消息进行处理,该函数内部将调用AfxCallWndProc函数,AfxCallWndProc函数又将调用WindowProc函数(CWnd类的成员函数),应用程序所有类型的消息都会进入到这个函数中。WindowProc函数又将调用OnWndMsg函数,该函数会对到来的消息进行一个类型判断:若是标准消息,OnWndMsg函数查找相应的消息映射函数进行处理;若是命令消息,就交由OnCommand函数来处理,该函数将完成命令消息的路由;若是通告消息,将交由OnNotify函数来处理,该函数将完成通告消息的路由。OnCommand函数和OnNotify函数最后都会调用OnCmdMsg函数。如下图所示:
2、菜单命令消息路由的具体过程:当单击某个菜单项时,最先接收到这个菜单命令消息的是框架类(Frame类)。框架类将把接收到的这个消息交给它的子窗口,即视类(View类)。视类首先根据命令消息映射机制查找自身是否对此消息进行了响应,若响应了,就调用相应响应函数对这个消息进行处理,消息路由结束;若视类没有对此命令消息做出响应,就交由文档类。文档类同样查找自身是否对这个菜单命令进行了响应,若响应了,就由文档类的命令消息响应函数进行处理,路由过程结束。若文档类也未做出响应,就把这个命令消息交还给视类,视类又把该消息交还给框架类。框架类查看自己是否对这个命令消息进行了响应,若它也没有做出响应。就把这个菜单命令消息交给应用程序类来处理。因此菜单命令的响应顺序依次是:视类、文档类、框架类、应用程序类。 二、菜单
1、菜单项前添加标记”√”
(1)、通过菜单项位置索引,在Frame类的OnCreate函数中添加:
GetMenu()->GetSubMenu(0)->CheckMenuItem(0,MF_BYPOSITION | MF_CHECKED);
说明:GetMenu()获得菜单栏,GetSubMenu(0)获得第一个子菜单,CheckMenuItem(0,MF_BYPOSITION | MF_CHECKED)为子菜单的第一个菜单项添加标记。GetMenu函数是CWnd类的成员函数,而GetSubMenu函数是CMenu的成员函数。 (2)、通过菜单项标识,在Frame类的OnCreate函数中添加:
GetMenu()->GetSubMenu(0)->CheckMenuItem(ID_FILE_NEW,MF_BYCOMMAND | MF_CHECKED);
注意:分割栏在子菜单中是占据索引位置的。 2、设置默认菜单项:
(1)、通过菜单项位置索引,在Frame类的OnCreate函数中添加: GetMenu()->GetSubMenu(0)->SetDefaultItem(1,TRUE); 提示:一个子菜单只能有一个默认菜单项。
(2)、通过菜单项标识,在Frame类的OnCreate函数中添加:
GetMenu()->GetSubMenu(0)->SetDefaultItem(ID_FILE_OPEN,FALSE); 3、菜单项前加图形标记:
(1)、在Frame类的OnCreate函数中添加:
m_bitmap.LoadBitmap(IDB_BITMAP1);// IDB_BITMAP1为位图资源的ID,m_bitmap是CBitmap类型的全局变量。
GetMenu()->GetSubMenu(0)->SetMenuItemBitmaps(0,MF_BYPOSITION,&m_bitmap,&m_bitmap);
提示:MFC都是采用大写字母来标示资源ID号的。一般都遵循一个原则:在”ID”字符串后加上一个标识资源类型的字母,如M表示菜单Menu,C表示光标Cursor,I表示图标Icon。例子:IDM_OPEN、IDC_MOUSE。
(2)、获得菜单项前图形标记的长度和宽度(默认是13×13): CString str;
str.Format(\YMENUCHECK));//按一定的格式把内容格式化,然后保存到CString类型的字符串对象中 MessageBox(str); 4、禁用菜单项:
(1)、在CMainFrame类的构造函数中添加: m_bAutoMenuEnable=FALSE;
说明:程序在运行会根据命令更新机制去判断哪个菜单可以使用,哪个菜单不能够使用,然后显示其相应的状态。默认情况下,所有菜单项的更新都是由MFC的命令更新机制完成的。若我们想自己更新菜单项的状态,那就必须把m_bAutoMenuEnable变量设置为FALSE,之后,我们对菜单项的状态更新才能其作用。m_bAutoMenuEnable变量被设置为FALSE后,MFC就不再利用它的菜单命令更新机制去判断菜单的使用状态,此时,需要我们自己去完成菜单的显示工作。
(2)、在CMainFrame类的OnCreate函数中添加:
GetMenu()->GetSubMenu(0)->EnableMenuItem(1,MF_BYPOSITION | MF_DISABLED |MF_GRAYED);
5、菜单的移除和装载
(1)、移除菜单栏,在Frame类的OnCreate函数中添加: SetMenu(NULL);
(2)、装载菜单,在Frame类的OnCreate函数中添加: CMenu menu; menu.LoadMenu(IDR_MAINFRAME); SetMenu(&menu); menu.Detach();
注意:若没有Detach()函数,则会出现错误,除非将menu设为全局变量。SetMenu函数会把窗口的菜单设置为其参数指定的新菜单,导致窗口重绘,以反映菜单的这种变化,同时也将该菜单对象的所有权交由给窗口对象。而随后的Detach函数会把菜单句柄与这个菜单对象分离,这样,当这个句柄菜单对象的生命周期结束时,它不会去销毁一个它不再具有拥有权的菜单,这个菜单在窗口销毁时会自动销毁。 6、添加子菜单及其菜单项
(1)、在Frame类的OnCreate函数中添加: CMenu menu;
menu.CreateMenu();//创建菜单
//在菜单栏中插入”Test”子菜单,CMenu对象的m_hMenu成员变量是菜单句柄。
GetMenu()->InsertMenu(2,MF_POPUP | MF_BYPOSITION,(UINT)menu.m_hMenu,\//为”Test”子菜单添加菜单项
menu.AppendMenu(MF_STRING,111,\menu.AppendMenu(MF_STRING,112,\menu.AppendMenu(MF_STRING,113,\
menu.Detach();//将菜单句柄与菜单对象之间的关联断开 7、删除菜单
(1)、删除子菜单或菜单项可用DeleteMenu函数,如: GetMenu()->DeleteMenu(1,MF_BYPOSITION); 三、MFC菜单命令更新机制
利用MFC编程时,菜单项状态的维护依赖于CN_UPDATE_COMMAND_UI消息。当显示菜单时,操作系统发出WM_INITMENUPOPUP消息,然后由程序窗口的基类如CFrameWnd接管。它会创建一个CCmdUI对象,并与程序的第一个菜单项相关联,调用该对象的一个成员函数DoUpdate()。该函数发出CN_UPDATE_COMMAND_UI消息,该消息带有一个指向CCmdUI对象的指针。这时,系统会判断是否存在一个ON_UPDATE_COMMAND_UI宏