理論
創建普通菜單步驟如下:
- 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;
}
