词条 | CMenu |
释义 | 定义对于系统菜单,创建起来比较简单,直接使用资源编辑器就能生成菜单,再通过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); }三。如果使用资源的话,创建菜单确实非常简单了,只须在窗口类的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 初始化 Attach 菜单操作 DeleteMenu 菜单项操作 AppendMenu 可覆盖的函数 DrawItem |
随便看 |
百科全书收录4421916条中文百科知识,基本涵盖了大多数领域的百科知识,是一部内容开放、自由的电子版百科全书。