MFC---上下文菜单(快捷菜单)管理器

在MFC中的app类的InitInstance函数中,我们会看到这样一个函数,InitContextMenuManager,从它的字面意义可以看出是“初始化上下文菜单管理器”。像这样,在初始化函数中调用了这个函数,那么MFC框架就会为你创建一个类型为CContextMenuManager的对象,另外我们也可以手动创建这个对象,但是如果手动创建,那么就不要在使用这个函数了,否则会出错,MFC中由这个对象来管理程序中的快捷菜单,当然,我们也可以使用win32的那种方法来实现快捷菜单的功能。那么MFC的一个优势就是使用面向对象的方法来管理程序中的各个对象,对于菜单,MFC也提供了一个对象来专门管理快捷菜单,首先来看看在由MFC向导生成的单文档程序中,对菜单管理器的使用。

当我们使用MFC向导生成一个单文档程序之后,我们在客户区点击右键,就有一个快捷菜单,如下:


由于我们没有添加命令响应,因此菜单上面的项目都是灰色的。现在来看看它是如何做到的,首先在app类的PreLoadState函数中有如下语句:

void CcontextmenuApp::PreLoadState()
{
BOOL bNameValid;
CString strName;
bNameValid = strName.LoadString(IDS_EDIT_MENU);
ASSERT(bNameValid);
GetContextMenuManager()->AddMenu(strName, IDR_POPUP_EDIT);
}

在这里GetContextMenuManager是app类的一个方法,但是这里要注意的是这个函数是CWinAppEx函数,在CWinApp类中没有,这个我们可以修改我们自己的app类的基类就可以了,但是使用VS2010这不是什么问题。GetContextMenuManager函数会返回CContextMenuManager类型的对象指针,然后调用AddMenu方法,就将一个菜单资源添加到了这个对象当中,那么这个对象指针由框架保存,为了我们方便使用,我们可以在我们的类中声明一个CContextMenuManager类型的对象指针,来保存对象的地址,这样我们在使用的时候比较方便。

在这里已经将菜单资源添加到了快捷菜单管理器中,现在我们就可以使用了,那么在什么时候应该弹出快捷菜单呢,有的人使用的鼠标右键按下或是右键弹起的时候,进行弹出响应。这样做也是可以达到效果的,但是在windows中,有一个消息,是专门用来处理快捷菜单的,那就是WM_CONTEXTMENU,那么这个消息也是在当 WM_RBUTTONUP 或是WM_NCRBUTTONUP(非客户区鼠标右键弹起)传递给默认窗口过程函数DefWindowProc时由默认窗口过程处理生成的。因此,这里我们就要注意,当我们自己处理了WM_RBUTTONUP之后,应该继续调用基类处理。否则,不会有WM_CONTEXTMENU消息生成,另外,还需要注意的一个是WM_RBUTTONUP的消息参数中传递的坐标是客户区坐标,而我们要使用的,应该是屏幕坐标,因此,需要做一个转换或是使用GetCursorPos来获取光标的位置。现在看由MFC框架生成的对快捷菜单的调用,它是在View类中处理的WM_CONTEXTMENU消息中处理的,如下:

oid CcontextmenuView::OnContextMenu(CWnd* /* pWnd */, CPoint point)
{
#ifndef SHARED_HANDLERS
theApp.GetContextMenuManager()->ShowPopupMenu(IDR_POPUP_EDIT, point.x, point.y, this, TRUE);
#endif
}

这样,当我们点击鼠标右键的时候,就会生成一个WM_CONTEXTMENU消息,这时候,我们响应快捷菜单弹出的消息,这里它就是是用快捷菜单管理器来弹出的快捷菜单,ShowPopuMenu就是CContextMenuManager类的成员函数。如果我们是使用win32的方法来实现快捷菜单,也可以在这里做出相应的处理,而不使用MFC提供的快捷菜单管理器。下面我们做一个自己的快捷菜单,来看看快捷菜单管理器的使用。

首先我们在资源编辑器中,插入自定义的菜单,如下:


现在回到App类的PreLoadState函数做,做出修改,加载我们自己定义的菜单,修改后如下:

void CcontextmenuApp::PreLoadState()
{
/*BOOL bNameValid;
CString strName;
bNameValid = strName.LoadString(IDS_EDIT_MENU);
ASSERT(bNameValid);
*/
GetContextMenuManager()->AddMenu(L"MYMENU"/*strName*/, IDR_MYMENU);
}

接着,我在View类的WM_CONTEXTMENU消息响应函数下,也做出修改,修改后如下:

void CcontextmenuView::OnContextMenu(CWnd* /* pWnd */, CPoint point)
{
#ifndef SHARED_HANDLERS
theApp.GetContextMenuManager()->ShowPopupMenu(IDR_MYMENU, point.x, point.y, this, TRUE);
#endif
}

现在可以运行一下,看看效果:


这样就实现了我们功能,我们看见菜单项目仍然是灰色,当我们为它们添加命令响应之后,那么就不会是灰色状态,以第一个菜单项目为例:


我在View类中做响应,如下:

void CcontextmenuView::OnMymenu32771()
{
// TODO: 在此添加命令处理程序代码
this->MessageBox(L"菜单项目一");
}

下面再次运行:

现在我们看见“菜单项目一”,由于添加了命令响应,现在已经不再是灰色了,我们点击响应一次:


在快捷菜单管理器其中,我们可以使用AddMenu添加多个菜单,但是同一个菜单不应多次添加。另外,如果是自己手动创建的快捷菜单管理器对象,那么在使用的时候,需要多点注意事项,例如,新菜单弹出来之后,是否应该自动关闭原来的那个快捷菜单,如果遇到问题,可以查阅msdn,获得解决方法。推荐使用由MFC的这个快捷菜单管理器来管理我们的快捷菜单,省去了使用win32弹出快捷菜单的很多步骤和资源回收的工作。更加安全可靠。

更多信息,参考MSDN,推荐大家用好MSDN,是我不懈的努力!^_^

推荐编程者访问网站:http://www.panshy.com 获取更多知识。

本文代码:http://download.csdn.net/detail/xinzhiyounizhiyouni/6793861

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值