当前位置: 首页 > 图文教程 > 开发语言 > VC++ > 完美实现真彩自绘菜单

VC++
在Dialog中使用Menu和Toolbar
如何定制对话框中的回车键
再谈 Windows 2000 “打开”文件对话框
Windows2000新型Open对话框的使用
Windows SDK 非模态对话框的消息处理
VC6中使用CHtmlView在对话框控制中显示HTML文件
Windows 2000 UI 新特点之四:其他类型的外壳扩展
Windows 2000 UI 新特点之二:自定义文件夹栏目
Windows 2000 UI 新特点之三:搜索管理器
Windows 2000 UI 新特点之一:信息条提示(Infotip)
数据库异步操作(ADODB)
VC++:小编谈自动注册数据源(DSN)
VC++:小编分享面向对象特征及其优点
VC++:VC++中Windows 3.x的协同多任务
VC++:小编浅谈VC++中的CRecordset类
VC++:小编浅谈ODBC概念,了解ODBC不在是难事
VC++:小编谈用ODBC创建表
VC++:小编浅谈用DAO创建表
VC++:浅析VC++中传统控件的控件通知消息
VC++:小编浅谈静态控件

VC++ 中的 完美实现真彩自绘菜单


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-10-30   浏览: 77 ::
收藏到网摘: n/a

完美实现真彩自绘菜单

作者:阿福(geforce_zf)

下载源代码

一、提出问题

  在VCKBASE上读到《自绘菜单的实现》[作者:querw]。应用的我自己的正在进行的工程后发现效果不错,可是有存在许多问题。整个类的设计方面存在很多缺陷(先天,后天的),存在的主要问题如下:

  1. 当应用在多文档界面(MDI)中的时候,无法对系统自动添加菜单和文档模板菜单进行自绘(比如无法对文件->最近文件(MRU)菜单项中的文件列表就是系统自动添加)。原因是类内部没有对CMainFrame::OnInitPopupMenu()消息进行处理的函数, 因此不具备修改系统自动添加菜单项的功能。(BCMENU有这功能,而且工作的不错)
  2. 作者提到的 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 0x%04X.\n",	lpMeasureItemStruct->itemID);	}	else	{	......	}	......} 
  3. 当菜单项中含有子菜单(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);} 
    菜单编辑器中没有分割条菜单的菜单



    原CMenuEx执行的模样