本文仅用于学习交流,商业用途请支持正版!转载请注明:
认识菜单:
有菜单栏、子菜单和菜单项三个概念。如图示:菜单栏包括若干子菜单,每个子菜单里有若干菜单项。
对于菜单来说,子菜单和菜单项的访问是有所不同的。子菜单只能通过索引号进行访问;而菜单项既可以通过位置索引号实现访问,也可以通过菜单项的标识ID操作。
标记菜单:
带对号标记的菜单。
如何标记菜单项?在框架类的OnCreate函数中依次:获得菜单栏GetMenu函数(即在框架窗口中获得指向菜单栏的指针);获取子菜单GetSubMenu函数;为菜单项添加或移除标记CheckMenuItem函数。具体代码如下:
//标记New菜单项,使用索引号访问菜单项 GetMenu() -> GetSubMenu(0) -> CheckMenuItem(0,MF_BYPOSITION | MF_CHECKED); //使用菜单项ID访问 GetMenu() -> GetSubMenu(0) -> CheckMenuItem(ID_FILE_NEW,MF_BYPOSITION | MF_CHECKED);
注:索引号是从0开始的。
这样我们就标记了File子菜单下的New菜单项了。如下图示:
默认菜单项:
子菜单下以粗体显示的菜单项,一个子菜单只能有一个默认菜单项。分隔栏在子菜单中是占据索引位置的。
方法一,利用菜单项位置索引实现。
默认菜单项的设置代码如下:
//设置默认菜单-利用位置索引
GetMenu() -> GetSubMenu(0) -> SetDefaultItem(0,TRUE);
方法二,利用菜单项标识实现。
默认菜单项的设置代码如下:
//设置默认菜单-利用菜单项标识
GetMenu() -> GetSubMenu(0) -> SetDefaultItem(ID_FILE_NEW,FALSE);
运行可见,New菜单项已经以粗体显示。
图形标记菜单:
即菜单项前带有图形。如图VS中的图形标记菜单:
利用CMenu类的SetMenuItemBitmaps函数,将指定的位图与菜单项关联起来。
首先,新建一个位图资源。如图示:
为了使位图可以作为标记菜单的内容使用,需要把位图对象设置为CMainFrame的成员变量。添加一个CBitmap类型的成员变量:m_bitmap。如果不知道如何添加成员变量,请查看此分类下之前的相应文章。
接下来,就可以在CMainFrame类的OnCreate函数中添加实现图形标记代码了,代码如下:
m_bitmap.LoadBitmap(IDB_BITMAP1);
GetMenu() -> GetSubMenu(0) -> SetMenuItemBitmaps(0,MF_BYPOSITION,&m_bitmap,&m_bitmap);
运行,效果如下:可以看到New菜单项前显示了我们的位图标记。
禁用菜单项:
即是屏蔽某一个或多个菜单项的功能.
我们可以利用CMenu类的成员函数EnableMenuItem来完成,该函数可以设置菜单项的状态:可以使用、禁用或变灰显示。通常情况下,我们会把禁用MF_DISABLED和变灰显示MF_GRAYED同时使用,但这并不是必需的。
因为菜单栏在框架类上,通过实践可知,在框架类的OnCreate函数中可以实现禁用菜单项。代码如下:
//禁用文件菜单下的打开菜单项
GetMenu() -> GetSubMenu(0) -> EnableMenuItem(1,MF_BYPOSITION | MF_DISABLED);
运行发现,打开功能仍可使用。
问题在于:MFC为菜单提供了一个命令更新机制,程序默认会根据此机制判断菜单的可用性,然后显示其状态。默认状态下,所有的菜单项的更新都是由MFC命令更新机制完成的。如果我们想自己更改菜单项状态,需要将变量m_bAutoMenuEnable设置为FALSE,这样我们自己对菜单的状态更新才起作用。
运行效果如图示:
经VS2010测试发现,将菜单项设置为MF_GRAYED或MF_DISABLED均会导致菜单项不可用并灰色显示。(有待查阅相关技术文档)
移除和装载菜单:
利用CWnd类的成员函数SetMenu可以实现菜单的移除和装载:
BOOL SetMenu(CMenu* pMenu);
在框架类的OnCreate函数中,添加此函数:SetMenu(NULL);运行会发现已经没有了菜单栏了。
当然也可以装载菜单资源并显示,下面把菜单资源加载进来并显示。
//加载菜单栏
CMenu menu;
menu.LoadMenuW(IDR_MAINFRAME);
SetMenu(&menu);
运行,可以发现菜单栏已经加载成功。
但是当我们单击菜单时会提示如下错误,
这个错误是由于CMenu对象menu是一个局部对象造成的。当menu的生命周期结束后就会去销毁其关联的菜单对象。
解决方法一:将menu设置为框架类的成员变量
即将此定义:CMenu menu; 放到框架类的头文件中即可。
解决方法二:在调用SetMenu()将此对象设置为窗口的菜单之后,立即利用CMenu类的成员函数Detach(),把菜单句柄与此菜单对象分离。
理解:SetMenu()函数会把窗口的菜单设置为其参数指定的新菜单,导致窗口重绘,以反应菜单的变化,同时也将该菜单对象的所有权交给窗口对象。Detach()函数会将菜单句柄与菜单对象分离,这样当这个句柄菜单对象的生命周期结束时,它就不会去销毁一个它不再具有拥有权的菜单了。由于此菜单的所有权已经交给了窗口,因此当窗口销毁时这个菜单会自动销毁。
//加载菜单栏
CMenu menu;
menu.LoadMenuW(IDR_MAINFRAME);
SetMenu(&menu);
menu.Detach();
运行,可以看到程序已经正常了。
如果有疑问,可以联系giserdev@163.com,更多内容请参考:,技术交流请加QQ群:586571286。