MFC菜单栏(CMenu)控件
1.設(shè)置菜單左邊顯示位圖和背景位圖
CMenu類(lèi)里要了解的函數(shù)
SetMenuItemBitmaps//設(shè)置菜單項(xiàng)左邊的位圖
函數(shù)定義:BOOL SetMenuItemBitmaps( UINT nPosition, UINT nFlags, const CBitmap* pBmpUnchecked, const CBitmap* pBmpChecked );
nPostion指明具體要設(shè)置的菜單項(xiàng),可以是菜單項(xiàng)索引,菜單項(xiàng)ID,具體由nFlags參數(shù)指明,為MF_BYPOSITION,則以菜單項(xiàng)索引指明,
為MF_BYCOMMAND則第一個(gè)參數(shù)nPosition是菜單項(xiàng)ID號(hào)。pBmpUnchecked未被檢測(cè)時(shí)顯示的位圖(正常時(shí)),pBmpChecked檢測(cè)時(shí)顯示的圖片(就是菜單項(xiàng)被打上勾時(shí)所顯示的圖片,跟CheckMenuItem函數(shù)有關(guān)聯(lián))
一個(gè)API函數(shù)SetMenuInfo,這個(gè)函數(shù)可以設(shè)置菜單重繪時(shí)選擇的填充畫(huà)刷類(lèi)型,該函數(shù)有兩個(gè)參數(shù),第一個(gè)是要設(shè)置的菜單句柄,第二個(gè)是一個(gè)MENUINFO結(jié)構(gòu)指針,我們只要了解這結(jié)構(gòu)里有一個(gè)成員hbrBack就行了,hbrBack是一個(gè)畫(huà)刷句柄,而菜單背景位圖就通過(guò)創(chuàng)建位圖畫(huà)刷來(lái)實(shí)現(xiàn)的。
好了,以上面的工程為例,引入三張位圖,ID號(hào)默認(rèn)不變,然后再引入一張位圖(菜單背景位圖,ID:IDB_MENUBACK),接著在對(duì)話(huà)框類(lèi)的OnInitDialog函數(shù)里添加如下語(yǔ)句:
CMenu *pMenu=GetMenu();//獲取對(duì)話(huà)框關(guān)聯(lián)菜單
?CMenu *pSubMenu=pMenu->GetSubMenu(0);//獲得子菜單(如果有)0表示索引,對(duì)應(yīng)“文件”菜單
?for(int i=0;i<3;i++)
?{
?????CBitmap bmp;
?????bmp.LoadBitmap(IDB_BITMAP1+i);
??pSubMenu->SetMenuItemBitmaps(i,MF_BYPOSITION,&bmp,&bmp);
??bmp.Detach();
?}
?CBitmap bmp;
?CBrush m_BKBrush;
?bmp.LoadBitmap(IDB_MENUBACK);
?m_BKBrush.CreatePatternBrush(&bmp);//創(chuàng)建位圖畫(huà)刷
?MENUINFO mnInfo;
?memset(&mnInfo,0,sizeof(MENUINFO));
?mnInfo.cbSize=sizeof(MENUINFO);
?mnInfo.fMask=MIM_BACKGROUND;
?mnInfo.hbrBack=m_BKBrush;
?::SetMenuInfo(pSubMenu->m_hMenu,&mnInfo);
????m_BKBrush.Detach();
運(yùn)行效果如下圖:
(PS:不知道大家有沒(méi)有碰到過(guò)這個(gè)問(wèn)題,MENUINFO結(jié)構(gòu)未定義,解決的方法是進(jìn)入文件選項(xiàng)卡(FileView),在Source??File文件下的StdAfx.cpp文件里的最前面部分添加這個(gè)語(yǔ)句:#define??WINVER 0x0501)
2.設(shè)計(jì)彈出式菜單
?CMenu類(lèi)里要了解的函數(shù):
TrackPopupMenu( UINT nFlags, int x, int y, CWnd* pWnd,LPCRECT lpRect = NULL );
該函數(shù)用于在界面顯示菜單,nFlags參數(shù)指明菜單顯示標(biāo)志,x,y用于確定菜單顯示基于的坐標(biāo)點(diǎn),pWnd是菜單相關(guān)聯(lián)的窗口。
在“MFC類(lèi)庫(kù)詳解”中有關(guān)參數(shù)nFlags的解釋如下:
指定屏幕位置標(biāo)志或鼠標(biāo)鍵標(biāo)志。
屏幕位置標(biāo)志可以為下列值之一: · TPM_CENTERALIGN 使彈出菜單在水平方向相對(duì)于x指定的坐標(biāo)居中。 · TPM_LEFTALIGN 放置彈出菜單,以便彈出菜單在由坐標(biāo)值x指定的位置左對(duì)齊。 · TPM_RIGHTALIGN 放置彈出菜單,以便彈出菜單在由坐標(biāo)值x指定的位置右對(duì)齊。?
鼠標(biāo)鍵標(biāo)志可以為下列值之一: · TPM_LEFTBUTTON 導(dǎo)致彈出菜單追蹤鼠標(biāo)左鍵。 · TPM_RIGHTBUTTON 導(dǎo)致彈出菜單追蹤鼠標(biāo)右鍵。
以上面工程為例,給對(duì)話(huà)框添加鼠標(biāo)右鍵抬起(WM_RBUTTONUP)消息處理函數(shù),在函數(shù)里添加如下代碼:
void CSeventhDlg::OnRButtonUp(UINT nFlags, CPoint point)
{
?// TODO: Add your message handler code here and/or call default
?CMenu *Menu=GetMenu();
?ClientToScreen(&point);//將窗口坐標(biāo)轉(zhuǎn)換成屏幕坐標(biāo)
?Menu->GetSubMenu(0)->TrackPopupMenu(
??TPM_LEFTBUTTON|TPM_VERTICAL,point.x,point.y,this);
?Menu->Detach();
?CDialog::OnRButtonUp(nFlags, point);
}
要注意的是,要在界面顯示的菜單,必須是一個(gè)彈出菜單,雖然Menu->TrackPopupMenu也可以顯示,但顯然不是想要的結(jié)果。
運(yùn)行效果:
3.動(dòng)態(tài)(純代碼)創(chuàng)建一個(gè)菜單
上面的例子,都是使用了菜單資源創(chuàng)建的菜單,這一次我們用代碼來(lái)創(chuàng)建菜單,其實(shí)本質(zhì)跟前面的用控件類(lèi)的Create函數(shù)創(chuàng)建一個(gè)控件一樣。只不過(guò)這里的“Create”函數(shù)是CreateMenu和CreatePopupMenu函數(shù)。
CMenu類(lèi)里要了解的函數(shù):
CreateMenu //創(chuàng)建一個(gè)主菜單,函數(shù)沒(méi)有參數(shù)
CreatePopupMenu//創(chuàng)建一個(gè)具有彈出屬性的菜單,函數(shù)沒(méi)有參數(shù)
AppendMenu//往一個(gè)菜單里添加菜單項(xiàng),或彈出式菜單
AppendMenu函數(shù)定義如下:
BOOL AppendMenu( UINT nFlags, UINT nIDNewItem = 0, LPCTSTR lpszNewItem = NULL );
nFlags參數(shù)常用取值如下:
?MF_STRING 表明添加的是一個(gè)不具有彈出屬性的菜單項(xiàng)。
MF_POPUP 添加的一個(gè)彈出菜單項(xiàng)
MF_SEPARATOR 添加的是一個(gè)菜單分隔條
MF_OWNERDRAW??表明對(duì)應(yīng)菜單具有自繪屬性
nIDNewItem參數(shù),如果添加的是一個(gè)不具有彈出屬性的菜單項(xiàng),那么該值就是菜單項(xiàng)ID號(hào),否則是彈出式菜單句柄,lpszNewItem是菜單項(xiàng)名稱(chēng)(菜單文本內(nèi)容)
好了,接著我們來(lái)動(dòng)態(tài)創(chuàng)建一個(gè)菜單,首先往對(duì)話(huà)框里添加一個(gè)按鈕控件,當(dāng)單擊這個(gè)按鈕時(shí),就創(chuàng)建菜單,響應(yīng)這個(gè)按鈕控件的單擊消息,消息處理函數(shù)里添加如下代碼:
CMenu Menu;
??Menu.CreateMenu();//創(chuàng)建一個(gè)主菜單
??CMenu popMenu;
??popMenu.CreatePopupMenu();//創(chuàng)建一個(gè)彈出式菜單
??popMenu.AppendMenu(MF_STRING,1001,"新建");//添加菜單項(xiàng)
??popMenu.AppendMenu(MF_STRING,1002,"打開(kāi)");
??popMenu.AppendMenu(MF_STRING,1003,"保存");
??Menu.AppendMenu(MF_POPUP,(UINT)popMenu.m_hMenu,"文件");//添加彈出菜單項(xiàng)
??SetMenu(&Menu);//關(guān)聯(lián)到窗口中
??Menu.Detach();
??popMenu.Detach();
4.更改菜單項(xiàng)大小(寬高),設(shè)置菜單文本字體大小
由于CMenu類(lèi)里并沒(méi)有提供設(shè)置菜單項(xiàng)大小以及字體大小的函數(shù),所以我們?nèi)绻獙?shí)現(xiàn)上述功能的話(huà),只能采取自繪的方法。
如果對(duì)CMenu類(lèi)的某些函數(shù)不了解的話(huà),可以參考"MFC 類(lèi)大全",這里就不講述了
首先從CMenu派生出一個(gè)子類(lèi)CNewMenu(類(lèi)的類(lèi)型為Generic Class),然后往這個(gè)類(lèi)添加三個(gè)成員函數(shù),MeasureItem(設(shè)置菜單寬高),
DrawItem(自繪菜單),ChangeMenuItem(修改菜單項(xiàng)類(lèi)型)
三個(gè)函數(shù)分別定義如下:
void CNewMenu::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
void CNewMenu::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
void CNewMenu::ChangeMenuItem(CMenu *pMenu)
其中MeasureItem和DrawItem是CMenu類(lèi)的虛函數(shù)。
各函數(shù)的代碼如下:
void CNewMenu::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
?lpMeasureItemStruct->itemHeight=25;//項(xiàng)高
?lpMeasureItemStruct->itemWidth=120;//項(xiàng)寬
}
void CNewMenu::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
?CRect rect=lpDrawItemStruct->rcItem;
?CDC dc;
?dc.Attach(lpDrawItemStruct->hDC);
?dc.FillSolidRect(rect,RGB(0,166,170));
?CFont Font;
?Font.CreatePointFont(125,"宋體");//創(chuàng)建字體
?dc.SelectObject(&Font);
?CString *pText=(CString *)lpDrawItemStruct->itemData;
?if(lpDrawItemStruct->itemState&ODS_SELECTED)
???dc.FillSolidRect(rect,RGB(80,89,202));//菜單被選中
?dc.SetTextColor(RGB(10,0,181));//設(shè)置文本顏色
?dc.DrawText(*pText,rect,DT_VCENTER|DT_LEFT|DT_SINGLELINE);
?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);//獲取菜單項(xiàng)ID號(hào)
?pMenu->GetMenuString(i,*pText,MF_BYPOSITION);//獲取菜單文本
//ModifyMenu函數(shù)最后一個(gè)參數(shù)對(duì)應(yīng)DRAWITEMSTRUCT結(jié)構(gòu)里的itemData變量
?pMenu->ModifyMenu(i,MF_OWNERDRAW|MF_BYPOSITION|MF_STRING,itemID,(LPSTR)pText);
??if(itemID==-1)//如果是一個(gè)彈出式菜單
?{
??ChangeMenuItem(pMenu->GetSubMenu(i));
?}
}??
}
必須讓每個(gè)菜單項(xiàng)具有MF_OWNERDRAW屬性,不然接不到WM_MEASUREITEM和WM_DRAWITEM消息,而且菜單項(xiàng)不具有MF_OWNERDRAW屬性, 即使接到消息,也無(wú)法自繪,所以上面的ChangeMenuItem函數(shù)就是用于修改菜單項(xiàng)屬性
WM_MEASUREITEM和WM_DRAWITEM消息不是直接發(fā)給菜單窗口的,會(huì)被父窗口給收到,所以得處理父窗口的WM_MEASUREITEM和WM_DRAWITEM消息,給話(huà)框類(lèi)添加這兩個(gè)消息處理函數(shù),兩個(gè)函數(shù)里的代碼分別如下:
void CFirstDlg::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
?// TODO: Add your message handler code here and/or call default
?????if(lpMeasureItemStruct->CtlType==ODT_MENU)//如果類(lèi)型是菜單
???????newMenu.MeasureItem(lpMeasureItemStruct);//調(diào)用CNewMenu類(lèi)的MeasureItem成員函數(shù)
???????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);
}
接著我們?cè)趯?duì)話(huà)類(lèi)添加一個(gè)成員變量:
CNewMenu newMenu; (記得要包含頭文件:"NewMenu.h"),然后在對(duì)話(huà)框類(lèi)的OnInitDialog函數(shù)添加如下代碼:
?newMenu.LoadMenu(IDR_MENU1);
?SetMenu(&newMenu);
?//只更改下主菜單下的第一項(xiàng),更改全部:newMenu.ChangeMenuItem(&newMenu);
?newMenu.ChangeMenuItem(newMenu.GetSubMenu(0));
IDR_MENU1是菜單資源的ID號(hào),可自行創(chuàng)建。好了,到了這里大功已經(jīng)告成了,點(diǎn)編譯運(yùn)行,效果如下:
跟自繪按鈕控件一樣,上面依然沒(méi)處理菜單的所有狀態(tài),如獲得焦點(diǎn),被核記,有無(wú)關(guān)聯(lián)圖片。也不處理菜單分隔條。。
如果想處理這些狀態(tài)的話(huà)。建議查看DRAWITEMSTRUCT結(jié)構(gòu)的itemState變量,這個(gè)成員指明菜單項(xiàng)的狀態(tài),
關(guān)聯(lián)圖片,就查看CMenu類(lèi)的函數(shù)。。。
原文:https://blog.csdn.net/lanmeng_smile/article/details/26285705?
?
總結(jié)
以上是生活随笔為你收集整理的MFC菜单栏(CMenu)控件的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 3D电视,你知道多少?
- 下一篇: MFC中 给按钮添加图片的方法