VC驿站

 找回密码
 加入驿站

QQ登录

只需一步,快速开始

搜索
查看: 1650|回复: 11

[原创] 怎样使用CMenu类之我见

[复制链接]
79_avatar_middle
在线会员 发表于 2015-12-18 20:41:24 | 显示全部楼层 |阅读模式
我是个vc++初学者,,也学到了不少东西。感觉学vc++稍微深入一点好,至少要能搞清楚AppWizard在背后都干了些什么东西。
事实上mfc就是用CMenu类来生成菜单的。让我们就从CMenu开始吧。
    CMenu生成的菜单有两种:Popup类型和非Popup类型。这两种方法里又可以分
成使用资源编辑器生成的菜单资源和不使用这个资源。对于非Popup类型的菜单,
必须在创建出来后把它张贴到某个窗口上,它才会显示出来,从而才有用处。Po
pup的菜单却不能张贴到窗口上。
    说明之前,先定义几个常量:
#define IDM_MENU0 0
#define IDM_MENU1 1
#define IDM_MENU2 2
#define IDM_MENU3 3
#define IDM_ITEM0 10
#define IDM_ITEM1 11
#define IDM_ITEM2 12
#define IDM_ITEM3 13
#define IDM_ITEM4 14
#define IDM_ITEM5 15
#define IDM_ITEM6 16


一。创建非Popup类型菜单,不使用资源。
(一)创建非下拉菜单。
1。在窗口类的OnCreate函数里创建CMenu对象。如果是创建运用程序主框架窗口
的话,也可以在InitInstance()函数里。
2。声明一个CMenu对象:CMenu MyMenu;
3。调用MyMenu.CreateMenu()或MyMenu.LoadMenu()
4。调用若干次MyMenu.AppendMenu()或MyMenu.InsertMenu(),每调用一次创建一
个菜单项。
5。调用MyMneu.SetMenu()将菜单Attach到窗口上。
6。调用MyMenu.Detach()。

例子:
int CMyWnd::OnCreate( LPCREATESTRUCT lpCreateStruct )
{
     CMenu MyMenu;
     MyMenu.CreateMenu();
     MyMenu.AppendMenu(MF_STRING,IDM_MENU0,"文件");
     MyMenu.AppendMenu(MF_STRING,IDM_MENU1,"编辑");
     MyMenu.AppendMenu(MF_STRING,IDM_MENU2,"查看");
     MyMenu.AppendMenu(MF_STRING,IDM_MENU3,"帮助");
     MyMenu.InsertMenu(IDM_MENU2,MF_BYCOMMAND,IDM_ITEM0,"有关");
     this->SetMenu(&MyMenu);
     MyMenu.Detach();
     return 0;
}//各个函数的细节就不讲解了,看联机帮助是最好的。
    这个方法是先把菜单创建好后再贴到窗口上去,然后用Detach()使菜单和My
Menu对象脱离关系,因为MyMenu对象马上就要超出作用域了,这一步是必须的。


(二)创建下拉菜单,不使用资源。
    这种菜单当鼠标移动到菜单条目上面点击时不是去执行某段程序,而是弹出
一个下拉菜单。这需要用前面的方法创建两个菜单。第一个是鼠标未点击时看到
的那个菜单,另一个就是扮演下拉菜单的菜单。例子:
int CMyWnd::OnCreate( LPCREATESTRUCT lpCreateStruct )
{
        CMenu MyMenu0,MyMenu1;
        //下面这几条创建下拉菜单
        MyMenu1.CreateMenu();
        MyMenu1.AppendMenu(MF_STRING,IDM_ITEM0,"拷贝");
        MyMenu1.AppendMenu(MF_STRING,IDM_ITEM1,"剪切");
        MyMenu1.AppendMenu(MF_STRING,IDM_ITEM2,"粘贴");
        MyMenu1.AppendMenu(MF_SEPARATOR,IDM_ITEM3,"");
        MyMenu1.AppendMenu(MF_STRING,IDM_ITEM4,"全选");
        MyMenu1.AppendMenu(MF_SEPARATOR,IDM_ITEM5,"");
        MyMenu1.AppendMenu(MF_STRING,IDM_ITEM6,"删除");
        //下面这两条创建鼠标未点击时看到的那个菜单
        //其中第二句将下拉菜单张贴到第一个菜单上。
        MyMenu0.CreateMenu();
        MyMenu0.AppendMenu(MF_POPUP,(UINT)MyMenu1.m_hMenu,"编辑");

        this->SetMenu(&MyMenu0);//将菜单张贴到窗口上
        MyMenu0.Detach();//必须有
        MyMenu1.Detach();//必须有
        return 0;
}

二。创建Popup类型的菜单,也不用资源。
    很多程序里,只要用鼠标右键点一下窗口客户区,就会在鼠标的位置弹出一
个菜单,这叫右键菜单。我们可以用CMenu类来制作。
    制作这种菜单比制作第一类菜单稍微复杂点。首先要在窗口类里加个成员变
量:CMenu *MyMenu2;
    然后在窗口类的构造函数里(或OnCreate()函数里)加上创建菜单的语句,再
在析构函数里加上销毁菜单的语句,最后在OnRButtonDown()函数里加上显示菜单
的语句。
    创建菜单时,CMenu类对象应该用new来分配。
    例子:

CMyWnd::CMyWnd()
{
     //CMyWnd是从CWnd派生来的。
     //先把菜单创建起来。
     MyMenu2=new CMenu;
     MyMenu2->CreatePopupMenu();
     MyMenu2->AppendMenu(MF_STRING,IDM_ITEM0,"拷贝");
     MyMenu2->AppendMenu(MF_STRING,IDM_ITEM1,"剪切");
     MyMenu2->AppendMenu(MF_STRING,IDM_ITEM2,"粘贴");
     MyMenu2->AppendMenu(MF_SEPARATOR,IDM_ITEM3,"");
     MyMenu2->AppendMenu(MF_STRING,IDM_ITEM4,"全选");
     MyMenu2->AppendMenu(MF_SEPARATOR,IDM_ITEM3,"");
     MyMenu2->AppendMenu(MF_STRING,IDM_ITEM5,"删除");

}
CMyWnd::~CMyWnd()
{
     MyMenu2->DestroyMenu();//销毁菜单所占用的系统资源
     delete MyMenu2;//销毁菜单类对象
}
void CMyWnd::OnRButtonDown(UINT nFlags, CPoint point)
{
     RECT rect;
     GetWindowRect(&rect);
     //显示菜单
     MyMenu2->TrackPopupMenu(TPM_RIGHTALIGN,point.x+rect.left,point.y+
rect.top,this,NULL);
}

三。使用资源编辑器做好的菜单,只能做非POPUP类型菜单。
    如果使用资源的话,创建菜单确实非常简单了,只须在窗口类的OnCreate()
函数里加几句话就行了:
int CMyWnd::OnCreate( LPCREATESTRUCT lpCreateStruct )
{
     CMenu  MyMenu3;
     MyMenu3.LoadMenu(IDR_MENU1);//IDR_MENU1是你的菜单的资源ID。
     this->SetMenu(&MyMenu3);
     MyMenu3.Detach();
     return 0;
}



    CMenu类还有很多成员函数,使你可以在运行中对菜单进行裁剪,比如加上几
项或减去几项等等,使用非常方便。大家可以去看msdn。

    如果要实验以上的菜单创建方法的话,可以用一个非常简单的mfc程序来搞:


//这是一个非常简单的mfc程序,必要的函数自己去加吧。
#include <afxwin.h>

class CMyApp : public CWinApp
{
public:
     virtual BOOL InitInstance();
};

class CMyWnd : public CWnd
{
public:
      DECLARE_MESSAGE_MAP()
};

CMyApp MyApp;

BEGIN_MESSAGE_MAP(CMyWnd,CWnd)
END_MESSAGE_MAP()

BOOL CMyApp::InitInstance()
{
      RECT rect={30,30,400,300};
      CMyWnd* pCWindow=new CMyWnd;
      pCWindow->CreateEx
      (
         NULL,
         AfxRegisterWndClass(NULL,0,(HBRUSH)::GetStockObject(WHITE_BRU
SH),0),
         "实验程序",
         WS_OVERLAPPEDWINDOW,
         rect,NULL,NULL,NULL
      );
      m_pMainWnd = pCWindow;
      pCWindow->ShowWindow(m_nCmdShow);
      pCWindow->UpdateWindow();

      return TRUE;
}
为了防止伸手党 所以请回复后观看

评分

参与人数 4驿站币 +6 热心值 +6 收起 理由
88_avatar_small 寂寞江湖 + 2 + 2 赞一个!
21_avatar_small jankey + 1 + 1
10_avatar_small cmx006 + 1 + 1 很给力!
65_avatar_small 编程者 + 2 + 2 很给力!

查看全部评分





上一篇:VS 2005使用map文件查找程序崩溃原因
下一篇:将一个十六进制字符串转换为十进制数值的几种方法
65_avatar_middle
donate_vip 发表于 2015-12-19 08:36:09 | 显示全部楼层
回复后观看
73_avatar_middle
在线会员 发表于 2015-12-19 11:12:16 | 显示全部楼层
可不可以做一个全局公用的MENU?,可以在所有的窗口中注入的功能
79_avatar_middle
ico_lz  楼主| 发表于 2015-12-19 13:47:35 | 显示全部楼层
yutianyu 发表于 2015-12-19 11:12
可不可以做一个全局公用的MENU?,可以在所有的窗口中注入的功能

看过了 请加热心
10_avatar_middle
在线会员 发表于 2015-12-19 13:48:19 | 显示全部楼层
看看好不好
21_avatar_middle
在线会员 发表于 2015-12-19 15:18:15 | 显示全部楼层
CMenu类老大好像讲过
02_avatar_middle
在线会员 发表于 2016-1-7 11:22:16 | 显示全部楼层
看看是否使用资源
02_avatar_middle
在线会员 发表于 2016-1-7 11:25:38 | 显示全部楼层
不错,有借鉴意义。以后借用。
49_avatar_middle
online_vip 发表于 2016-2-19 14:10:23 | 显示全部楼层
CMenu类之我见
61_avatar_middle
在线会员 发表于 2016-3-22 10:35:01 | 显示全部楼层
学习CMENU 来看看
95_avatar_middle
在线会员 发表于 2017-5-18 14:28:45 | 显示全部楼层
回复后观看
51_avatar_middle
online_vip 发表于 2018-1-25 22:33:40 | 显示全部楼层
学习一下
您需要登录后才可以回帖 登录 | 加入驿站 qq_login

本版积分规则

关闭

站长提醒上一条 /2 下一条

QQ|小黑屋|手机版|VC驿站 ( 辽ICP备09019393号tongdun|网站地图wx_jqr

GMT+8, 2019-6-20 02:13

Powered by Discuz! X3.4

© 2009-2019 cctry.com

快速回复 返回顶部 返回列表