[Win32]Win32 SDK編程系列文章——菜單(快捷菜單)——動態加載


理論

創建普通菜單步驟如下:

  • 1)創建菜單 如:CreateMenu
  • 2)   添加菜單項 如:AppendMenu
  • 3)加載菜單         LoadMenu
  • 4)設置菜單到窗口 SetMenu
  • 5)處理菜單響應
  • 6)消除菜單 DestroyMenu

 

創建右鍵菜單的步驟如下:

  • 1)創建菜單 如:CreateMenu
  • 2)   添加菜單項 如:AppendMenu
  • 3)使用TrackPopupMenu加載菜單。
  • 4)處理菜單響應
  • 5)消除菜單 DestroyMenu

 

當然,如果你選擇在已有菜單上進行編輯的話,也是可以的,就省略了其中的一些步驟。本節的例子就是在已有的菜單里面添加自己定義的菜單項。對於右鍵菜單你也可以選擇已有的菜單中的一欄作為彈出菜單。
使用菜單后,要涉及清除的問題,和窗口相連的菜單句柄在窗口摧毀的時候會由Windows自動釋放,不需要手工釋放,但沒有和窗口相連的菜單就要由程序自己來釋放了,方法是使用DestroyMenu函數,比如沒有和窗口相連而僅用TrackPopupMenu彈出的菜單句柄。本例中,我們使用的是窗口關聯的菜單句柄,因此我們不需要調用DestroyMenu消除菜單資源。

菜單消息:當用戶選擇一個菜單項時,windwos通常向窗口過程發送幾個不同的消息。在大多數情況下,你的程序可以忽略大部分的消息,只需要把他們傳遞給DefWindowProc即可。

  1. WM_INITMENU 消息,wParam :主菜單句柄, lParam : 0;這個消息是當一個菜單將要激活時發出。當用戶點擊菜單欄上的項或者 使用菜單鍵選擇 。這個消息允許應用程序在顯示之前修改菜單。可以在這時修改頂層菜單。
  2. WM_MENUSELECT: LOWORD(wParam): 選中項:菜單id或者彈出式菜單句柄。HIWORD(wParam): 選擇標; lParam: 包含選中項的菜單句柄。當用戶選擇某個菜單項時,這個消息就會被發送到菜單所屬的窗口。   這個消息是一個菜單跟蹤消息,wParam告訴你當前選中的是菜單中的哪一項,wParam的高位字中的“選擇標志”可以是下列這些標志的組合: MF_GRAYED、MF_DISABLED、MF_CHECKED、MF_BITMAP、MF_POPUP、MF_HELP、MF_SYSMENU和 MF_MOUSESELECT.   如果你需要根據菜單項的選擇來改變窗口客戶區的內容,那么可以你可以使用這個消息。
  3. WM_INITMENUPOPUP: wParam:   彈出式菜單句柄;  LOWORD(lParam):彈出式菜單索引;   HIWORD(lParam):系統菜單為1,其他為0 ;   如果要在彈出式菜單顯示之前啟用或者禁用菜單項,那么這個消息就很重要。
  4. WM_COMMAND: LOWORD(wParam): 菜單id;       HIWOED(wParam): 0 ;     lParam:   0 ;  如果這個消息是由子窗口控制產生,如button產生則:LOWORD(wParam): 控制ID      HIWORD(lParam): 通知碼     lParam:     子窗口句柄。如果這個消息是由子窗口或者快捷鍵產生,則通知碼為1,由菜單產生,通知碼為0。通過參數,可以區分這個消息的來源是來自於控件,快捷鍵還是菜單。
  5. WM_SYSCOMMAND: 類似於WM_COMMAND消息,只是WM_SYSCOMMAND表示用戶從系統菜單中選擇一個啟動菜單項或者用戶選擇最大化,最小化,關閉按鈕。 LOWORD(wParam): 菜單id   HIWOED(wParam): 0        lParam:   0;如果消息是由按鼠標產生的,LOWORD(wParam)和HIWORD(lParam)將包含鼠標光標的位置x,y屏幕坐標。對於windows預先定義的系統菜單項,用wParam表示。 SC_CLOSE,SC_MAXIMIZE,SC_MINIMIZE,SC_MOVE等等。

 

對於已有菜單,我們可以使用GetSystemMenu,GetMenu ,GetSubMenu來獲取菜單句柄。當需要更改菜單時,可以使用下面的API進行更改。 AppendMenu, DeleteMenu,InsertMenu,ModifyMenu,RemoveMenu等等。

實例

資源:菜單和快捷鍵
/////////////////////////////////////////////////////////////////////////////
//
// Menu
IDM_MAIN MENU
BEGIN
    POPUP "文件(&F)"
    BEGIN
        MENUITEM "打開文件(&O)...",                 IDM_OPEN
        MENUITEM "關閉文件(&C)...",                 IDM_OPTION
        MENUITEM SEPARATOR
        MENUITEM "退出(&X)",                      IDM_EXIT
    END
    POPUP "查看(&V)"
    BEGIN
        MENUITEM "字體(&F)...\tAlt+F",            IDM_SETFONT
        MENUITEM "背景色(&B)...\tCtrl+Alt+B",      IDM_SETCOLOR
        MENUITEM SEPARATOR
        MENUITEM "被禁用的菜單項",                     IDM_INACT, INACTIVE
        MENUITEM "被灰化的菜單項",                     IDM_GRAY, GRAYED
        MENUITEM SEPARATOR
        MENUITEM "大圖標(&G)",                     IDM_BIG
        MENUITEM "小圖標(&M)",                     IDM_SMALL
        MENUITEM "列表(&L)",                      IDM_LIST
        MENUITEM "詳細資料(&D)",                    IDM_DETAIL
        MENUITEM SEPARATOR
        POPUP "工具欄(&T)"
        BEGIN
            MENUITEM "標准按鈕(&S)",                    IDM_TOOLBAR
            MENUITEM "文字標簽(&C)",                    IDM_TOOLBARTEXT
            MENUITEM "命令欄(&I)",                     IDM_INPUTBAR
        END
        MENUITEM "狀態欄(&U)",                     IDM_STATUSBAR
    END
    POPUP "幫助(&H)"
    BEGIN
        MENUITEM "幫助主題(&H)\tF1",                IDM_HELP
        MENUITEM SEPARATOR
        MENUITEM "關於(&A) ...",                  IDM_ABOUT
    END
END


/////////////////////////////////////////////////////////////////////////////
//
// Accelerator //加速鍵,在資源視圖中,添加快捷鍵資源
IDC_SDKPOPUPMENU ACCELERATORS
BEGIN
    "/",            IDM_ABOUT,              ASCII,  ALT, NOINVERT
    "?",            IDM_ABOUT,              ASCII,  ALT, NOINVERT
    VK_F1,          IDM_HELP,               VIRTKEY, NOINVERT
    "B",            IDM_SETCOLOR,           VIRTKEY, CONTROL, ALT, NOINVERT
    "F",            IDM_SETFONT,            VIRTKEY, ALT, NOINVERT
END
關鍵代碼
resouces.h
#define IDC_MYICON                      2
#define IDD_SDKPOPUPMENU_DIALOG         102
#define IDS_APP_TITLE                   103
#define IDD_ABOUTBOX                    103
#define IDI_SDKPOPUPMENU                107
#define IDI_SMALL                       108
#define IDC_SDKPOPUPMENU                109
#define IDR_MAINFRAME                   128
#define IDM_MAIN                        0x2000
#define IDA_MAIN                        0x2000
#define IDM_OPEN                        0x4101
#define IDM_OPTION                      0x4102
#define IDM_EXIT                        0x4103
#define IDM_SETFONT                     0x4201
#define IDM_SETCOLOR                    0x4202
#define IDM_INACT                       0x4203
#define IDM_GRAY                        0x4204
#define IDM_BIG                         0x4205
#define IDM_SMALL                       0x4206
#define IDM_LIST                        0x4207
#define IDM_DETAIL                      0x4208
#define IDM_TOOLBAR                     0x4209
#define IDM_TOOLBARTEXT                 0x4210
#define IDM_INPUTBAR                    0x4211
#define IDM_STATUSBAR                   0x4212
#define IDM_HELP                        0x4301
#define IDM_ABOUT                       0x4302 

TCHAR szClassName[] = L"Menu Example";
TCHAR szCaptionMain[] = L"menu";
TCHAR szMenuHelp[] = L"幫助主題(&H)";  
TCHAR szMenuAbout[] = L"關於本程序(&A)..."; 
HWND g_hWinMain;
HMENU g_hMenu;
HMENU g_hSubMenu;
void DisplayMenuItem(DWORD dwCommandID)
{
	TCHAR szBuffer[256] = {0};
	wsprintf(szBuffer, L"您選擇了菜單命令:%08x",dwCommandID);
	MessageBox(g_hWinMain,szBuffer, L"菜單選擇",MB_OK);
}  
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;

   hInst = hInstance; // 將實例句柄存儲在全局變量中 
   g_hMenu = LoadMenu(hInstance,MAKEINTRESOURCE(IDM_MAIN));//加載菜單資源,返回菜單句柄
   g_hSubMenu = GetSubMenu(g_hMenu,1); //獲取主菜單的第2個子菜單,用作快捷菜單
   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, g_hMenu, hInstance, NULL);//把菜單放到窗口中
   g_hWinMain=hWnd;
   if (!hWnd)
   {
      return FALSE;
   }
   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);
   return TRUE;
} 
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;
	PAINTSTRUCT ps;
	HDC hdc;
	POINT stPos;
	HMENU hSysMenu;
	switch (message)
	{
	case WM_CREATE:
		hSysMenu = GetSystemMenu(hWnd,FALSE);//獲取系統菜單句柄
		AppendMenu(hSysMenu,MF_SEPARATOR,0,NULL);//把分割線附加到系統菜單中
		AppendMenu(hSysMenu,0,IDM_HELP,szMenuHelp);//把菜單項help附加到系統菜單中
		AppendMenu(hSysMenu,0,IDM_ABOUT,szMenuAbout);//把菜單項about附加到系統菜單中
		break;
	case WM_COMMAND: //用戶菜單項命令的消息
		DisplayMenuItem(wParam);//顯示對話框
		//對於單項項的標識(單項,雙選)的標識
		if(LOWORD(wParam) == IDM_EXIT)
		{
			DestroyWindow(hWnd); 
		} 
		else if(LOWORD(wParam) >= IDM_TOOLBAR &&	LOWORD(wParam) <= IDM_STATUSBAR) //多選的  工具欄的:標准按鈕,命令欄,文字標簽   
		{
			UINT uState = GetMenuState(g_hMenu,LOWORD(wParam),MF_BYCOMMAND);
			if(uState == MF_CHECKED)
				uState = MF_UNCHECKED;
			else
				uState = MF_CHECKED;
			CheckMenuItem(g_hMenu,LOWORD(wParam),uState);//復選或撤銷指定菜單的菜單條目
		}
		else if(LOWORD(wParam) >= IDM_BIG && LOWORD(wParam) <= IDM_DETAIL)//單選的  大圖標,小圖標,列表,詳細資料
		{
			CheckMenuRadioItem(g_hMenu,IDM_BIG,IDM_DETAIL,LOWORD(wParam),MF_BYCOMMAND);//單選[IDM_BIG,IDM_DETAIL]中的一個
		}
		//CheckMenuItem,CheckMenuRadioItem分別用於改變菜單項的狀態。菜單項的狀態可以通過GetMenuState函數獲得。
		break;
	case WM_SYSCOMMAND://系統菜單項的命令消息
		if(LOWORD(wParam) == IDM_HELP || LOWORD(wParam) == IDM_ABOUT)//附加到系統菜單的help,about的菜單項
			DisplayMenuItem(wParam);
		else
			return DefWindowProc(hWnd,message,wParam,lParam);
		break;
	case WM_RBUTTONDOWN:
		GetCursorPos(&stPos);//獲取光標位置
		TrackPopupMenu(g_hSubMenu,TPM_LEFTALIGN,stPos.x,stPos.y,NULL,hWnd,NULL);//在指定位置顯示快捷菜單,並跟蹤菜單選項
		break; 
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps); 
		EndPaint(hWnd, &ps);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM