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

VC++
用VC++创建自定义向导程序
自定义 CRichEditCtrl 控件
Office 2000 风格的停泊、智能型菜单
黑客攻击手段之偷梁换柱
完善 CPopupText 类
让工具条显示256色图像
定制编辑框的上下文菜单
列表控件排序功能的实现
一个优秀的网格控件CGridCtrl
如何用代码动态添加控件
如何在编辑框中使用IAutoComplete接口
应用程序中添加“Coolbars”的简单方法
介绍一个有Toolbar功能的可重用类 CPopupText
在工具栏按钮上添加文本标签
类似Dreamweaver的颜色选择器
如何设置ListView控件的完全行(Full Row)选项
如何enable/disable菜单项
关于CEdit控件的透明 --作者:monsoon
动态菜单项、状态条提示、工具条提示问题
CAnimateCtrl::Open的使用问题

VC++ 中的 自绘菜单的实现


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

自绘菜单的实现

作者:querw
(北方工业大学 2000级计算机4班)

下载源代码

  在VCKBASE上读到《一种漂亮的自绘菜单》 [作者:郑恒 (lbird)]。应用到我的工程里后发现:文章中提到的效果能很好的实现。但是有一点不方便:需要映射 WM_DRAWITEM 和 WM_MEASUREITEM 消息才能实现自画功能。这对于一个基于对话框的工程或者仅仅需要弹出式菜单的工程来说很不方便。网上有一种很有名的自绘菜单 :BCMenu (http://www.rocscience.com/~corkum/BCMenu.html) (在附带工程中也有 BCMenu),在使用它的时候并不需要映射上述的两个消息就能实现自绘效果。这个问题让我觉得很困惑,MSDN也说明:MeasureItem() 和 DrawItem() 两个虚函数是由框架调用的 。并不用手工映射。可是若不映射上述的两个消息则显示不正常。(我查看了好多资料,直到现在还是不明白原因。呵呵:))既然 BCMenu 可以不用映射 WM_DRAWITEM 和 WM_MEASUREITEM 就能实现自画功能,那么它肯定经过了特殊处理。果然,BCMenu::LoadMenu()对整个菜单作了处理 。我注意到,如果菜单是弹出式的,那么不需要映射 WM_DRAWITEM 和 WM_MEASUREITEM 就能实现自画功能。于是我在CMenuEx::LoadMenu()中重新构建了整个菜单, 把所有的子菜单创建为弹出式的菜单使用API函数::CreatePopupMenu(),代码如下:

BOOL CMenuEx::LoadMenu(UINT uMenu){	//重新读入菜单,创建为popup菜单,才能自画(由框架调用MesureItem() 和 DrawItem()	HMENU hMenu = ::CreateMenu();	this->Attach(hMenu);	//临时菜单(使用CMenu的LoadMenu()函数读入菜单,并以之为蓝本构建新的菜单)	CMenu Menu;	UINT uID;	Menu.LoadMenu(uMenu);	for(int i = 0; i < (int)Menu.GetMenuItemCount(); i++)	{	uID = Menu.GetMenuItemID(i);	if(uID == 0)	//分隔符	{	::AppendMenu(hMenu,MF_SEPARATOR,0,NULL);	}	else if((int)uID == -1)	//弹出菜单(即子菜单)	{	CMenu *pSubMenu = Menu.GetSubMenu(i);	//创建子菜单	HMENU hSubMenu = ::CreatePopupMenu();	CString strPopup;	Menu.GetMenuString(i,strPopup,MF_BYPOSITION);	::InsertMenu(hMenu,	i,	MF_BYPOSITION | MF_POPUP | MF_STRING,	(UINT)hSubMenu,	strPopup);	//对子菜单递归调用ChangeMenuStyle(),把子菜单改为MF_OWNERDRAW风格	ChangeMenuStyle(pSubMenu,hSubMenu);	}	else	//正常的菜单项	{	CString strText;	Menu.GetMenuString(uID,strText,MF_BYCOMMAND);	AppendMenu(MF_STRING,uID,strText);	}	}	Menu.DestroyMenu();	//销毁临时菜单	return TRUE;}void CMenuEx::ChangeMenuStyle(CMenu *pMenu,HMENU hNewMenu){	//关联为CMenuEx(关联为CMenuEx后才能自动重画	//原因不明(CMenu封装的结果?)	CMenuEx *pNewMenu;	pNewMenu = new CMenuEx;	pNewMenu->Attach(hNewMenu);	m_SubMenuArr.Add(pNewMenu);	UINT uID;	int nItemCount = pMenu->GetMenuItemCount();	for(int i = 0; i < nItemCount; i++)	{	uID = pMenu->GetMenuItemID(i);	if(uID == 0)	//分隔符	{	::AppendMenu(hNewMenu,MF_SEPARATOR,0,NULL);	//pNewMenu->AppendMenu(MF_SEPARATOR,0,NULL);	CString strText;	MENUITEM *pMenuItem = new MENUITEM;	pMenuItem->uID = 0;	pMenuItem->uIndex = -1;	pMenuItem->uPositionImageLeft = -1;	pMenuItem->pImageList = &m_ImageList;	m_MenuItemArr.Add(pMenuItem);	::ModifyMenu(hNewMenu, i, MF_BYPOSITION | MF_OWNERDRAW, -1, (LPCTSTR)pMenuItem);	}	else if(uID == -1)	//弹出菜单(即子菜单)	{	CMenu *pSubMenu = pMenu->GetSubMenu(i);	HMENU hPopMenu = ::CreatePopupMenu();	CString strPopup;	pMenu->GetMenuString(i,strPopup,MF_BYPOSITION);	::InsertMenu(hNewMenu, i, MF_BYPOSITION | MF_POPUP, (UINT)hPopMenu, strPopup);	MENUITEM *pMenuItem = new MENUITEM;	pMenuItem->uID = -1;	pMenuItem->strText = strPopup;	pMenuItem->uIndex = -1;	pMenuItem->uPositionImageLeft = -1;	pMenuItem->pImageList = &m_ImageList;	m_MenuItemArr.Add(pMenuItem);	::ModifyMenu(hNewMenu, i, MF_BYPOSITION | MF_OWNERDRAW, -1, (LPCTSTR)pMenuItem);	ChangeMenuStyle(pSubMenu,hPopMenu);	}	else	//正常的菜单项	{	CString strText;	pMenu->GetMenuString(uID,strText,