改变菜单栏字体的大小

这两天在菜单栏,需要改变菜单栏字体的大小,但是CMenu类没有提供相应的方法,自己上网找了点,找到了两种方法,具体的使用情况还有待研究,先做点笔记吧

方法一:在MainFrame的OnCreate函数中增加如下代码

// start
	LOGFONT m_lf;  
	memset(&m_lf, 0, sizeof(LOGFONT));     

	m_lf.lfHeight = 26; 
	m_lf.lfWeight = 700;//设置字体为粗体(一般为400,粗体为700)

	_tcsncpy_s(m_lf.lfFaceName, LF_FACESIZE, _T("Arial"), 7); //字符拷贝函数,使用的如果是UNICODE编码,则采用wcscpy_s()函数,如果是多字节编码,则采用strcpy_s()函数 ,m_lf.lfFaceName设置字体名称
	m_wndMenuBar.SetMenuFont(&m_lf); 
	// end

或者这么写:

        LOGFONT logfont = {0};
	::SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &logfont, 0);
	logfont.lfHeight = 26;
	logfont.lfWeight = 700;
	afxGlobalData.SetMenuFont(&logfont, true);
这里似乎只能改变主窗口的菜单字体,并且主窗口其他地方的体统字体都会随之改变。那么如果在一个弹出对话框中,要改变其菜单的字体如何实现呢?请看方法二


方法二:

首先从CMenu派生出一个子类CNewMenu(利用向导建立新的MFC类时,选择基类时没有CMenu,而CMenu派生自CObject,所以可以先将CNewMenu派生自CObject,然后再声明和定义的地方将CObject改成CMenu),然后往这个类添加三个成员函数,MeasureItem(设置菜单宽高),
DrawItem(自绘菜单),ChangeMenuItem(修改菜单项类型)

三个函数分别定义如下:

void CNewMenu::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)

void CNewMenu::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)

void CNewMenu::ChangeMenuItem(CMenu *pMenu)

其中MeasureItem和DrawItem是CMenu类的虚函数。

各函数的代码如下:

void CNewMenu::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
 lpMeasureItemStruct->itemHeight=25;//项高
 lpMeasureItemStruct->itemWidth=120;//项宽
}


void CNewMenu::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{

	// TODO:  Add your code to draw the specified item
	CRect rect=lpDrawItemStruct->rcItem;//菜单项矩形区域
	CRect rectCheck=lpDrawItemStruct->rcItem;
	rectCheck.right = rectCheck.left + 25;//icon或checkmark的矩形区域
	CDC dc;
	dc.Attach(lpDrawItemStruct->hDC);
	dc.FillSolidRect(rect,/*RGB(255,255,255)*/dc.GetBkColor());//设置菜单项的文本背景色
	dc.DrawEdge(&rect, EDGE_ETCHED, BF_TOP);//绘制菜单项边界
	
	
	CFont Font;
	Font.CreatePointFont(125,"宋体");//创建字体
	dc.SelectObject(&Font);
	CString *pText=(CString *)lpDrawItemStruct->itemData;
	rect.left += 25;
	if(lpDrawItemStruct->itemState&ODS_SELECTED)
	{
		dc.FillSolidRect(rect,RGB(0,255,0));//设置菜单被选中时的背景色
	}
	dc.SetTextColor(RGB(10,0,181));//设置文本颜色
	dc.DrawText(*pText,rect,DT_VCENTER|DT_LEFT|DT_SINGLELINE);//绘制文字
	
	
	//通过菜单项ID来确定是否显示icon以及是否checked
	switch(lpDrawItemStruct->itemID)
	{
	case IDM_MENU21:
		//DrawMenuItemIcon(&dc,rectCheck,FALSE/*,IDB_BITMAP1*/);
		DrawCheckMark(&dc,rectCheck,TRUE);
		//DrawCheckMark(&dc,rectCheck,FALSE);
		break;
	case IDM_MENU22:
		DrawMenuItemIcon(&dc,rectCheck,TRUE,IDB_BITMAP1);
		//DrawCheckMark(&dc,rectCheck,TRUE);
		break;
	case IDM_MENU31:
		DrawMenuItemIcon(&dc,rectCheck,TRUE,IDB_BITMAP1);
		break;
	case IDM_MENU13:
		DrawMenuItemIcon(&dc,rectCheck,TRUE,IDB_BITMAP1);
		break;
	}
	dc.Detach();
}



void CNewMenu::ChangeMenuItem(CMenu * pMenu)
{
	int itemCount=pMenu->GetMenuItemCount();//获取弹出菜单项个数
	for(int i=0;i<itemCount;i++)
	{
		CString *pText=new CString;
		UINT itemID=pMenu->GetMenuItemID(i);//通过菜单项的编号位置获取菜单项ID号
		pMenu->GetMenuString(i,*pText,MF_BYPOSITION);//获取菜单文本

		//ModifyMenu函数最后一个参数对应DRAWITEMSTRUCT结构里的itemData变量
		pMenu->ModifyMenu(i,MF_OWNERDRAW|MF_BYPOSITION|MF_STRING,itemID,(LPSTR)pText);
		if(itemID==-1)//如果是一个弹出式菜单
		{
			ChangeMenuItem(pMenu->GetSubMenu(i));
		}
	}  
}

另外在类中添加两个绘制菜单项icon和checkMark的函数:

void CNewMenu::DrawMenuItemIcon(CDC * pDC, CRect rect, BOOL bSelected,UINT nIDBmpResource)
{
	//如果不绘制icon,则用背景色填充icon所在区域
	if(!bSelected)
	{
		CBrush MenuItemBKBrush;
		MenuItemBKBrush.CreateSysColorBrush(COLOR_BTNFACE);
		FillRect(pDC->GetSafeHdc(),&rect,(HBRUSH)MenuItemBKBrush);
		return;
	}

	CBitmap bmp;
	if (bmp.LoadBitmap(nIDBmpResource))
	{
		//获取位图属性

		BITMAP bmpInfo;
		bmp.GetBitmap(&bmpInfo);

		// 创建一个与当前DC兼容的内存DC

		CDC dcMemory;
		dcMemory.CreateCompatibleDC(pDC);

		// 将位图选入内存DC

		CBitmap* pOldBitmap = dcMemory.SelectObject(&bmp);

		//获取bmp图片绘制的适当位置
		int nX = rect.left + (rect.Width() - bmpInfo.bmWidth) / 2;
		int nY = rect.top + (rect.Height() - bmpInfo.bmHeight) / 2;

		// 将内存DC中的位图拷贝到当前DC进行显示

		pDC->BitBlt(nX ,nY , bmpInfo.bmWidth, bmpInfo.bmHeight, &dcMemory, 
			0, 0, SRCCOPY);

		//dcMemory.SelectObject(pOldBitmap);
		
	}
}


绘制菜单项前面那个√,可以自绘,也可以直接贴一张bmp图片
void CNewMenu::DrawCheckMark(CDC * pDC, CRect rect, BOOL bSelected)
{
	//这是自绘的方式,但是使用资源图片直接贴上去会更简单
	//if(!bSelected)
	//	return;
	//const int nCheckDots = 8;
	//CPoint pt1, pt2, pt3;	//3 point of the checkmark
	//pt1.x = 0;	// 5/18 of the rect width
	//pt1.y = 3;	
	//pt2.x = 2;
	//pt2.y = 5;
	//pt3.x = 7;
	//pt3.y = 0;

	//int xOff = (rect.Width()-nCheckDots)/2 + rect.left ;
	//int yOff = (rect.Height()-nCheckDots)/2 + rect.top;
	//pt1.Offset(xOff, yOff);
	//pt2.Offset(xOff, yOff);
	//pt3.Offset(xOff, yOff);

	//CPen	pen(PS_SOLID, 1, RGB(0, 0, 0));
	//CGdiObject *pOldPen = pDC->SelectObject(&pen);
	//pDC->MoveTo(pt1);
	//pDC->LineTo(pt2);
	//pDC->LineTo(pt3);
	//pt1.Offset(0, 1);
	//pt2.Offset(0, 1);
	//pt3.Offset(0, 1);
	//pDC->MoveTo(pt1);
	//pDC->LineTo(pt2);
	//pDC->LineTo(pt3);
	//pt1.Offset(0, 1);
	//pt2.Offset(0, 1);
	//pt3.Offset(0, 1);
	//pDC->MoveTo(pt1);
	//pDC->LineTo(pt2);
	//pDC->LineTo(pt3);
	//pDC->SelectObject(pOldPen);

	DrawMenuItemIcon(pDC,rect,bSelected,IDB_CHECKMARK);

}

必须让每个菜单项具有MF_OWNERDRAW属性,不然接不到WM_MEASUREITEM和WM_DRAWITEM消息,而且菜单项不具有MF_OWNERDRAW属性, 即使接到消息,也无法自绘,所以上面的ChangeMenuItem函数就是用于修改菜单项属性
WM_MEASUREITEM和WM_DRAWITEM消息不是直接发给菜单窗口的,会被父窗口给收到,所以得处理父窗口的WM_MEASUREITEM和WM_DRAWITEM消息,给话框类添加这两个消息处理函数,两个函数里的代码分别如下:

void CFirstDlg::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
 // TODO: Add your message handler code here and/or call default
     if(lpMeasureItemStruct->CtlType==ODT_MENU)//如果类型是菜单
       newMenu.MeasureItem(lpMeasureItemStruct);//调用CNewMenu类的MeasureItem成员函数
       else
    CDialog::OnMeasureItem(nIDCtl, lpMeasureItemStruct);
  
}

void CFirstDlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
{
 // TODO: Add your message handler code here and/or call default
 if(lpDrawItemStruct->CtlType==ODT_MENU)
  newMenu.DrawItem(lpDrawItemStruct);
 else
 CDialog::OnDrawItem(nIDCtl, lpDrawItemStruct);
}

接着我们在对话类添加一个成员变量:

CNewMenu newMenu; (记得要包含头文件:"NewMenu.h"),然后在对话框类的OnInitDialog函数添加如下代码:

        newMenu.LoadMenu(IDR_MENU1);
	SetMenu(&newMenu);
	//只更改下主菜单下的第一项,更改全部:newMenu.ChangeMenuItem(&newMenu);
	newMenu.ChangeMenuItem(newMenu.GetSubMenu(1));
	newMenu.CheckMenuItem(IDM_MENU12,MF_CHECKED);
	newMenu.ChangeMenuItem(newMenu.GetSubMenu(2));

现在可以运行了,但是还是存在一些问题,请看下图:


菜单名的大小并没有变,这个问题还有待研究

这里绘制菜单的文字和icon都是在类的DrawItem中完成的,由于刚刚接触MFC不久,还不知道怎么写好点的接口实现动态设置icon,希望得到大家的指点



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值