分享
 
 
 

CMenu

王朝百科·作者佚名  2010-04-05
窄屏简体版  字體: |||超大  

对于系统菜单,创建起来比较简单,直接使用资源编辑器就能生成菜单,再通过ClassWizard创建菜单命令函数。在我的资源中上传了一个工程,实现了一个右键弹出贴图菜单。结合这个工程,介绍动态创建菜单、创建弹出式菜单和重绘菜单。

首先介绍基础知识:

一、CMenu类的成员函数:

1. CreateMenu()和CreatePopupMenu(),这两个函数用来创建一个菜单实例,CreateMenu()创建的是普通的菜单实例,如果想创建弹出式菜单,就要用CreatePopupMenu()函数。

2. AppendMenu()向菜单中添加一个子项,这个函数有两个主要的参数。第一个UINT nFlags,这个参数表明了该子项的属性特征,可以这样说,这个参数规定了菜单的样式和功能。后面会详细讲这个参数所能使用的值。第二个参数UINT_PTR nIDNewItem,根据nFlags使用不同的设置,该参数将标明菜单的资源ID或在这个菜单中的索引号。第三个参数可以省略,如果不省略,可以传入一个字符串,这个字符串将显示在菜单中(因为我准备用突破表示菜单项,所以我的工程中省略了这个参数)。

3. DrawItem(),这是一个虚函数,如果菜单设置成可以自绘类型,则这个函数将在生成菜单、弹出菜单、选中菜单、点击菜单等时由系统框架调用。因此,这个函数是一个很有用的函数,它可以帮你绘制出各种样式的菜单。

4. MeasureItem()也是一个虚函数,当菜单被创建的时候由系统框架调用。这个函数用来设置菜单的大小。

二、nFlags说明:

只有当nFlags设置成MF_OWNERDRAW的时候,系统框架才会重绘菜单。

MF_CHECKED:命令旁显示默认复选标志

MF_UNCHECKED:清除命令旁的复选标志

MF_DISABLED:禁止此菜单命令,但是不变灰显示

MF_ENABLED:允许此菜单命令,恢复到正常状态

MF_GRAYED:禁止此菜单命令,变灰显示

MF_MENUBARBREAK:对于静态菜单,放到新行;对于弹出菜单,放到新栏 中,栏间有分隔线

MF_MENUBREAK:对于静态菜单,放到新行;对于弹出菜单,放到新栏,栏间雾分隔线

MF_OWNERDRAW:指定该命令是自画式菜单命令

MF_POPUP:指定该菜单命令有一个关联的弹出式菜单

MF_SEPARATOR:画一条水平分隔线,只用于弹出式菜单

MF_STRING:指定此菜单命令是一个字符串

CMenu类从CObject类派生而来。为什么要使用CMenu类呢?AppWzard不是把菜 单做好了吗?在资源编辑器上修改菜单不是很方便吗?

感觉学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

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;

CMenu类为Windows HMENU的封装类。它提供了成员函数以用于创建、追踪、更新及销毁菜单。

在本地的堆栈框架中创建一个CMenu对象,然后调用CMenu的成员函数来操纵所需的新菜单。接着,调用CWnd::SetMenu函数为窗口设置菜单。然后立即调用CMenu对象的Detach成员函数。CWnd::SetMenu成员函数将窗口的菜单设置为新菜单,这将导致在窗口刷新后将影响菜单的改变,同时也将菜单的拥有者传递给窗口。调用Detach函数将把HMENU从CMenu对象中分离出来,以便当本地的CMenu变量超出范围后,CMenu对象的构造函数将不会销毁不再拥有的菜单。当窗口销毁后,菜单自动销毁。

可以调用LoadMenuIndirect成员函数在内存中创建来自模板的菜单,不过通过调用LoadMenu创建的菜单更容易维护。并且这种菜单资源本身也可以由菜单编辑器创建或修改。

#include <afxwin.h>

CMenu类的成员

数据成员m_hMenu指定附加给CMenu对象的窗口菜单的句柄

构造函数CMenu构造一个CMenu对象

初始化Attach附加一个Windows菜单句柄给CMenu对象Detach从CMenu对象中分离Windows菜单的句柄,并返回该句柄FromHandle返回一个指向给定Windows菜单句柄的CMenu对象的指针GetSafeHmenu返回由CMenu对象包含的m_hMenu值DeleteTempMap删除由FromHandle成员函数创建的所有临时CMenu对象CreateMenu创建一个空菜单,并将其附加给CMenu对象CreatePopupMenu创建一个空的弹出菜单,并将其附加给CMenu对象LoadMenu从可执行文件中装载菜单资源,并将其附加给CMenu对象LoadMenuIndirect从内存的菜单模板中装载菜单,并将其附加给CMenu对象DestroyMenu销毁附加给CMenu对象的菜单,并释放菜单占用的内存

菜单操作DeleteMenu从菜单中删除指定的项。如果菜单项与弹出菜单相关联,那么将销毁弹出菜单的句柄,并释放它占用的内存TrackPopupMenu在指定的位置显示浮动菜单,并跟踪弹出菜单的选择项

菜单项操作AppendMenu在该菜单末尾添加新的菜单项CheckMenuItem在弹出菜单的菜单项中放置或删除检测标记CheckMenuRadioItem将单选钮放置在菜单项之前,或从组中所有的其它菜单项中删除单选钮SetDefaultItem为指定的菜单设置缺省的菜单项GetDefaultItem获取指定的菜单缺省的菜单项EnableMenuItem使菜单项有效、无效或变灰GetMenuItemCount决定弹出菜单或顶层菜单的项数GetMenuItemID获取位于指定位置菜单项的菜单项标识GetMenuState返回指定菜单项的状态或弹出菜单的项数GetMenuString获取指定菜单项的标签GetMenuItemInfo获取有关菜单项的信息GetSubMenu获取指向弹出菜单的指针InsertMenu在指定位置插入新菜单项,并顺次下移其它菜单项ModifyMenu改变指定位置的已存在的菜单项RemoveMenu从指定的菜单中删除与弹出菜单相关联的菜单项SetMenuItemBitmaps将指定检测标记的位图与菜单项关联GetMenuCountextHelpID获取与菜单关联的帮助文本的ID号SetMenuCountextHelpID设置与菜单关联的帮助文本的ID号

可覆盖的函数DrawItem通过框架来调用,其发生于拥有者菜单的可视部分有所改变MeasureItem通过框架来调用,用于决定当创建了拥有者菜单时的菜单维数

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有