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

VC++
用 auto_ptr 类模板帮助动态内存管理
走近 STL
一步一步学STL标准模板库
使用 <multimap> 库创建重复键关联容器
使用 <map> 库创建关联容器
用 vectors 改进内存的再分配
用函数模板实现和优化抽象操作
STL 字符串类与 UNICODE 及其它......
如何在Dll中导出STL类
再谈“在STL列表(Lists)中插入不同类型的对象”
使用::std::vector<>作为管理动态数组的优先选择
三种常见中文内码的转换方法
JNI 中文处理问题小结
构建 GB2312 汉字库的 unicode 码表
正则表达式简介
在非MFC程序中引用CString
UTF-8与GB2312之间的互换
宽字符标量L"xx"在VC6.0/7.0和GNU g++中的不同实现
用VC++设计语法编辑器
C语言中对时间和日期的处理

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


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