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

VC++
在类VC的界面实现中加入目录树
软件换肤技术在 BCB 中的实现
利用非模窗口生成MDI介面
报表输出轻松搞定
Windows 中不规则窗体的编程实现
解说Win32的窗口子类化
使用测试优先方法开发用户界面
一个简单的登录对话框的实现
一个简单的日记本程序
从资源中加载皮肤
一个在RichEdit中添加表情图象的类
ActiveSkin 4.3 软件换肤在VC中的实现
一种另类“关于(About)”对话框的动态显示方法
对话框打印预览及打印
关于如何换肤、子类化的解决方案
制作 MSN、QQ 的消息提示窗口
如何对 BCGControlBarPro 进行换肤
定制个性化的对话框窗口类
改变窗口中的光标形状
更新MFC中的视图,跟踪.NET Framework中的事件

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


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