当前位置: 首页 > 图文教程 > 开发语言 > 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   浏览: 103 ::
收藏到网摘: n/a

简简单单:三个函数实现框架菜单自绘

作者:无心_所爱


  在VCKBASE看到的自绘菜单都是派生出一个新类,其实不用这么麻烦,添加三个函数即可实现框架菜单自绘,方便简单,易于维护。
  在MFC中,如果菜单带有MF_OWNERDRAW标志,程序就会调用OnDrawItem和OnMeasureItem函数来绘制菜单。
下面就让我们来动手吧!首先在CMainFrame响应三个消息,分别是:

WM_DRAWITEM:绘制菜单的样式WM_MEASUREITEM:指定要绘制菜单的大小WM_INITMENU:把框架菜单全部改成带MF_OWNERDRAW标志

  下面我帖出这三个函数代码,你不想改的话,把这三个函数的代码复制你的程序,编译一下看看你的程序菜单是不是变得很漂亮:)

void CMainFrame::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct) {	LPMEASUREITEMSTRUCT& lpM=lpMeasureItemStruct; //起个别名,好用一点	if(lpM->CtlType==ODT_MENU){ //判断是不是菜单要自绘	if(lpM->itemID!=ID_SEPARATOR) //分别设定普通菜单和分隔栏的大小	{	lpM->itemHeight=20; //分隔栏大小	lpM->itemWidth=150;	}	else	{	lpM->itemHeight=1; //普通菜单大小	lpM->itemWidth=150;	}	}}void CMainFrame::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) {	LPDRAWITEMSTRUCT& lpD=lpDrawItemStruct; //起个别名,好用一点	//判断是不是菜单自绘,因为按钮也可以自绘	if(nIDCtl==0)	{	CDC* pDC=CDC::FromHandle(lpD->hDC); //得到菜单的设备指针,用来绘制菜单	pDC->SetBkMode(TRANSPARENT);	CMenu menu;	menu.Attach((HMENU)lpD->hwndItem); //得到框架菜单对象	CRect AllRgn(lpD->rcItem); //得到当前绘制的菜单选项项大小	CRect FrontRgn(AllRgn.left,AllRgn.top,20,AllRgn.bottom);	CBrush brushAll(RGB( 250,250,250 )); //初始化画刷	CBrush brushFront(RGB( 230,230,230 ));	CBrush brushSel(RGB(148,170,214 ));	CString strText;	menu.GetMenuString(lpD->itemID,strText,MF_BYCOMMAND); //得到当前绘制的菜单选项文本	if(lpD->itemID!=ID_SEPARATOR) //菜单和分隔栏分别绘制	{	if(lpD->itemAction & ODA_SELECT) //菜单选中时的样式	{	pDC->FillRect(AllRgn,&brushSel); //绘制	if(lpD->itemState &ODS_GRAYED)	//设定文本颜色(在最后才绘制出来)	pDC->SetTextColor(RGB(194,194,194));	else if(lpD->itemState & ODS_SELECTED)	pDC->SetTextColor(RGB(250,250,250));	}	//菜单非选中时的样式	if(!((lpD->itemAction & ODA_SELECT) && (lpD->itemState & ODS_SELECTED)))	{	pDC->FillRect(AllRgn,&brushAll); //绘制	pDC->FillRect(FrontRgn,&brushFront);	if(lpD->itemState & ODS_GRAYED)	pDC->SetTextColor(RGB(194,194,194 ));	else	pDC->SetTextColor(RGB(66,110,180 ));	}	}	else	pDC->FillRect(AllRgn,&brushFront); //绘制分隔栏	pDC->TextOut(AllRgn.left+30,AllRgn.top+5,strText); //打印出字体	menu.Detach();//分隔菜单句柄和对象(必要!)	}}void CMainFrame::OnInitMenu(CMenu* pMenu) {	CMenu *pSubMenu;	UINT nCount,nSubCount,nID;	CString strText;	nCount=pMenu->GetMenuItemCount();	for(UINT i=0;i<nCount;i++)	{	pSubMenu =pMenu->GetSubMenu(i);	nSubCount=pSubMenu->GetMenuItemCount();	for(UINT j=0;j<nSubCount;j++)	{	nID=pSubMenu->GetMenuItemID(j);	//将框架菜单所有菜单都添加MF_OWNERDRAW标志	pSubMenu->ModifyMenu(j,MF_BYPOSITION|MF_OWNERDRAW,nID);	pSubMenu->GetMenuString(j,strText,MF_BYPOSITION);	}	}}	
这样,你的程序就拥有了一个漂亮的菜单:) 这只是个初板而已。

建议改进:因为每次弹出菜单的时候都调用OnInitMenu,本来已改好的菜单就不必再改了,在OnInitMenu加一个全部变量标识菜单是否改好了,避免重复的修改菜单。那当然也可以在OnCreate中修改,不过你要确定你的菜单没有再添加新选项了。

缺点:不清楚为什么对"最近文件"那项不起作用,知道的还望告诉我一下。对子菜单的弹出菜单没有修改MF_OWNERDRAW,不过你可以增加一点代码遍历一下就OK了。这样一个简单菜单换肤就完成了,^_^
(参考了VCK的一些资料)

本文参考了 VCKBASE 的一些资料,以及 MSDN 库:只列出部分
void CMainFrame::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruc