《VC++深入详解》学习笔记[5]——第6章 菜单

本文深入探讨了MFC菜单系统的概念、组件及其在实际应用中的操作方法,包括弹出式菜单、命令消息路由、基本菜单操作、快捷菜单、动态菜单等。详细介绍了如何标记、设置默认菜单项、图形标记菜单、禁用菜单项、移除和装载菜单,以及MFC菜单命令更新机制。同时,提供了MFC菜单系统中动态菜单操作的实例,包括添加、插入、删除菜单项目,以及如何实现快捷菜单。文章旨在为开发者提供全面的MFC菜单系统指导。
 

第6章 菜单

1.MFC中把设置为Pop-up类型的菜单称为弹出式菜单,Visual C++默认顶层菜单为弹出式菜单。这种菜单不能响应命令。

2.菜单命令的路由

程序类对菜单命令的响应顺序依次是:视类、文档类、框架类、应用程序类;

Windows消息的分类

①标准消息(窗口消息):除WM_COMMAND之外,所有以WM_开头的消息都是标准消息。从CWnd派生的类都可以接收到这类消息。

②命令消息:来自菜单、加速键或者工具栏按钮的消息。这类消息都以WM_COMMAND形式呈现。在MFC中,通过菜单项的标识(ID)来区分不同的命令消息;在SDK中,通过消息的wParam参数识别。从CCmdTarget派生的类都可以接收到这类消息。

③通告消息(控件消息):由控件产生的消息,目的是向其父窗口(通常是对话框)通知事件的发生。这类消息也是以WM_COMMAND形式呈现的。从CCmdTarget派生的类都可以接收到这类消息。

因为CWnd派生于CCmdTarget类,也就是说,凡是从CWnd派生的类,它们既可以接收标准消息,也可以接收命令消息和通告消息,而对于那些从CCmdTarget派生的类,则只能接收命令消息和通告消息,不能接收标准消息。

菜单命令消息路由的具体过程:当点击某个菜单项时,最先收到这个菜单命令消息的是框架类。框架类将把这个消息交给视类,视类首先进行处理。视类根据命令消息映射机制查找自身是否对此消息进行了响应,如果响应了就调用相应响应函数对这个消息进行处理,消息路由结束;如果视类没有对此命令消息做出响应,就交由文档类,文档类同样查找消息映射,若进行了响应则消息路由结束,否则将这个消息交还给视类,视类再将该消息交还给框架类。框架类查找自身有无消息响应函数,如果没有则将该命令消息交给应用程序类。

3.基本菜单操作:

如果要访问某个菜单项,既可以通过该菜单项的标识ID,也可以通过其位置索引来实现访问。但对于子菜单来说,只能通过索引号进行访问,因为子菜单是没有标识号的。分隔栏在子菜单中是占据索引位置的。

因为程序的主菜单属于框架窗口,所以需要在框架类窗口创建完成之后再去访问菜单对象。可以在框架类CMainFrame的OnCreate函数的最后(但一定要在return语句之前)添加实现这个功能的语句。

①标记菜单

       GetMenu()->GetSubMenu(0)->CheckMenuItem(ID_FILE_NEW,MF_BYCOMMAND |                                MF_UNCHECKED);

CWnd::GetMenu函数返回一个指向CMenu类对象的指针。

CMenu::GetSubMenu函数返回一个由索引指定的子菜单的CMenu指针。

CMenu::CheckMenuItem函数为菜单项添加一个标记,或者移除菜单项的标记。第一个参数指定需要处理的菜单项,它的取值取决于第二个参数的取值。

②默认菜单项

GetMenu()->GetSubMenu(0)->SetDefaultItem(1,TRUE);

CMenu::SetDefaultItem

BOOL SetDefaultItem( UINT uItem, BOOL fByPos = FALSE );

一个子菜单只能有一个默认菜单项。

③图形标记菜单

       m_bitmap.LoadBitmap(IDB_BITMAP1);

       GetMenu()->GetSubMenu(0)->SetMenuItemBitmaps(0,MF_BYPOSITION,&m_bitmap,&m_bitmap);

CMenu::SetMenuItemBitmaps

BOOL SetMenuItemBitmaps( UINT nPosition, UINT nFlags, const CBitmap* pBmpUnchecked, const CBitmap* pBmpChecked );

       图形标记菜单上显示的位图的尺寸有固定的标准,通过int GetSystemMetrics(int nIndex)函数可以得到位图的尺寸:

       int x=GetSystemMetrics(SM_XMENUCHECK); 

       int y=GetSystemMetrics(SM_CYMENUCHECK);      

④禁用菜单项

       GetMenu()->GetSubMenu(0)->EnableMenuItem(ID_FILE_NEW,MF_BYCOMMAND | MF_DISABLED);

       MFC为菜单提供了一种命令更新的机制,程序在运行时根据此机制去判断哪个菜单可以使用,哪个菜单不能够使用,然后显示其相应的状态。默认情况下所有菜单项的更新都是由MFC的命令更新机制完成的。如果想自己更改菜单项的状态,就必须把m_bAutoMenuEnable变量设置为FALSE,之后我们自己对菜单项的状态更新才能起作用。

⑤移除和装载菜单

CWnd:: BOOL SetMenu( CMenu* pMenu );

SetMenu(NULL); //移除菜单

 

CMenu menu;

menu.LoadMenu(IDR_MAINFRAME);

SetMenu(&menu);//装载菜单

menu.Detach();

在设置窗口菜单时,如果定义的是局部菜单对象,则一定要在调用SetMenu函数设置窗口菜单后立即调用菜单对象的Detach函数将菜单句柄与菜单对象分离。

CMenu:: HMENU Detach( );

Return Value:The handle, of type HMENU, to a Windows menu, if successful; otherwise NULL.

Remarks:Detaches a Windows menu from a CMenu object and returns the handle. The m_hMenu data member is set to NULL.

⑥MFC菜单命令更新机制

如果要在程序中设置某个菜单项的状态,首先通过ClassWizard为这个菜单项添加UPDATE_COMMAND_UI消息响应函数,然后在这个函数中进行状态的设置即可,如为“新建”菜单项添加UPDATE_COMMAND_UI消息响应函数:

       void CMainFrame::OnUpdateFileNew(CCmdUI* pCmdUI)

       {

              pCmdUI->Enable(FALSE); //使“新建”菜单项失效

       }

UPDATE_COMMAND_UI消息的响应只能应用于菜单项,不能应用于永久显示的顶级菜单,即弹出式菜单项目。

如果要把工具栏上的一个工具按钮与菜单栏中的某个菜单项相关联,只要将它们的ID设置为同一个标识就可以了。因为菜单项和工具按钮的位置索引计算方式不同,为了保持二者状态一致,最好采用菜单项标识或工具栏按钮标识的方式来进行设置。

⑦快捷菜单

插入快捷菜单:【Project】->【Add To Project】->【Components and Controls…】->Pop-up Menu;

插入快捷菜单之后添加了两处内容:

       第一处,在ResourceView选项卡的Menu分支下多了一个标识为CG_IDR_POPUP_MENU_VIEW的菜单资源,这个菜单只有一个顶层菜单项:_POPUP_,其下有Cut、Copy、Paste三个菜单项。

       第二处,为CMenuView类添加了一个函数:OnContextMenu。在程序运行时,当用鼠标右键单击窗口时,程序就会调用这个函数,该函数内部使用TrackPopupMenu函数来显示快捷菜单。

由此可以在鼠标右击响应函数中定义实现自己的快捷菜单:

void CMenuView::OnRButtonDown(UINT nFlags, CPoint point)

{

       // TODO: Add your message handler code here and/or call default

       CMenu menu;

       menu.LoadMenu(IDR_MENU1);

       CMenu *pPopup = menu.GetSubMenu(0);

       ClientToScreen(&point); //将一个坐标点或矩形区域坐标转换成屏幕坐标。

       pPopup->TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON,

              point.x, point.y,this);//在指定位置以指定的方式显示弹出菜单。

 

       CView::OnRButtonDown(nFlags, point);

}

对于快捷菜单,只有将其拥有者窗口设置为框架类窗口,框架类窗口才有机会获得对该快捷菜单中菜单项命令的响应,否则就只能由视类窗口做出响应。

4.动态菜单操作

①添加菜单项目

       CMenu menu; //创建一个菜单

       menu.CreatePopupMenu();   

       GetMenu()->AppendMenu(MF_POPUP,(UINT)menu.m_hMenu,"AppednMenu");

              //MF_POPUP创建一个弹出菜单,(UINT)menu.m_hMenu 是菜单句柄

       menu.Detach();      //将句柄与CMenu对象断开

②插入菜单项目

       GetMenu()->InsertMenu(2,MF_BYPOSITION|MF_POPUP,

              (UINT)menu.m_hMenu,"InsertMenu");       //插入一个子菜单

       menu.AppendMenu(MF_STRING,IDM_HELLO/*ID号*/,"Hello");

       menu.AppendMenu(MF_STRING,112,"Weixin");

       menu.Detach();     

       GetMenu()->GetSubMenu(0)->InsertMenu(ID_FILE_OPEN,

              MF_BYCOMMAND | MF_STRING,115,"维新(&p)    Ctrl+P");

              //在“文件->打开”之前插入一个叫“维新”的菜单项

③删除菜单

       GetMenu()->DeleteMenu(1,MF_BYPOSITION); //删除“编辑”子菜单

       GetMenu()->GetSubMenu(0)->DeleteMenu(ID_FILE_PRINT, MF_BYCOMMAND); //删除“文件->打印”

④动态添加的菜单项的命令响应

       在Header Files目录下的Resource.h文件中定义了当前程序使用的一些资源ID,可以手工为菜单项添加一个ID,然后遵照MFC消息映射机制,即需要添加三处代码来实现命令消息的响应。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值