基本菜单操作(一)

本文仅用于学习交流,商业用途请支持正版!转载请注明:http://www.cnblogs.com/mxbs/p/6271011.html 

  认识菜单:

  有菜单栏、子菜单和菜单项三个概念。如图示:菜单栏包括若干子菜单,每个子菜单里有若干菜单项。

  对于菜单来说,子菜单和菜单项的访问是有所不同的。子菜单只能通过索引号进行访问;而菜单项既可以通过位置索引号实现访问,也可以通过菜单项的标识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,更多内容请参考:http://www.cnblogs.com/mxbs/,技术交流请加QQ群:586571286。

原文地址:https://www.cnblogs.com/mxbs/p/6271011.html