CMenu

CMenu

 對於系統菜單,建立起來比較簡單,直接使用資源編輯器就能生成菜單,再經過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。在窗口類的OnCreate函數裏建立CMenu對象。若是是建立運用程序主框架窗口

  的話,也能夠在InitInstance()函數裏。

  2。聲明一個CMenu對象:CMenu MyMenu;

  3。調用MyMenu.CreateMenu()或MyMenu.LoadMenu()

  4。調用若干次MyMenu.AppendMenu()或MyMenu.InsertMenu(),每調用一次建立一

  個菜單項。

  5。調用MyMneu.SetMenu()將菜單Attach到窗口上。

  6。調用MyMenu.Detach()。

  例子:

  int CMyWnd::OnCreate( LPCREATESTRUCT lpCreateStruct )

  {

  {

  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::OnCreate( LPCREATESTRUCT lpCreateStruct )

  {

  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;

  而後在窗口類的構造函數裏(或OnCreate()函數裏)加上建立菜單的語句,再

  在析構函數里加上銷燬菜單的語句,最後在OnRButtonDown()函數里加上顯示菜單

  的語句。

  建立菜單時,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::OnRButtonDown(UINT nFlags, CPoint point)

  {

  RECT rect;

  GetWindowRect(&rect);

  //顯示菜單

  MyMenu2->TrackPopupMenu(TPM_RIGHTALIGN,point.x+rect.left,point.y+

  rect.top,this,NULL);

  }

  三。使用資源編輯器作好的菜單,只能作非POPUP類型菜單。

  若是使用資源的話,建立菜單確實很是簡單了,只須在窗口類的OnCreate()

  函數里加幾句話就好了:

  int CMyWnd::OnCreate( LPCREATESTRUCT lpCreateStruct )

  {

  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 經過框架來調用,用於決定當建立了擁有者菜單時的菜單維數
相關文章
相關標籤/搜索