|
完美实现真彩自绘菜单
作者:阿福(geforce_zf)
下载源代码 逆风者
一、提出问题
在VCKBASE上读到《自绘菜单的实现》[作者:querw]。应用的我自己的正在进行的工程后发现效果不错,可是有存在许多问题。整个类的设计方面存在很多缺陷(先天,后天的),存在的主要问题如下:
-
当应用在多文档界面(MDI)中的时候,无法对系统自动添加菜单和文档模板菜单进行自绘(比如无法对文件->最近文件(MRU)菜单项中的文件列表就是系统自动添加)。原因是类内部没有对CMainFrame::OnInitPopupMenu()消息进行处理的函数,
因此不具备修改系统自动添加菜单项的功能。(BCMENU有这功能,而且工作的不错)
- 作者提到的 BCMENU 不用映射 WM_DRAWITEM 和 WM_MEASUREITEM
两个消息就能实现自画功能,实际上是错误的。不映射这两个重要的消息,即使能自绘,也是有问题的,不信看图。
菜单编辑器中的模菜单样
使用BCMENU并且映射了这两个消息后的执行情况

使用BCMENU没有映射两个消息的执行情况

原作者分析的自绘的是因为把主菜单(top-level menu)的子菜单都加载成弹出菜单(popupmenu),是不正确的。真正的原因是因为MFC框架会自动调用CMenu的两个虚拟函数MeasureItem()和OnDrawItem()。
因此,当CMenuEx派生于CMenu,并且重写这两个虚拟函数以后。
1、MFC框架调用的GetMenu()->MeasureItem()就相当于调用了CMenuEx::MeasureItem(),从而实现自绘菜单控件尺寸的测量。
2、MFC框架调用GetMenu()->DrawItem()就相当于调用了CMenuEx::DrawItem()来实现自绘菜单控件的自绘操作(不懂??,这正是C 的虚拟的妙用,指向派生类对象的基类指针可以调用派生类的虚拟函数,多么伟大的发明,谁想出来的???)。与子菜单是否为弹出菜单(popupmenu)没有什么关系。以下是摘自WINCORE.CPP的一段程序,也就是WM_MEASUREITEM消息的默认流向的地方,相信大家会从中看出一些端倪。
void CWnd::OnMeasureItem(int /*nIDCtl*/, LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
if (lpMeasureItemStruct->CtlType == ODT_MENU)
{
......
// 如果没有主菜单
if (pThreadState->m_hTrackingWindow == m_hWnd)
{
......
}
else
{
// 如果有主菜单
pMenu = GetMenu(); // 找到窗体的主菜单,注意,pMenu的是CMenu* 类型
}
// 在当前菜单中寻找ID匹配的菜单项
pMenu = _AfxFindPopupMenuFromID(pMenu, lpMeasureItemStruct->itemID);
if (pMenu != NULL)
// 如果找到,就调用MeasureItem()
// 这就是所谓的基类指针指向派生类对象,可以调用派生类虚拟函数的情况了
pMenu->MeasureItem(lpMeasureItemStruct);
else
TRACE1("Warning: unknown WM_MEASUREITEM for menu item 0xX.\n",
lpMeasureItemStruct->itemID);
}
else
{
......
}
......
}
- 当菜单项中含有子菜单(submenu),而不含有分割条的时候,子菜单项的高度不可调。原因为原CMenuEx程序中将分割条的原COMMAND
ID(0)改为菜单项的COMMADN ID(-1), 以欺骗MFC框架调用CMenuEx::MeasureItem()来计算子菜单项(submenu)的高度。(很令我失望,这也是促使我自己动手重写该类的原因之一。不信看程序,看图)
摘录自原CMenuEx.cpp第546-560行
if(uID == 0) //分隔符
{
::AppendMenu(hNewMenu,MF_SEPARATOR,0,NULL);
......
// 注意,就是下面那个-1,把分割条的ID从0改到-1,
// 从而是MFC框架误以为找到了ID为-1的菜单项,并且测量了它的尺寸
// 而实际上ID为-1的菜单项是不可能被void CWnd::OnMeasureItem()找到的
::ModifyMenu(hNewMenu,i,MF_BYPOSITION | MF_OWNERDRAW,-1,(LPCTSTR)pMenuItem);
} 本文章更多内容:1 - 2 - 3 - 4 - 5 - 下一页>> |