转自:对话框中使用ON_UPDATE_COMMAND_UI更新菜单
从命令用户界面处理函数(Command UI handler)改变菜单状态(启用/禁用,选择/取消选
择,更改文字)在由对话框处理时没有正常工作。
在下拉菜单显示的时候, WM_INITMENUPOPUP消息被先发送以显示菜单项。MFC CFrameWn
d::OnInitMenuPopup 函数遍历菜单项并为每个菜单项调用更新命令处理函数(如果有的
话).菜单的外观被更新以反映它的状态(启用/禁用,选择/取消选择)
更新用户界面机制在基于对话框的应用程序中不能工作,因为CDialog没有OnInitMenuP
opup 处理函数,而使用CWnd's 默认处理函数,该函数没有为菜单项调用更新命令处理函
数。
适用下列步骤解决此问题
在消息映射中添加ON_WM_INITMENUPOPUP 项:
基本上是从CFrameWnd::OnInitMenuPopup(在WinFrm.cpp中)复制过来的):
设计上行为如此。
命令用户界面处理函数也被CWnd::OnCommand 调用以确认命令在传递之前没有被禁用。
这就是禁用的菜单项的命令处理没有被调用的原因(虽然没有以灰色显示(不可用))。
在这种情况下,菜单项没有被重画以反映菜单项的状态.这是Wincore.cpp 文件中的相关
代码:
//在传递命令之前,确定命令没有被禁用
重现此行为的步骤
使用应用程序向导建立一个基于对话框的应用程序
建立一个新的菜单资源,并且向其上添加文件和文件/退出菜单项。
在对话框的属性中设置对话框的菜单为上述菜单.
使用类向导为文件/退出菜单项添加一个UPDATE_COMMAND_UI处理并添加下列语句之一到
处理函数。
===================================================================================================void CAVCDlg::OnRButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
//定位鼠标的位置
CPoint m_pPoint; // A copy of the mouse position
m_pPoint = point;
ClientToScreen(&m_pPoint);// Convert the position to a screen position
CMenu m_rMenu;
m_rMenu.LoadMenu(IDR_MNUR );
CMenu* pMenu=m_rMenu.GetSubMenu(0);
//更新菜单状态
::SendMessage(this->m_hWnd,WM_INITMENUPOPUP,int(pMenu->m_hMenu),FALSE);
pMenu->TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON,m_pPoint.x,m_pPoint.y,this);
CDialog::OnRButtonUp(nFlags, point);
}
捕获WM_INITMENUPOPUP消息,在此函数更新菜单状态
void CAVCDlg::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu)
{
CDialog::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu);
// TODO: Add your message handler code here
if(nIndex) //
{
CDialog::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu);
return;
}
ASSERT(pPopupMenu);
pPopupMenu->EnableMenuItem(0,MF_BYPOSITION|MF_DISABLED|MF_GRAYED);
}
PS:
工作原理可以参考:CCmdUI工作原理及作用