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

VC++
WTL字体类
CTreeCtrl类的递归使用
类似EXCEL的报表类库
实现类似VC中可设断点的编辑窗口
一个实用的CToolBar扩展类CToolBarEx
VC学习笔记之一:怎样实现XP风格按钮
增强GridCtrl
支持数据项查找功能的树控制(CTreeCtrl)类
如何锁定 ListView 的栏目头宽度
带文字的进度条
三态选择树实现终结者
如何定制对话框系统菜单
让CButtonST 类支持鼠标掠过时发声
可以显示多行文字的工具条
利用钩子实现菜单阴影效果
动态真彩工具栏
可以替代系统记事本的程序
如何实现三态选择树
一个好用的DBGRID
告别图标失真的烦恼

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


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-10-30   浏览: 49 ::
收藏到网摘: 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,