Win32創建菜單篇

一、知識準備:

菜單 ----- 每個菜單會有一個HMENU句柄
菜單項 ------ 每個菜單項會有一個ID號,可以根據這個ID執行不同的操作。

菜單一般分爲三種:系統菜單頂層菜單彈出菜單(右鍵菜單)
系統菜單: 程序左上角的圖標點擊鼠標左鍵、或者在標題欄點擊鼠標右鍵,出現的就是系統菜單。主要內容有:還原、移動、大小、最小化、最大化、關閉。
頂層菜單: 一般出現在程序左上角位置。
彈出菜單: 程序的窗口中點擊鼠標右鍵(必要的時候左鍵也可以)彈出的菜單,或者頂層菜單點擊後出現的菜單,都稱爲彈出式菜單(也稱爲右鍵菜單)。

菜單創建方式:
1.從資源中加載菜單。
2.自己通過API函數創建。


二、從資源中加載菜單

1.添加菜單資源

資源文件-----添加-----資源-----選擇Menu-----導入或新建-----加載成功(出現IDR_MENU1)
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

2.添加成功後,使用資源菜單

API函數:

  • 加載菜單資源:LoadMenu函數
// 加載菜單資源
  HMENU hmenu = LoadMenu(hInstance,MAKEINTRESOURCE(IDR_MENU1));

// 頂層菜單的創建方法1
  wc.lpszMenuName   = MAKEINTRESOURCEW(IDR_MENU1);
// 頂層菜單的創建 方法2
  hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, hmenu, hInstance, nullptr);

三、自己創建菜單

API函數:

  • 指定的菜單條、下拉式菜單、子菜單或快捷菜單的末尾追加一個新菜單項的函數:AppendMenu
    函數AppendMenu己被lnsertMenultem取代
BOOL AppendMenu(hMenu hMenu,// 將被修改的菜單條、下拉式菜單、子菜單、或快捷菜單的句柄。
                 UINT uFlags,  // 控制新菜單項的外觀和性能的標誌
                 UINT uIDNewltem,// 指定新菜單項的標識符,或者當uFlags設置爲MF_POPUP時,表示下拉式菜單或子菜單的句柄。
                 LPCTSTR lpNewltem); // 指定新菜單項的內容。如果第二個參數爲MF_BITMAP,此參數表含有位圖句柄;
                                     // 如果第二個參數爲MF_STRING,此參數表以`\O’結束的字符串的指針;
uFlags參數 說明
MF_BYCOMMAND 基於id
MF_BYPOSITION 基於下標
MF_BITMAP 將一個位圖用作菜單項。參數lpNewltem裏含有該位圖的句柄。
MF_CHECKED 在菜單項旁邊放置一個選取標記。如果應用程序提供一個選取標記,位圖(參見SetMenultemBitmaps),則將選取標記位圖放置在菜單項旁邊。
MF_DISABLED 使菜單項無效,使該項不能被選擇,但不使菜單項變灰。
MF_ENABLED 使菜單項有效,使該項能被選擇,並使其從變灰的狀態恢復。
MF_GRAYED 使菜單項無效並變灰,使其不能被選擇。
MF_MENUBARBREAK 對菜單條的功能同MF_MENUBREAK標誌。對下拉式菜單、子菜單或快捷菜單,新列和舊列被垂直線分開。
MF_MENUBREAK 將菜單項放置於新行(對菜單條),或新列(對下拉式菜單、子菜單或快捷菜單)且無分割列。
MF_OWNERDRAW 指定該菜單項爲自繪製菜單項。菜單第一次顯示前,擁有菜單的窗口接收一個WM_MEASUREITEM消息來得到菜單項的寬和高。然後,只要菜單項被修改,都將發送WM_DRAWITEM消息給菜單擁有者的窗口程序。
MF_POPUP 指定菜單打開一個下拉式菜單或子菜單。參數uIDNewltem下拉式菜單或子菜單的句柄。此標誌用來給菜單條、打開一個下拉式菜單或於菜單的菜單項、子菜單或快捷菜單加一個名字。
MF_SEPARATOR 畫一條水平區分線。此標誌只被下拉式菜單、子菜單或快捷菜單使用。此區分線不能被變灰、無效或加亮。參數IpNewltem和uIDNewltem無用。
MF_STRING 指定菜單項是一個正文字符串;參數lpNewltem指向該字符串。
MF_UNCHECKED 不放置選取標記在菜單項旁邊(缺省)。如果應用程序提供一個選取標記位圖(參見SetMenultemBitmaps),則將選取標記位圖放置在菜單項旁邊。

1.系統菜單

1、獲取系統菜單:

HMENU hmenu = GetSystemMenu( HWND hWnd, 
                             BOOL bRevert);    // FALSE獲取當前的系統菜單。                      
                         // TRUE恢復到默認的系統菜單,將刪除所有自己定義的系統菜單項。

2、添加系統菜單:

BOOL AppendMenuW( HMENU hMenu, 
                  UINT uFlags,    // 標誌,常用的MF_STRING(字符串),MF_SEPARATOR(分割線)
                  UINT_PTR uIDNewItem,    // 菜單ID
                  LPCWSTR lpNewItem);     // 菜單名字

3、刪除系統菜單:

BOOL DeleteMenu( HMENU hMenu, 
                 UINT uPosition,   // 菜單ID或者菜單position Index
                 UINT uFlags);  // 刪除標誌: MF_BYPOSITION —通過索引刪除
                                            MF_BYCOMMAND–通過菜單id方式刪除

4、獲取菜單總數:

int GetMenuItemCount(HMENU hMenu);   // 注意,分隔符也會作爲菜單項的

5、獲取position Index位置的菜單項ID:

UINT GetMenuItemID( HMENU hMenu, int nPos);  // 一般情況下,分隔符菜單的ID設置爲0

6、系統菜單的消息處理WM_SYSCOMMAND
系統菜單點擊以後產生的消息是WM_SYSCOMMAND,wParam中存放的是菜單ID。


2.頂層菜單(下拉式菜單)

1、創建頂層菜單
HMENU hmenu = CreateMenu();

2、添加頂層菜單項(添加在後面)水平方向
AppendMenu函數,同樣可以添加菜單項,同樣通過WM_COMMAND消息響應。

AppendMenu(hMenu, 0, 1, _T("打開(&O)"));  // 按住alt + O鍵可打開快捷鍵
AppendMenu(hMenu, MF_BYCOMMAND, 2, _T("複製"));  // MF_BYCOMMAND 基於id ;MF_BYPOSITION基於下標

3、插入菜單項

BOOL InsertMenu(HMENU hMenu,
                UINT uPosition, // 插入位置,注意:這裏可寫位置也可寫ID,必須和下面的uFlags配合使用,>MF_BYPOSITION或者MF_BYCOMMAND(默認是這個),會插入在該位置或該ID的前面。
                UINT uFlags, // 菜單項的標誌
                UINT_PTR uIDNewItem, // 菜單項目ID
                LPCWSTR lpNewItem); // 菜單項的字符串

另外一個插入菜單項的函數:InsertMenuItem

4、修改菜單項(ModifyMenu)

BOOL ModifyMenu(HMENU hMnu,
                UINT uPosition,   // 位置或ID,與下面的uFlags配合使用
                UINT uFlags,   // MF_STRING MF_BYPOSITION MF_BYCOMMAND等等
                UINT_PTR uIDNewItem,  // 修改後的ID
                LPCWSTR lpNewItem);   // 修改後的字符串

另外一個修改菜單項的函數:SetMenuItemInfoW

5、設置頂層菜單(顯示菜單)

BOOL WINAPI SetMenu(HWND hWnd, HMENU hMenu); 

一般在窗口的WM_CREATE中使用,讓頂層菜單顯示在窗口的頂層。

6、刷新菜單(菜單項修改後重新顯示)

BOOL WINAPI DrawMenuBar(HWND hWnd); 

添加或者刪除頂層菜單項以後,需要使用該函數及時地刷新菜單的顯示。

7、創建彈出式菜單並添加彈出式菜單的菜單項。
同上,使用CreatePopupMenu和AppendMenu、InsertMenu。

8、關聯頂層菜單和彈出式菜單。
還是使用AppendMenu,只不過參數有些不同。

AppendMenu(頂層菜單句柄,MF_POPUP,(UINT)彈出式菜單句柄,頂層菜單項字符串);

對於在彈出式菜單中再增加一個彈出式菜單,也是同樣的方法。

9、獲取菜單句柄

HMENU GetMenu(HWND hWnd); //獲取窗口的頂層菜單

10、獲取子菜單句柄

HMENU GetSubMenu(HMENU hMenu, int nPos); //獲取子菜單的句柄

11、菜單項的勾選 CheckMenuItem
在添加菜單項的時候,可以用 MF_STRING | MF_CHECKED | MF_UNCHECKED 來設置是否勾選。

DWORD CheckMenuItem(HMENU hMenu,UINT uIDCheckItem,UINT uCheck);
CheckMenuItem(hMenu, 1, MF_UNCHECKED|MF_BYCOMMAND ); //設置不勾選
CheckMenuItem(hMenu, 2, MF_CHECKED|MF_BYPOSITION ); // 設置勾選

12、菜單項可用不可用設置 EnableMenuItem
在初始化的時候,假如需要該菜單項不能被點擊,可以使用MF_STRING | MF_GRAYED設置爲灰色(不能點擊)。

EnableMenuItem(Hm, 3002, MF_ENABLED | MF_BYCOMMAND); //設置爲可以點擊
EnableMenuItem(Hm, 1, MF_DISABLED | MF_BYPOSITION); //設置爲不可點擊

13、菜單項前面加圖標

在正常的添加菜單項的後面再加上一句:
BOOL SetMenuItemBitmaps(HMENU hMenu,
                        UINT uPosition,  // 位置或者ID,配合uFlags使用
                        UINT uFlags,     // MF_BYPOSITION MF_BYCOMMAND
                        HBITMAP hBitmapUnchecked,   // 非選擇
                        HBITMAP hBitmapChecked);    // 選擇

這個適合在彈出式菜單


3.彈出菜單(右鍵菜單)

1、創建彈出式菜單

HMENU CreatePopupMenu();   // 返回創建彈出式菜單的菜單句柄

2、添加、刪除菜單項 ,同上面的系統菜單,AppendMenu,DeleteMenu。

AppendMenu(hMenu, MF_CHECKED, 5001, _T("新建"));   //添加菜單項
AppendMenu(hMenu, MF_POPUP, (UINT)hMenu1, _T("文件(&P)"));// MF_POPUP添加一個子菜單

3、銷燬彈出式菜單

BOOL DestroyMenu(HMENU hMenu); // 彈出式菜單是自己創建的,所以在不需要的時候,使用DestroyMenu銷燬菜單

4、顯示彈出式菜單(一般響應WM_RBUTTONDOWN)

BOOL TrackPopupMenu(HMENU hMenu,
                    UINT uFlags, //標誌,比如TPM_LEFTALIGN,菜單左邊在x的位置
                    int x,int y, //注意:屏幕座標x,y
                    int nReserved,
                    HWND hWnd,
                    RECT *prcRect); //用屏幕座標定義的一個矩形,如用戶在這個矩形的範圍內單擊,則彈出式菜單不會關閉。如單擊彈出式菜單之外的任何一個地方,則會關閉菜單。可以設爲NULL。該函數爲阻塞函數。

5、彈出式菜單的消息處理 WM_COMMAND
彈出式菜單點擊以後,發送消息WM_COMMAND,wParam保存菜單項ID。


效果圖:
在這裏插入圖片描述
部分代碼:

   HMENU hMenu = CreatePopupMenu();  // 創建一個彈出式菜單
   AppendMenu(hMenu, MF_CHECKED, 3001, _T("第一個菜單項"));   // 添加第一個菜單項,打勾的

   HMENU hMenu1 = CreateMenu();     // 創建子菜單1
   AppendMenu(hMenu1, MF_CHECKED, 5001, _T("菜單1.1(&A)"));  // 菜單1的第1個項
   AppendMenu(hMenu1, 0, 5002, _T("菜單1.2(&B)"));       // 菜單1的第2個項
   AppendMenu(hMenu1, 0, 5003, _T("菜單1.3"));            // 菜單1的第3個項
   AppendMenu(hMenu, MF_POPUP, (UINT)hMenu1, _T("子菜單2(&P)"));// MF_POPUP,將菜單1作爲彈出菜單的子菜單

   HMENU hMenu2 = CreateMenu();
   AppendMenu(hMenu2, MF_BYPOSITION | MF_CHECKED, 6001, _T("菜單2.1"));// 菜單2的第1個項
   AppendMenu(hMenu2, MF_BYPOSITION, 6002, _T("菜單2.2"));         // 菜單2的第2個項
   AppendMenu(hMenu2, MF_BYCOMMAND, 6003, _T("菜單2.3"));          // 菜單2的第3個項
   InsertMenu(hMenu2, 6003, MF_BYCOMMAND | MF_SEPARATOR, 6004, _T("-"));  // 一條水平區分線
   AppendMenu(hMenu, MF_POPUP, (UINT)hMenu2, _T("子菜單2(&E)"));// MF_POPUP,將菜單2作爲彈出菜單的子菜單

case WM_RBUTTONDOWN:
	{
		POINT pt;
		pt.x = LOWORD(lParam);
		pt.y = HIWORD(lParam);
		ClientToScreen(hWnd, &pt);  // 把客戶區座標轉換爲屏幕座標
		
		//彈出右鍵菜單
		TrackPopupMenu(hMenu,//哪一個菜單
			TPM_LEFTALIGN | TPM_TOPALIGN,//菜單風格,對齊方式
			pt.x, pt.y,//鼠標點擊的位置
			0,hWnd,nullptr);
	}
	break;

一個人一定要活出不一樣的自己,不管別人怎麼看待,你需要的是成爲自己的英雄!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章