完美实现真彩自绘菜单 -电脑资料

电脑资料 时间:2019-01-01 我要投稿
【www.unjs.com - 电脑资料】

   

    完美实现真彩自绘菜单

   

    作者:阿福(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)没有什么关系,

    电脑资料

    完美实现真彩自绘菜单》(https://www.unjs.com)。以下是摘自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	{		......	}	......}

    当菜单项中含有子菜单(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执行的模样

       

最新文章