MFC动态创建菜单

菜单是Windows的标准界面元素,几乎所有的Windows应用程序中都有它的身影。MFC中的类CMenu对它进行了封装,使其使用起来更加简便。要在程序中使用菜单也很简单,一般分以下几步:第一步先用VC的菜单编辑器创建一个菜单资源,给它赋予我们自己定义的ID,第二步在程序中构造一个CMenu类的对象,用CMenu::LoadMenu函数将菜单从资源中装入,接着调用CWnd::SetMenu函数将新菜单连到相应的窗口中,最后切记,要调用Detach成员函数把CMenu对象和菜单分离,以确保当CMenu对象生存期结束时,菜单不会被销毁。  

  以上是在程序中使用菜单的一般步骤,但有时候,我们在设计期是无法确定菜单包含哪些项的,这时这种事先设计好菜单资源的方法就行不通了。为了解决这个问题,必须要用到动态创建菜单的技术。通过CMenu类所提供的CreateMenu/CreatePopupMenu、AppendMenu/InsertMenu等函数,可以很方便地实现菜单的动态创建。下面简单地介绍一下这几个函数(函数原型和参数注释请查阅MSDN,这里不再赘述),然后用几个实例,讲解动态创建菜单的步骤。  

  CreateMenu函数用来创建一个空的菜单,并将其绑定到该CMenu对象上。要添加菜单项,可以使用CMenu的AppendMenu/InsertMenu成员函数(稍后我会介绍这两个函数有何不同)。如果这个创建出来的菜单是连到一个窗口上的,那么在窗口被销毁的时候,菜单会自动随之销毁;如果这个菜单不属于任何窗口,那么程序退出前,必须手动销毁菜单以及和它相关联的一切系统资源。销毁菜单用的是CMenu的DestroyMenu成员函数。  

  CreatePopupMenu和CreateMenu类似,只不过它创建的是一个空的浮动菜单(Pop-up   Menu),和普通菜单不同的是,浮动菜单既可以连到别的菜单上(连到普通菜单或者浮动菜单都可以)成为次级子菜单,也可以连接到某个窗口上;而普通菜单只能连接到某个窗口上。  

  AppendMenu用于在菜单的末尾追加一个菜单项,而InsertMenu可以在菜单的指定位置插入一个菜单项。这里尤其要注意的就是第一个参数,如果添加的菜单项,是要弹出另一个子菜单的(比如下图所示的“View”菜单项),那么第一个参数nFlags一定要包含MF_POPUP标志,同时第二个参数nIDNewItem设置成子菜单的句柄。具体后面会详细讲述。  

     

  Menu和Pop-up   Menu,是有区别的。普通菜单(就是用CreateMenu函数创建出来的菜单),直观地说,就是固定在标题栏下方的菜单,每Append一个菜单项,横向上就多出一列出来。让我们在OnInitDialog函数中添加如下代码:  

  CMenu Menu;  

  Menu.CreateMenu();  

  SetMenu(&Menu);  

  Menu.Detach();  

  编译运行, 没有效果,这是显而易见的,因为这时Menu还是空的,因为我们没有添加任何菜单项。截图如下:  

     

  好,现在让我们向菜单中添加一个菜单项。在Menu.CreateMenu()语句下面插入下面的代码:  

  Menu.AppendMenu(MF_STRING,   ID_APP_FILE,   "&File");  

  好了,有效果了,出来一个菜单,但是鼠标按下去什么都没有,仔细想想也很合理,只是添加了一个菜单项而已,一个菜单项怎么会弹出另一个菜单呢?效果如下(可以看到鼠标按下去什么都没有出来)  

     

  还记得刚才我说的吗,普通菜单其实就是横向的那一条,每一个都是一个菜单项。好,现在让我们来试验一下,再在Menu中添加一个菜单项:  

  Menu.AppendMenu(MF_STRING,   ID_APP_EDIT,   "&Edit");  

  可以看到又出来一项,仍然是按下去什么都没有,但这证明了我们之前的结论——Menu就好比横过来的一个菜单,有固定的位置。  

     

  如何要让这个菜单项按下去出现另一个菜单,就要另外创建一个浮动菜单(Pop-up   Menu),因为只有浮动菜单可以连到另一个菜单中去。好,让我们修改代码成下面这个样子:  

  CMenu Menu,PopupMenu;  

   

  Menu.CreateMenu();  

  PopupMenu.CreatePopupMenu();  

   

  PopupMenu.AppendMenu(MF_STRING,IDC_POPMENU_FILE_NEW,"&New");  

  PopupMenu.AppendMenu(MF_STRING,IDC_POPMENU_FILE_OPEN,"&Open");  

  PopupMenu.AppendMenu(MF_STRING,IDC_POPMENU_FILE_CLOSE,"&Close");  

  PopupMenu.AppendMenu(MF_STRING,IDC_POPMENU_FILE_EXIT,"E&xit");  

   

  Menu.AppendMenu(MF_POPUP,   (UINT)PopupMenu.m_hMenu,   "&File");   //关键!  

  Menu.AppendMenu(MF_STRING,   ID_APP_EDIT,   "&Edit");  

   

  SetMenu(&Menu);  

  Menu.Detach();  

  PopupMenu.Detach();  

  然后看看效果:  

     

  现在我们来详细分析一下上面的代码。  

  首先,再创建一个CMenu类的对象PopupMenu,然后调用函数CreatePopupMenu创建了一个空的浮动菜单。紧接着向这个空的浮动菜单中加入我们想要的菜单项。接着是最关键的一步:  

  Menu.AppendMenu(MF_POPUP,   (UINT)PopupMenu.m_hMenu,   "&File");  

  这一步是向普通菜单Menu中追加一项。注意这里的参数和下一句有什么不同。第一个参数设成MF_POPUP,表示本菜单项(即“File”这个菜单项),是用来操纵一个浮动菜单的,第二个参数,原本应该是新菜单项的命令ID,这里设成子菜单的句柄。因为单击Fiile菜单项的时候,它的动作是弹出浮动菜单,所以它就没有必要拥有命令ID了(命令ID只是为了处理单击消息而设),最后一个参数,是这个菜单项在Menu中的标题,如果换成别的字符串,譬如Hello,那么最上面的File将变成Hello。  

  这里要强调一点,普通的Menu(相对Pop-up   Menu而言),就 只是标题栏下面那一条,这一行上都是它的菜单项(你可以把它看成是一个横过来放的菜单);而所有在鼠标点击后才出现的菜单(不管是左键还是右键),统统都是Pop-up   Menu(也可以认为,Menu就是横排的菜单,Pop-up   Menu就是竖排的菜单)。以一个Windows   Shell窗口为例,只有最上一行才是Menu,其中诸如“文件”,“编辑”等等,每个都是Menu的一个Item,其余,都是Pop-up   Menu。  

     

  最后简单介绍一下如何实现右键弹出菜单。步骤很简单:首先,映射WM_CONTEXTMENU消息,在消息处理函数中,先通过指定要弹出的子菜单的位次,用函数GetSubMenu函数得到该子菜单的指针。这里要注意,指定位次的菜单项,必须是有MF_POPUP属性的,并且的菜单项是从上到下以0为开始计数的(对于普通Menu则是从左到右)。得到想要的菜单的指针后,就可以用函数TrackPopupMenu把菜单在指定的位置显示出来了。整个用于显示的代码只有一行即可(当然为了安全性可以增加一些ASSERT宏进行检测,这里为了突出重点而略过):  

  GetMenu()->GetSubMenu(0)->  

  TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON,point.x,point.y,this);  

  这里GetMenu得到最上面的主菜单指针,GetSubMenu(0)得到File下面的Pop-up菜单指针,最后用TrackPopupMenu将其显示出来。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值