您的位置:逆风者 VC++ 正文
 添加时间:2007-09-01 原文发表:2007-08-31 人气:103 来源:vckbase.com

本文章共3396字,分2页,当前第1页,快速翻页:
 

自绘菜单的实现

作者: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,MF_BYCOMMAND);

			MENUITEM *pMenuItem = new MENUITEM;

			pMenuItem->uID = pMenu->GetMenuItemID(i);

			pMenu->GetMenuString(pMenuItem->uID,

			                     pMenuItem->strText,

			                     MF_BYCOMMAND);

			pMenuItem->uIndex = -1;

			pMenuItem->uPositionImageLeft = -1;

			pMenuItem->pImageList = &m_ImageList;

			m_MenuItemArr.Add(pMenuItem);



			UINT uState = pMenu->GetMenuState(i,MF_BYPOSITION);

			::AppendMenu(hNewMenu,

			             MF_OWNERDRAW | MF_BYCOMMAND | uState,

			             uID,

			             (LPCTSTR)pMenuItem);

		}

	}

}       
 
本文章更多内容1 - 2 - 下一页>>
相关文章

系统托盘编程完全指南(二)
魔法单词记忆——DAO访问ACCESS数据库
解析CE下浏览器源码
QQ界面的模拟实现(上)
MFC程序员的WTL指南: Part IV - 对话框与控
Pure C :.NET 下的泛型编程
轻松实现DES算法查看器
直接通过DAO读写Access文件
在资源文件中加入声音资源
监听以太网(三) Packet32数据结构说明
遍历搜索注册表
调试方法和技巧
模拟器和远程调试工具(一)
Windows2000下的Raw TCP/IP库
Win32串口编程
乱砍设计模式之一:STRATEGY模式———赵子
基于 ODBC 自动存储自动定期删除数据库记录
除虫随记
软件框架的利器、TangramMini组件应用教程一
深入浅出ShellExecute

相关评论


本文章所属分类:首页 VC++

  热门关键字: