您的位置:逆风者 VC++ 正文
 添加时间:2007-09-01 原文发表:2007-08-31 人气:142 来源:vckbase.com

本文章共7979字,分5页,当前第1页,快速翻页:
 

完美实现真彩自绘菜单

作者:阿福(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 0xX.\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);
    
    }         
     
    本文章更多内容1 - 2 - 3 - 4 - 5 - 下一页>>
相关文章

控件如何传递自定义struct
文件系统识别器
用 ATL ActiveX 绘制任意平面函数的曲线
软件框架的利器、TangramMini组件应用教程四
如何让一个打开的文档成为活动文档
消息值,托管字符串,扰乱代码及其它
修改一个完全颜色的CListCtrl类
编程之道
更新MFC中的视图,跟踪.NET Framework中的事
常用编码详解
VC 6.0 中如何使用 CRT 调试功能来检测内
软件开发专业相关的英文简历及其资源
定制调试诊断工具和实用程序——摆脱DLL“地
发掘 C# 特性赋予科学计算项目以威力
《系统飞狐》中获取系统信息的方法
使用 Http 在线自动升级程序
UTF-8与GB2312之间的互换
在VC中调用DirectShow全屏播放视频
案例研究:If-Trader 订单流程处理系统
介绍一个操作DHTML表格的C 对象

相关评论


本文章所属分类:首页 VC++

  热门关键字: