C++ MFC中的CMenu---动态添加菜单/菜单项_mfc cmenu_安静平和的博客-程序员宅基地

技术标签: C/C++  Cmenu  C++  动态菜单  mfc  

如何动态添加菜单/菜单项、子菜单、右键菜单

有关菜单的操作主要用到CMenu类,当然也可用相应API函数,CMenu类只是MFC对API中操作菜单的函数的封装而已。 不过能用类就尽量用类,类的组织方式好呗,代码看着也舒服。 若是SDK编程,那就用API吧 。

     CMenu menuMain,menu1; //首先 定义CMenu对象

一、 创建菜单,有两种方法

1. 用LoadMenu函数从资源加载

menuMain.LoadMenu(IDR_MAINFRAME); //从资源加载,这里使用SDI的主菜单资源

2. 用CreateMenu函数创建

menu1.CreateMenu();   //创建菜单,还没有菜单项

二、 添加菜单项,可用AppendMenu()在菜单的最后加、InsertMenu()在指定的位置加.

// ID_TEST1 在Resource.h 中定义,随便给个整数值,不要和已有的重复就行了

menu1.AppendMenu(MF_STRING,ID_TEST1,"Test1"); // 第一项菜单项

menu1.AppendMenu(MF_STRING,ID_TEST2,"Test2"); // 第二项菜单项

menu1.InsertMenu(1,MF_BYPOSITION|MF_STRING,

(UINT)ID_TEST1,"ID_TEST1"); // 在第二项菜单项前添加新菜单项

三、 添加子菜单

同样用AppendMenu()、InsertMenu()函数。不过要注意参数的设置。

menu1.AppendMenu(MF_BYPOSITION|MF_POPUP|MF_STRING,

(UINT) menuMain.GetSubMenu(0) ->m_hMenu,"子菜单");

//第二个参数是菜单的句柄HMENU

四、 删除菜单

用DeleteMenu()、RemoveMenu()函数来删除指定位置的菜单/菜单项。

两者区别:如果菜单项是一个弹出式菜单,那么DeleteMenu和RemoveMenu之间的区别就很重要。DeleteMenu清除弹出式菜单,但RemoveMenu不清除它。一个是彻底的删除,一个只是移除.

MSDN: 1.The   DeleteMenu   function   destroys   the   handle   to   the   menu   or   submenu   and   frees   the   memory   used   by   the   menu   or   submenu.       它使菜单或者子菜单的handle无效(destroys)。

2.   RemoveMenu   does   not   destroy   the   menu   or   its   handle,   allowing   the   menu   to   be   reused. 可以再利用,并不从内存中将menu删除。

五、 添加右键菜单

CMenu menu1;

      menu1.CreatePopupMenu();     //动态创建弹出式菜单对象

      menu1.AppendMenu(MF_STRING,ID_TEST1," 菜单项1");

      menu1.AppendMenu(MF_STRING,ID_TEST2," 菜单项2");

menu1.InsertMenu(2,MF_BYPOSITION|MF_POPUP|MF_STRING,

           (UINT) menuMain.m_hMenu,"子菜单"); //添加子菜单

      CPoint pt;

      GetCursorPos(&pt);

      menu1.TrackPopupMenu(TPM_RIGHTBUTTON, pt.x, pt.y, this);

      menu1.DestroyMenu();

[转]MFC中的CMenu---如何动态添加菜单/菜单项,子菜单,右键菜单 - 金星 - 金清...

六、 响应菜单的事件

1. 若是资源中添加的菜单可用Class Wizard添加菜单的响应事件。

2. 若是通过代码创建的菜单,要手工实现菜单的消息映射。本例是在CmainFrame类中,当然也可在View类、Doc类中,基于对话框的同样也可以。

1) 在.h文件中

// Generated message map functions

protected:

       //{ {AFX_MSG(CMainFrame)

       afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);

afx_msg void OnChangmenuitem(); //这里添加菜单命令处理函数的声明

       //}}AFX_MSG

       DECLARE_MESSAGE_MAP()

2) 在.cpp文件中,

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)

       //{ {AFX_MSG_MAP(CMainFrame)

       ON_WM_CREATE()

ON_COMMAND(IDM_CHANGMENUITEM, OnChangmenuitem) //这里添加,注意没有’ ;’

       //}}AFX_MSG_MAP

END_MESSAGE_MAP()

void CMainFrame::OnChangmenuitem()

{

       // 这里写你要如何处理的代码

……

}

其他方法:

若菜单ID值是连续的,最好用ON_COMMAND_RANGE来映射消息处理函数,可以在一个函数中处理一个范围内的所有消息。

当用户按下某个菜单项,会发出一个WM_COMMAND消息,而菜单项的ID号,就包含在参数wParam的低位中.  

BOOL   CYourView::OnCommand(WPARAM   wParam,   LPARAM   lParam)

{

// TODO:   Add your specialized code here and/or call the base class  

UINT   m_nItemID=LOWORD(wParam);  

if   (m_nItemID==ID_YOURITEM) //ID_YOURITEM为你加入菜单项时指定的ID号

{  

          //在这里放入响应的代码

   }  

return   CScrollView::OnCommand(wParam,   lParam);  

}   

   对于右键菜单可以通过TrackPopupMenu的返回值来处理。在参数uFlags中设置TPM_ RETURNCMD,这样返回值就是你选择的菜单项的ID,然后可以根据ID来处理。

TrackPopupMenu(TPM_ RETURNCMD ,pt.x,pt.y,this);

(关于函数TrackPopupMenu,这里有个地方需要注意一下,虽然MSDN里面没有写,但根据我的经验,TPM_ RETURNCMD 值与

TPM_NONOTIFY值一样当你添加了这个值之后,函数都不会再向消息响应窗口发送(send) notification messages when the user clicks on a menu item. 需要你自己处理所有事件,或者你可以调用SendMessage 或PostMessage方法,将WM_COMMAND消息再发送给消息响应窗口,例如: ::PostMessage(m_nid.hWnd, WM_COMMAND, tSelected, 0); //tSelected是TrackPopupMenu的返回值,即发出消息的菜单项ID。)Edited by YY

MSDN:If you specify TPM_RETURNCMD in the uFlags parameter, the return value is the menu-item identifier of the item that the user selected.

(TPM_NONOTIFY
If this flag is set, the function does not send notification messages when the user clicks on a menu item.)Edited by YY

七、 其他

DrawMenuBar () ; //当您改变菜单时,需要重画菜单才能显示所做的改变

GetSystemMenu () ; //取得窗口控制窗口

GetMenu()   //取得当前程序使用的菜单

GetSubMenu() //取得子菜单

应使用CMenu类的Detach()成员函数从Cmenu对象中分离出菜单句柄,避免对象失效后程序出错。

如:

       CMenu menu;

       menu.CreatePopupMenu(); //动态创建弹出式菜单对象

       menu.AppendMenu(0,ID_TEST1,"Test1");

       menu.AppendMenu(0,ID_TEST2,"Test2");

       CMenu* menuMain = GetMenu(); //取得程序主菜单 需在CMainFrame类中

       menuMain->AppendMenu(MF_BYPOSITION|MF_POPUP|MF_STRING,(UINT)menu.m_hMenu,"子菜单1");

       menu.Detach();      //直接用menu.m_hMenu在运行时出错,menu对象在这个事件结束就销毁了

       DrawMenuBar();  

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
    本文链接:https://blog.csdn.net/cnhk1225/article/details/49333645

    智能推荐

    windows shared memory -- msdn document of the file mapping object_share memory msdn-程序员宅基地

    EXECUTE? Execute addresses within the shared memory?CreateFileMappingPAGE_READONLY Allows views to be mapped for read-only or copy-on-write access. An attempt to write to a specific region results_share memory msdn

    区别黑白照片和彩色照片-程序员宅基地

    java区别黑白和彩色照片原理:通过读照片流,获取每个点位的色彩灰度,当灰度点数大于60个点位或者更多的时候则认定其为黑白照片。代码如下: public static boolean execote(File file){ BufferedImage src; try { src = ImageIO.read(file); int height =src....

    ROS执行语音pocketsphinx出错:cannot launch node of type [pocketsphinx/recognizer.py]-程序员宅基地

    ROS执行出错:cannot launch node of type [pocketsphinx/recognizer.py]错误信息:ERROR: cannot launch node of type [pocketsphinx/recognizer.py]: can't locate node [recognizer.py] in package [pocketsphinx]...

    idea在导入了jar包为什么还显示java.lang.ClassNotFoundException: com.mysql.jdbc.Driver 啊,有没有大佬解决一下_导入了jar包还提示classnotfoundexception: com.mysql.jdbc.d-程序员宅基地

    @TOC欢迎使用Markdown编辑器你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。新的改变我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:全新的界面设计 ,将会带来全..._导入了jar包还提示classnotfoundexception: com.mysql.jdbc.driver

    javascript-ajax-json-java-servlet互相传值取值的学习心得-程序员宅基地

    前几天突然想学习以下jquery easyui 但是里面涉及到了json的知识,于是恶补起来ajax知识,经过以上的查资料,终于弄清楚javascript-ajax-json-java-servlet互相传值取值,的过程,特此分享出来,希望能帮助到初学的朋友么,也为了日后自己查询是使用,好了闲话少说,看下面代码go!!使用tomcat6.0index.jsp<%@ page ..._jsp使用json传给servlet的值怎么取

    python之excel操作_pandas 读excel 四舍五入_不染pigpig的博客-程序员宅基地

    python excel 操作(1)对excel表格某列数据四舍五入取整数代码四舍五入取整数import pandas as pddata = pd.read_excel(“2013flower.xlsx”)data = round(data)向下取整数data = int(data)四舍五入保留2位小数data= round(data,2)向上取整数data = math.ceil(data)data.to_excel(“2013flower1.xlsx”, sheet_na_pandas 读excel 四舍五入

    随便推点

    mybatis遍历集合List、Array、Map-程序员宅基地

    一、遍历集合1.不用注解public void insertList(List<User> users);<insert id="insertList" parameterType="java.util.List" >insert into user (id,name,password,sex,age)values <foreach collec..._mybatis遍历集合

    github快速下载_kuaisuxiazaigithub-程序员宅基地

    首先选择好下载时段,我用校园网在上午9点半左右网速很快,晚上60Kb/s,今天早上9.30直接最高3Mb/s,平均也有近400Kb/s,下载的是同样的文件。第二,使用码云,具体使用方法见如下网站:https://blog.csdn.net/weixin_39125053/article/details/88569938..._kuaisuxiazaigithub

    java导入大文件数据的解决方案_java导入十几m的文件-程序员宅基地

    2018年11月5号于南昌 中海蓝域小区 卧榻伴音弦最近在做项目,一个20G大小的文件,要按行读入到数据库,妈呀,有什么好方法吗?20G如果按照行读入的方式,需要20多个小时才能入库成功。主要性能瓶颈不是在内存,而是在数据库连接的次数。比如批量单次插入1000条和单次插入200条,其实是五倍性能差距。但是这个批量插入的条数是根据数据库缓存大小设置而决定的,数据库缓存不可能太大,比如一个8G..._java导入十几m的文件

    idea查看方法的返回类型和自动出来变量_idea查询后自动出对象名-程序员宅基地

    idea查看方法的返回类型: //解析request,需要抛异常 upload.parseRequest(request);比如说这时候,要出来,parseRequest()方法的返回类型这时候可以使用Ctrl+Q,出来该方法的返回类型,会发现该方法的返回类型是List<FileItem>。这时候,引申出来第二个问题,如何自动生成变量(对象)?..._idea查询后自动出对象名

    AndroidStudio2.2学习《第一行代码》HelloWorld报错:Failed to resolve: com.android.support:appcompat-v7:27.+-程序员宅基地

    相信很多小伙伴和我一样,学习《Android第一行代码》第二版,安装了Android Studio 2.2,刚建立第一个HelloWorld代码时,就开始报错。 报错信息如图,以后也可能是v7:28.+或v7:29.+等。解决方法是:file>settings 查看自己的Android SDK Tools的版本,如图是26.1.1。如果你和我一样是26的SDK,像我这样...

    新版Android Studio火烈鸟 在新建项目工程时 无法选java的语言模板解决方法_吕氏春秋i的博客-程序员宅基地

    最近下载最新版androidstudio时 发现不能勾选java语言模板了如果快速点击下一步 新建项目 默认是kotlin语言模板 这可能和google主推kt语言有关。