對於系統菜單,建立起來比較簡單,直接使用資源編輯器就能生成菜單,再經過ClassWizard建立菜單命令函數。在個人資源中上傳了一個工程,實現了一個右鍵彈出貼圖菜單。結合這個工程,介紹動態建立菜單、建立彈出式菜單和重繪菜單。c++
首先介紹基礎知識:框架
1、CMenu類的成員函數:編輯器
1. CreateMenu()和CreatePopupMenu(),這兩個函數用來建立一個菜單實例,CreateMenu()建立的是普通的菜單實例,若是想建立彈出式菜單,就要用CreatePopupMenu()函數。ide
2. AppendMenu()向菜單中添加一個子項,這個函數有兩個主要的參數。第一個UINT nFlags,這個參數代表了該子項的屬性特徵,能夠這樣說,這個參數規定了菜單的樣式和功能。後面會詳細講這個參數所能使用的值。第二個參數UINT_PTR nIDNewItem,根據nFlags使用不一樣的設置,該參數將標明菜單的資源ID或在這個菜單中的索引號。第三個參數能夠省略,若是不省略,能夠傳入一個字符串,這個字符串將顯示在菜單中(由於我準備用突破錶示菜單項,因此個人工程中省略了這個參數)。函數
3. DrawItem(),這是一個虛函數,若是菜單設置成能夠自繪類型,則這個函數將在生成菜單、彈出菜單、選中菜單、點擊菜單等時由系統框架調用。所以,這個函數是一個頗有用的函數,它能夠幫你繪製出各類樣式的菜單。this
4. MeasureItem()也是一個虛函數,當菜單被建立的時候由系統框架調用。這個函數用來設置菜單的大小。spa
2、nFlags說明:指針
只有當nFlags設置成MF_OWNERDRAW的時候,系統框架纔會重繪菜單。htm
MF_CHECKED:命令旁顯示默認複選標誌對象
MF_UNCHECKED:清除命令旁的複選標誌
MF_DISABLED:禁止此菜單命令,可是不變灰顯示
MF_ENABLED:容許此菜單命令,恢復到正常狀態
MF_GRAYED:禁止此菜單命令,變灰顯示
MF_MENUBARBREAK:對於靜態菜單,放到新行;對於彈出菜單,放到新欄 中,欄間有分隔線
MF_MENUBREAK:對於靜態菜單,放到新行;對於彈出菜單,放到新欄,欄間霧分隔線
MF_OWNERDRAW:指定該命令是自畫式菜單命令
MF_POPUP:指定該菜單命令有一個關聯的彈出式菜單
MF_SEPARATOR:畫一條水平分隔線,只用於彈出式菜單
MF_STRING:指定此菜單命令是一個字符串
CMenu類從CObject類派生而來。爲何要使用CMenu類呢?AppWzard不是把菜 單作好了嗎?在資源編輯器上修改菜單不是很方便嗎?
感受學vc++稍微深刻一點好,至少要能搞清楚AppWizard在背後都幹了些什麼東西。
事實上mfc就是用CMenu類來生成菜單的。讓咱們就從CMenu開始吧。
CMenu生成的菜單有兩種:Popup類型和非Popup類型。這兩種方法裏又能夠分
成使用資源編輯器生成的菜單資源和不使用這個資源。對於非Popup類型的菜單,
必須在建立出來後把它張貼到某個窗口上,它纔會顯示出來,從而纔有用處。Po
pup的菜單卻不能張貼到窗口上。
說明以前,先定義幾個常量:
#define IDM_MENU0 0
#define IDM_MENU1 1
#define IDM_MENU2 2
#define IDM_MENU3 3
#define IDM_ITEM0 10
#define IDM_ITEM1 11
#define IDM_ITEM2 12
#define IDM_ITEM3 13
#define IDM_ITEM4 14
#define IDM_ITEM5 15
#define IDM_ITEM6 16
一。建立非Popup類型菜單,不使用資源。
(一)建立非下拉菜單。
1。在窗口類的On
的話,也能夠在InitInstance()函數裏。
2。聲明一個CMenu對象:CMenu MyMenu;
3。調用MyMenu.CreateMenu()或MyMenu.LoadMenu()
4。調用若干次MyMenu.AppendMenu()或MyMenu.InsertMenu(),每調用一次建立一
個菜單項。
5。調用MyMneu.SetMenu()將菜單Attach到窗口上。
6。調用MyMenu.Detach()。
例子:
int CMyWnd::On
{
{
CMenu MyMenu;
MyMenu.CreateMenu();
MyMenu.AppendMenu(MF_STRING,IDM_MENU0,"文件");
MyMenu.AppendMenu(MF_STRING,IDM_MENU1,"編輯");
MyMenu.AppendMenu(MF_STRING,IDM_MENU2,"查看");
MyMenu.AppendMenu(MF_STRING,IDM_MENU3,"幫助");
MyMenu.InsertMenu(IDM_MENU2,MF_BYCOMMAND,IDM_ITEM0,"有關");
this->SetMenu(&MyMenu);
MyMenu.Detach();
return 0;
}//各個函數的細節就不講解了,看聯機幫助是最好的。
這個方法是先把菜單建立好後再貼到窗口上去,而後用Detach()使菜單和My
Menu對象脫離關係,由於MyMenu對象立刻就要超出做用域了,這一步是必須的。
(二)建立下拉菜單,不使用資源。
這種菜單當鼠標移動到菜單條目上面點擊時不是去執行某段程序,而是彈出
一個下拉菜單。這須要用前面的方法建立兩個菜單。第一個是鼠標未點擊時看到
的那個菜單,另外一個就是扮演下拉菜單的菜單。例子:
int CMyWnd::On
{
CMenu MyMenu0,MyMenu1;
//下面這幾條建立下拉菜單
MyMenu1.CreateMenu();
MyMenu1.AppendMenu(MF_STRING,IDM_ITEM0,"拷貝");
MyMenu1.AppendMenu(MF_STRING,IDM_ITEM1,"剪切");
MyMenu1.AppendMenu(MF_STRING,IDM_ITEM2,"粘貼");
MyMenu1.AppendMenu(MF_SEPARATOR,IDM_ITEM3,"");
MyMenu1.AppendMenu(MF_STRING,IDM_ITEM4,"全選");
MyMenu1.AppendMenu(MF_SEPARATOR,IDM_ITEM5,"");
MyMenu1.AppendMenu(MF_STRING,IDM_ITEM6,"刪除");
//下面這兩條建立鼠標未點擊時看到的那個菜單
//其中第二句將下拉菜單張貼到第一個菜單上。
MyMenu0.CreateMenu();
MyMenu0.AppendMenu(MF_POPUP,(UINT)MyMenu1.m_hMenu,"編輯");
this->SetMenu(&MyMenu0);//將菜單張貼到窗口上
MyMenu0.Detach();//必須有
MyMenu1.Detach();//必須有
return 0;
}
二。建立Popup類型的菜單,也不用資源。
不少程序裏,只要用鼠標右鍵點一下窗口客戶區,就會在鼠標的位置彈出一
個菜單,這叫右鍵菜單。咱們能夠用CMenu類來製做。
製做這種菜單比製做第一類菜單稍微複雜點。首先要在窗口類里加個成員變
量:CMenu *MyMenu2;
而後在窗口類的構造函數裏(或On
在析構函數里加上銷燬菜單的語句,最後在On
的語句。
建立菜單時,CMenu類對象應該用new來分配。
例子:
CMyWnd::CMyWnd()
{
//CMyWnd是從CWnd派生來的。
//先把菜單建立起來。
MyMenu2=new CMenu;
MyMenu2->CreatePopupMenu();
MyMenu2->AppendMenu(MF_STRING,IDM_ITEM0,"拷貝");
MyMenu2->AppendMenu(MF_STRING,IDM_ITEM1,"剪切");
MyMenu2->AppendMenu(MF_STRING,IDM_ITEM2,"粘貼");
MyMenu2->AppendMenu(MF_SEPARATOR,IDM_ITEM3,"");
MyMenu2->AppendMenu(MF_STRING,IDM_ITEM4,"全選");
MyMenu2->AppendMenu(MF_SEPARATOR,IDM_ITEM3,"");
MyMenu2->AppendMenu(MF_STRING,IDM_ITEM5,"刪除");
}
CMyWnd::~CMyWnd()
{
MyMenu2->DestroyMenu();//銷燬菜單所佔用的系統資源
delete MyMenu2;//銷燬菜單類對象
}
void CMyWnd::On
{
RECT rect;
GetWindowRect(&rect);
//顯示菜單
MyMenu2->TrackPopupMenu(TPM_RIGHTALIGN,point.x+rect.left,point.y+
rect.top,this,NULL);
}
三。使用資源編輯器作好的菜單,只能作非POPUP類型菜單。
若是使用資源的話,建立菜單確實很是簡單了,只須在窗口類的On
函數里加幾句話就好了:
int CMyWnd::On
{
CMenu MyMenu3;
MyMenu3.LoadMenu(IDR_MENU1);//IDR_MENU1是你的菜單的資源ID。
this->SetMenu(&MyMenu3);
MyMenu3.Detach();
return 0;
}
CMenu類還有不少成員函數,使你能夠在運行中對菜單進行裁剪,好比加上幾
項或減去幾項等等,使用很是方便。你們能夠去看msdn。
若是要實驗以上的菜單建立方法的話,能夠用一個很是簡單的mfc程序來搞:
//這是一個很是簡單的mfc程序,必要的函數本身去加吧。
#include
class CMyApp : public CWinApp
{
public:
virtual BOOL InitInstance();
};
};
class CMyWnd : public CWnd
{
public:
DECLARE_MESSAGE_MAP()
};
CMyApp MyApp;
BEGIN_MESSAGE_MAP(CMyWnd,CWnd)
END_MESSAGE_MAP()
BOOL CMyApp::InitInstance()
{
RECT rect={30,30,400,300};
CMyWnd* pCWindow=new CMyWnd;
pCWindow->CreateEx
(
NULL,
AfxRegisterWndClass(NULL,0,(HBRUSH)::GetStockObject(WHITE_BRU
SH),0),
"實驗程序",
WS_OVERLAPPEDWINDOW,
rect,NULL,NULL,NULL
);
m_pMainWnd = pCWindow;
pCWindow->ShowWindow(m_nCmdShow);
pCWindow->UpdateWindow();
return TRUE;
CMenu類爲Windows HMENU的封裝類。它提供了成員函數以用於建立、追蹤、更新及銷燬菜單。
在本地的堆棧框架中建立一個CMenu對象,而後調用CMenu的成員函數來操縱所需的新菜單。接着,調用CWnd::SetMenu函數爲窗口設置菜單。而後當即調用CMenu對象的Detach成員函數。CWnd::SetMenu成員函數將窗口的菜單設置爲新菜單,這將致使在窗口刷新後將影響菜單的改變,同時也將菜單的擁有者傳遞給窗口。調用Detach函數將把HMENU從CMenu對象中分離出來,以便當本地的CMenu變量超出範圍後,CMenu對象的構造函數將不會銷燬再也不擁有的菜單。當窗口銷燬後,菜單自動銷燬。
能夠調用LoadMenuIndirect成員函數在內存中建立來自模板的菜單,不過經過調用LoadMenu建立的菜單更容易維護。而且這種菜單資源自己也能夠由菜單編輯器建立或修改。
#include <afxwin.h>
CMenu類的成員
數據成員
m_hMenu | 指定附加給CMenu對象的窗口菜單的句柄 |
構造函數
CMenu | 構造一個CMenu對象 |
初始化
Attach | 附加一個Windows菜單句柄給CMenu對象 |
Detach | 從CMenu對象中分離Windows菜單的句柄,並返回該句柄 |
FromHandle | 返回一個指向給定Windows菜單句柄的CMenu對象的指針 |
GetSafeHmenu | 返回由CMenu對象包含的m_hMenu值 |
DeleteTempMap | 刪除由FromHandle成員函數建立的全部臨時CMenu對象 |
CreateMenu | 建立一個空菜單,並將其附加給CMenu對象 |
CreatePopupMenu | 建立一個空的彈出菜單,並將其附加給CMenu對象 |
LoadMenu | 從可執行文件中裝載菜單資源,並將其附加給CMenu對象 |
LoadMenuIndirect | 從內存的菜單模板中裝載菜單,並將其附加給CMenu對象 |
DestroyMenu | 銷燬附加給CMenu對象的菜單,並釋放菜單佔用的內存 |
菜單操做
DeleteMenu | 從菜單中刪除指定的項。若是菜單項與彈出菜單相關聯,那麼將銷燬彈出菜單的句柄,並釋放它佔用的內存 |
TrackPopupMenu | 在指定的位置顯示浮動菜單,並跟蹤彈出菜單的選擇項 |
菜單項操做
AppendMenu | 在該菜單末尾添加新的菜單項 |
CheckMenuItem | 在彈出菜單的菜單項中放置或刪除檢測標記 |
CheckMenuRadioItem | 將單選鈕放置在菜單項以前,或從組中全部的其它菜單項中刪除單選鈕 |
SetDefaultItem | 爲指定的菜單設置缺省的菜單項 |
GetDefaultItem | 獲取指定的菜單缺省的菜單項 |
EnableMenuItem | 使菜單項有效、無效或變灰 |
GetMenuItemCount | 決定彈出菜單或頂層菜單的項數 |
GetMenuItemID | 獲取位於指定位置菜單項的菜單項標識 |
GetMenuState | 返回指定菜單項的狀態或彈出菜單的項數 |
GetMenuString | 獲取指定菜單項的標籤 |
GetMenuItemInfo | 獲取有關菜單項的信息 |
GetSubMenu | 獲取指向彈出菜單的指針 |
InsertMenu | 在指定位置插入新菜單項,並順次下移其它菜單項 |
ModifyMenu | 改變指定位置的已存在的菜單項 |
RemoveMenu | 從指定的菜單中刪除與彈出菜單相關聯的菜單項 |
SetMenuItemBitmaps | 將指定檢測標記的位圖與菜單項關聯 |
GetMenuCountextHelpID | 獲取與菜單關聯的幫助文本的ID號 |
SetMenuCountextHelpID | 設置與菜單關聯的幫助文本的ID號 |
可覆蓋的函數
DrawItem | 經過框架來調用,其發生於擁有者菜單的可視部分有所改變 |
MeasureItem | 經過框架來調用,用於決定當建立了擁有者菜單時的菜單維數 |