理論
創建普通菜單步驟如下:
- 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即可。
- WM_INITMENU 消息,wParam :主菜單句柄, lParam : 0;這個消息是當一個菜單將要激活時發出。當用戶點擊菜單欄上的項或者 使用菜單鍵選擇 。這個消息允許應用程序在顯示之前修改菜單。可以在這時修改頂層菜單。
- 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. 如果你需要根據菜單項的選擇來改變窗口客戶區的內容,那么可以你可以使用這個消息。
- WM_INITMENUPOPUP: wParam: 彈出式菜單句柄; LOWORD(lParam):彈出式菜單索引; HIWORD(lParam):系統菜單為1,其他為0 ; 如果要在彈出式菜單顯示之前啟用或者禁用菜單項,那么這個消息就很重要。
- WM_COMMAND: LOWORD(wParam): 菜單id; HIWOED(wParam): 0 ; lParam: 0 ; 如果這個消息是由子窗口控制產生,如button產生則:LOWORD(wParam): 控制ID HIWORD(lParam): 通知碼 lParam: 子窗口句柄。如果這個消息是由子窗口或者快捷鍵產生,則通知碼為1,由菜單產生,通知碼為0。通過參數,可以區分這個消息的來源是來自於控件,快捷鍵還是菜單。
- 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; }