做一个MFC程序的时候碰到一个需求。就是需要根据定制情况,动态生成菜单,菜单的具体结构和信息是之前不知道的(因此不能利用工具构造),点击不同类型的菜单会触发特定的一类事件(需要动态绑定事件)。这种需求实际是蛮不BT的,很多场合下都可能会有,用C#写了个Demo花了不到半个小时。但转到MFC下来写,就费尽周折。其实这个问题代表了在MFC中动态创建资源绑定事件的一般性问题,所以总结一下。

动态创建菜单需要先了CMenu类。通常我们利用工具绘制一个菜单,每一个菜单项下都可以视为有一个CMenu类。它们联系在一起,形成树状。典型的一个菜单对应过来是如下图这个样子:

如上,CMenu可以分成三种,一个是Popup(黄色),一个是Separator(灰色),一个是Item(红色)。前两种都是没有ID信息的,Popup有一个指针,指向其SubMenu;Item保存各种信息有ID可以响应事件;Separator,恩,基本是一穷二白的。

CMenu的CreateMenu方法可以创建一个菜单资源,用DeleteMenu(包含所有子菜单)或DestoryMenu可以销毁菜单资源,用AppendMenu可以添加一个菜单。了解这些内容,就可以开工了,现实现上图所示的MainSubMenu1下菜单的动态创建,代码如下:

// 假设在ChildFrm中,调用该方法获得当前的主菜单指针
    CMenu* mainMenu = AfxGetMainWnd()->GetMenu();
    CMenu* subMenu = NULL;

// 遍历主菜单下的各级菜单寻找名为MainSubMenu1的菜单

int menuCount = mainMenu->GetMenuItemCount();

for(int i = 0; i < menuCount; i++)
    {
        CString menuName;
        if(mainMenu->GetMenuStringA(i, menuName, MF_BYPOSITION)
            && menuName == "&MainSubMenu1")
        {
            drawingMenu = mainMenu->GetSubMenu(i);
            break;
        }
    }

// 移除原有的菜单项
    int subMenu1Count = subMenu->GetMenuItemCount();
    for(int i = subMenu1Count - 1; i >= 0; i--)
    {
        subMenu->DeleteMenu(i, MF_BYPOSITION);
    }

// 动态添加Item菜单项
    for(int i = 0; i < 2; i++)
    {

CString message = "";

subMenu->AppendMenuA(MF_STRING, ID_BEGIN + i, message.Format("SubSubMenu%i", i);

}

// 添加分隔符

subMenu->AppendMenuA(MF_SEPARATOR);

// 添加弹出式子菜单

CMenu * popupMenu = new CMenu();
    popupMenu->CreateMenu();
    for(int i = 0; i < 2; i++)
    {

CString message = "";

popupMenu->AppendMenuA(MF_STRING, ID_BEGIN + 2 + i, message.Format("PopupSubMenu%i", i));

}
    subMenu->AppendMenuA(MF_POPUP, (UINT_PTR)popupMenu->operator HMENU(), "PopupMenu");

有几个需要注意的地方,一个是主菜单的指针获得,可以参考《MFC框架各部分指针获取方式》一文。另一个是Popup的菜单建立,策略是分成两部分,先new出内存在Create出资源,缺一不可。最后一个是为每个Item菜单合理分配ID,这些ID须事先预留出来,在MFC中,至少40000到49000通常都是没人用。

这也就引出下一个问题,即菜单事件的动态绑定。我们知道在.net中,事件是真正动态绑定的,而MFC中的事件都是只能静态绑定,这是由两者的编译方式决定的。所以,在MFC中需要定义菜单事件,你需要先挖好坑(预留足够ID),规定每个坑种什么罗卜(将不同类型的ID绑定到不同类别的事件处理函数上),最后才能按坑种罗卜(为执行相应事件的菜单设置相应的ID)。

可以有两种方式来绑定对应ID处理的事件,一个是通过ON_COMMAND_RANGE宏(想一下ON_COMMAND宏会不会派上用场?)在MessageMap里绑定批量处理事件的函数;另一个是重载PreTranslateMessage函数,截获并判断ID来进行处理。思想都是类似的。值得注意的是,通常还需要配套使用ON_UPDATE_COMMAND_UI_RANGE来保证动态创建的菜单Enable为True,否则很可能菜单不可以点击(我就被郁闷过很久:()。

MFC动态菜单全攻略相关推荐

  1. [转]ASP.NET页面HEAD区动态设置全攻略

    网页head区,不能用普通控件,但它有时又很重要,比如title.keywords.description,可能每个页面都不同,那么怎么样才能根据内容动态设置它们呢? 方法1:asp能做到的,asp. ...

  2. Dreamweaver下拉菜单全攻略

    下拉菜单是网上最常见到的效果之一,用鼠标轻轻一点或是移过去,就出现一个更加详细的菜单,它不仅节省了网页排版上的空间.使网页布局简洁有序,而且一个新颖美观的下拉菜单,更是为您的网页增色不少. 制作下拉菜 ...

  3. 用C#制作PDF文件全攻略(转)

    PDF文件是目前比较流行的电子文档格式,在办公自动化(OA)等软件的开发中,经常要用到该格式,但介绍如何制作PDF格式文件的资料非常少,在网上搜来搜去,都转贴的是同一段"暴力"破解 ...

  4. 前端小白也能快速学会的博客园博客美化全攻略

    前端小白也能快速学会的博客园博客美化全攻略 A呦V,博客园er的自我修养是什么?第一条,别只顾收藏和偷师呀,记得点"推荐"或关注本人喔~ 美化方法论简介 一般而言,需要选一个默认的 ...

  5. VC用ADO访问数据库全攻略  作者 相生昌

    VC用ADO访问数据库全攻略 作者 相生昌 <script language=VBScript> document.title="VC用ADO访问数据库全攻略 "&am ...

  6. 用C# itextsharp.dll制作PDF文件全攻略

    StreamWriter pPDF=new StreamWriter(filePath); ArrayList xRefs=new ArrayList(); float yPos =0f; long ...

  7. 用C#制作PDF文件全攻略 (专至csdn)

    前 言 丽水市汽车运输集团有限公司信息中心 苟安廷 PDF文件是目前比较流行的电子文档格式,在办公自动化(OA)等软件的开发中,经常要用到该格式,但介绍如何制作PDF格式文件的资料非常少,在网上搜来搜 ...

  8. 彻底分析ARP病毒查杀防范全攻略

                           彻底分析ARP病毒查杀防范全攻略      近期在全国范围内大规模爆发arp病毒及其各种变种.如果局域网中发现许多台电脑中毒,电脑中毒后会向同网段内所有计 ...

  9. SAP HANA Cloud Connector图文全攻略

    SAP HANA Cloud Connector图文全攻略 http://mp.weixin.qq.com/s?__biz=MjM5OTI2MjgyMA==&mid=2651785635&am ...

  10. Win7开机加速全攻略四:系统服务优化

    IT168 实用技巧]如何加快Windows 7系统的开机速度一直都是大家热议的问题,网络中流传的方法也很多,本站为大家整理了一些加快Windows 7系统的开机速度的方法,在接下去的几天中,将陆续分 ...

最新文章

  1. BZOJ 1050: [HAOI2006]旅行comf(枚举+并查集)
  2. linux 内核编译错误 undefined reference to '__mutex_lock_slowpath'
  3. Using Preferences(Beginning Android)
  4. xfermode的基本用法
  5. [ZJOI2009]假期的宿舍
  6. 万网mysql中文乱码_Linux下MySQL出现乱码的解决方法-阿里云开发者社区
  7. 06、主题 样式 国际化
  8. Spring Boot 使用Redis
  9. 最良心的 chrome 插件可以良心到什么程度?
  10. 操作系统中的fork()函数对应的进程创建过程
  11. 原码,补码,反码概念和计算方法详解
  12. VMware8序列号
  13. matlab:双或三方演化博弈,lotka-Volterra 1.双方演化博弈
  14. 曲速未来 揭示:Lisk(LSK)有什么价值?
  15. 智能手环: 调研报告
  16. 微信小程序-API的Promise化
  17. redis的过期键删除策略
  18. Excel快速对齐表格的中姓名(两个字姓名和三个字姓名对齐)
  19. KIS与KAV,KAV personal与KAV pro的区别!
  20. windows常用doc命令

热门文章

  1. Scrapy输出CSV指定列顺序
  2. 通过bindservice方式调用服务方法里面的过程
  3. git svn clone
  4. 多线程中,static函数与非static函数的区别?
  5. 关于12864显示器的SPI串行驱动问题的研究,AVR处理器(1)
  6. (转)Flex compc ant 编译
  7. 解决bootstrap-table表头filter-control select控件被遮挡显示不全的问题
  8. 洛谷 P1875 佳佳的魔法药水
  9. Jquery Ajax 异步设置Table中某列的值
  10. MongoDB-Getting Started with the C# Driver