改变菜单栏字体的大小

来源:互联网 发布:广州大数据 平台 编辑:程序博客网 时间:2024/05/31 19:05

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

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

// startLOGFONT 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 itemCRect 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以及是否checkedswitch(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兼容的内存DCCDC dcMemory;dcMemory.CreateCompatibleDC(pDC);// 将位图选入内存DCCBitmap* 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);//CPenpen(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,希望得到大家的指点



0 0
原创粉丝点击