使用MFC自绘菜单时遇到一个问题
2010-08-28 14:32
423 查看
最近在使用MFC自绘菜单时遇到一个问题:当菜单项都为Popup Menu 时,发现MFC不会调用自绘MeasureItem,
以至于我的菜单宽度不对,无法显示菜单项文字。
跟踪发现: 在wincore.cpp中的OnMeasureItem函数中调用的_AfxFindPopupMenuFromID有点问题。OnMeasureItem是自绘菜单弹出时向菜单父窗口发送的WM_MEASUREITEM消息的响应函数,而_AfxFindPopupMenuFromID是个递归查找子菜单的函数,如果AfxFindPopupMenuFromID找到子菜单MFC就会调用菜单的MeasureItem。(wincore.cpp在vc安装目录下atlmfc/src/mfc目录中)
_AfxFindPopupMenuFromID的代码如下:
AFX_STATIC CMenu* AFXAPI _AfxFindPopupMenuFromID(CMenu* pMenu, UINT nID)
{
ENSURE_VALID(pMenu);
// walk through all items, looking for ID match
UINT nItems = pMenu->GetMenuItemCount();
for (int iItem = 0; iItem < (int)nItems; iItem++)
{
CMenu* pPopup = pMenu->GetSubMenu(iItem);
if (pPopup != NULL)
{
if(pPopup->m_hMenu == (HMENU)(UINT_PTR)nID) {
pMenu = CMenu::FromHandlePermanent(pMenu->m_hMenu);
return pMenu;
}
// recurse to child popup
pPopup = _AfxFindPopupMenuFromID(pPopup, nID);
// check popups on this popup
if (pPopup != NULL)
return pPopup;
}
else if (pMenu->GetMenuItemID(iItem) == nID)
{
// it is a normal item inside our popup
pMenu = CMenu::FromHandlePermanent(pMenu->m_hMenu);
return pMenu;
}
}
// not found
return NULL;
}
可以看出这条函数只检查了pMenu的子菜单或菜单项而没有检查pMenu自身,所以当自绘菜单的菜单项只有子菜单就会导致查找不到菜单而不调用自绘菜单的MeasureItem函数。
修改方法: 可以在菜单的父窗口响应WM_MEASUREITEM消息,具体修改如下
CMenu* MyFindPopupMenuFromID(CMenu* pMenu, UINT nID)
{
ENSURE_VALID(pMenu);
// walk through all items, looking for ID match
UINT nItems = pMenu->GetMenuItemCount();
for (int iItem = 0; iItem < (int)nItems; iItem++)
{
CMenu* pPopup = pMenu->GetSubMenu(iItem);
if (pPopup != NULL)
{
if(pPopup->m_hMenu == (HMENU)(UINT_PTR)nID) {
pMenu = CMenu::FromHandlePermanent(pMenu->m_hMenu);
return pMenu;
}
// recurse to child popup
pPopup = MyFindPopupMenuFromID(pPopup, nID);
// check popups on this popup
if (pPopup != NULL)
return pPopup;
}
else if (pMenu->GetMenuItemID(iItem) == nID)
{
// it is a normal item inside our popup
pMenu = CMenu::FromHandlePermanent(pMenu->m_hMenu);
return pMenu;
}
if(pMenu->GetSafeHmenu() == nID)
{
pMenu = CMenu::FromHandlePermanent(pMenu->m_hMenu);
return pMenu;
}
}
// not found
return NULL;
}
void CMyWnd::OnMeasureItem(int /*nIDCtl*/, LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
if (lpMeasureItemStruct->CtlType == ODT_MENU)
{
ASSERT(lpMeasureItemStruct->CtlID == 0);
CMenu* pMenu=NULL;
_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
if (pThreadState->m_hTrackingWindow == m_hWnd)
{
// start from popup
pMenu = CMenu::FromHandle(pThreadState->m_hTrackingMenu);
}
else
{
// start from menubar
pMenu = GetMenu();
}
ENSURE(pMenu);
pMenu = MyFindPopupMenuFromID(pMenu, lpMeasureItemStruct->itemID);
if (pMenu != NULL)
{
pMenu->MeasureItem(lpMeasureItemStruct);
}
else
{
TRACE(traceAppMsg, 0, "Warning: unknown WM_MEASUREITEM for menu item 0x%04X. ",
lpMeasureItemStruct->itemID);
}
}
else
{
CWnd* pChild = GetDescendantWindow(lpMeasureItemStruct->CtlID, TRUE);
if (pChild != NULL && pChild->SendChildNotifyLastMsg())
return; // eaten by child
}
// not handled - do default
Default();
}
可以看出其实只在查找函数中多加了一个判断。至于为什么用HMENU和id比较,是因为如果是子菜单的话,id就是子菜单的句柄。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/yyan/archive/2007/10/15/1826601.aspx
以至于我的菜单宽度不对,无法显示菜单项文字。
跟踪发现: 在wincore.cpp中的OnMeasureItem函数中调用的_AfxFindPopupMenuFromID有点问题。OnMeasureItem是自绘菜单弹出时向菜单父窗口发送的WM_MEASUREITEM消息的响应函数,而_AfxFindPopupMenuFromID是个递归查找子菜单的函数,如果AfxFindPopupMenuFromID找到子菜单MFC就会调用菜单的MeasureItem。(wincore.cpp在vc安装目录下atlmfc/src/mfc目录中)
_AfxFindPopupMenuFromID的代码如下:
AFX_STATIC CMenu* AFXAPI _AfxFindPopupMenuFromID(CMenu* pMenu, UINT nID)
{
ENSURE_VALID(pMenu);
// walk through all items, looking for ID match
UINT nItems = pMenu->GetMenuItemCount();
for (int iItem = 0; iItem < (int)nItems; iItem++)
{
CMenu* pPopup = pMenu->GetSubMenu(iItem);
if (pPopup != NULL)
{
if(pPopup->m_hMenu == (HMENU)(UINT_PTR)nID) {
pMenu = CMenu::FromHandlePermanent(pMenu->m_hMenu);
return pMenu;
}
// recurse to child popup
pPopup = _AfxFindPopupMenuFromID(pPopup, nID);
// check popups on this popup
if (pPopup != NULL)
return pPopup;
}
else if (pMenu->GetMenuItemID(iItem) == nID)
{
// it is a normal item inside our popup
pMenu = CMenu::FromHandlePermanent(pMenu->m_hMenu);
return pMenu;
}
}
// not found
return NULL;
}
可以看出这条函数只检查了pMenu的子菜单或菜单项而没有检查pMenu自身,所以当自绘菜单的菜单项只有子菜单就会导致查找不到菜单而不调用自绘菜单的MeasureItem函数。
修改方法: 可以在菜单的父窗口响应WM_MEASUREITEM消息,具体修改如下
CMenu* MyFindPopupMenuFromID(CMenu* pMenu, UINT nID)
{
ENSURE_VALID(pMenu);
// walk through all items, looking for ID match
UINT nItems = pMenu->GetMenuItemCount();
for (int iItem = 0; iItem < (int)nItems; iItem++)
{
CMenu* pPopup = pMenu->GetSubMenu(iItem);
if (pPopup != NULL)
{
if(pPopup->m_hMenu == (HMENU)(UINT_PTR)nID) {
pMenu = CMenu::FromHandlePermanent(pMenu->m_hMenu);
return pMenu;
}
// recurse to child popup
pPopup = MyFindPopupMenuFromID(pPopup, nID);
// check popups on this popup
if (pPopup != NULL)
return pPopup;
}
else if (pMenu->GetMenuItemID(iItem) == nID)
{
// it is a normal item inside our popup
pMenu = CMenu::FromHandlePermanent(pMenu->m_hMenu);
return pMenu;
}
if(pMenu->GetSafeHmenu() == nID)
{
pMenu = CMenu::FromHandlePermanent(pMenu->m_hMenu);
return pMenu;
}
}
// not found
return NULL;
}
void CMyWnd::OnMeasureItem(int /*nIDCtl*/, LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
if (lpMeasureItemStruct->CtlType == ODT_MENU)
{
ASSERT(lpMeasureItemStruct->CtlID == 0);
CMenu* pMenu=NULL;
_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
if (pThreadState->m_hTrackingWindow == m_hWnd)
{
// start from popup
pMenu = CMenu::FromHandle(pThreadState->m_hTrackingMenu);
}
else
{
// start from menubar
pMenu = GetMenu();
}
ENSURE(pMenu);
pMenu = MyFindPopupMenuFromID(pMenu, lpMeasureItemStruct->itemID);
if (pMenu != NULL)
{
pMenu->MeasureItem(lpMeasureItemStruct);
}
else
{
TRACE(traceAppMsg, 0, "Warning: unknown WM_MEASUREITEM for menu item 0x%04X. ",
lpMeasureItemStruct->itemID);
}
}
else
{
CWnd* pChild = GetDescendantWindow(lpMeasureItemStruct->CtlID, TRUE);
if (pChild != NULL && pChild->SendChildNotifyLastMsg())
return; // eaten by child
}
// not handled - do default
Default();
}
可以看出其实只在查找函数中多加了一个判断。至于为什么用HMENU和id比较,是因为如果是子菜单的话,id就是子菜单的句柄。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/yyan/archive/2007/10/15/1826601.aspx
相关文章推荐
- 在MFC中使用OCX控件遇到的一个问题
- 这是我学习COM遇到的几个基本问题其解决 黄森堂(vcmfc)著 1.我用ATL生成一个组件对象,我在COM中使用IDD_IEncrypt,这个在哪里写义,是啥?GUID? 答:IDD_IEncry
- 经常遇到的一个问题是 MFC中开启多线程后 在非主线程中使用updata函数出现崩溃的情况。
- 今天使用VS2012遇到一个问题:"链接器工具错误 LNK2026 XXX模块对于 SAFESEH 映像是不安全的"
- 一个笨鸟在使用Eclipse导入Maven项目遇到的问题及解决方案
- saprk rdd使用中遇到的一个典型问题
- 使用Windows 7自带IIS(7.5)搭建FTP服务时遇到的一个奇怪问题
- cocos中使用tinyxml2遇到的一个小问题
- 使用 TestNG 创建一个数据驱动测试过程中遇到的问题
- 在 CakePHP 中使用 SimpleExcel 遇到的一个问题小记
- 使用mfc CWnd 自绘实现一个类似于QQ好友的一个控件
- 使用session时候,遇到的一个问题(请求解决方法)
- 使用Ant自动打包项目遇到的一个问题,备案!
- Chrome 下,重复使用 XMLHttpRequest进行Post数据时,遇到一个奇怪的问题
- 使用MFC CImage类绘制PNG图片时遇到的问题
- 使用MFC过程中遇到的问题以及解决方法(三)
- 使用PyCharm遇到的一个小问题及解决方案
- cordova插件file使用时遇到的一个平台相关的问题
- 使用xcopy遇到的一个问题
- 使用access时遇到的一个问题