上一篇咱們學習了利用windows API建立工具欄和菜單欄,與上一篇緊密聯繫的就是菜單欄,菜單欄是一個大多數複雜一些的Windows應用程序不可或缺的部分。好比下圖就是Windows自帶的記事本的菜單欄:java
菜單通常都是在標題欄下,工具欄以上,經常叫主菜單或頂級菜單(top-level menu),頂級菜單可能還會有彈出菜單(popup menu)或子菜單(submenu)。彈出菜單還有被「選中」(checked)狀態,各菜單還有啓用、禁用狀態。程序員
每個菜單都有一個ID與之對應,當某個菜單被點擊是,程序在WM_COMMAND消息中把菜單ID傳給應該消息處理函數,就能知道哪一個菜單被按下。編程
菜單欄的建立最多見是利用VS的菜單資源編輯器,而後加載該資源。好比下面的代碼片斷在建立主窗體時使用了LoadMenu函數加載菜單資源編輯的菜單:windows
hMenu = LoadMenu(hInstance, MAKEINTRESOURCE(ID_MENU)); hWnd = CreateWindow(TEXT(「myclass」), TEXT(「mytitle」), WS_OVERLAPPENDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 400, 300, NULL, hMenu, hInstance, NULL);
另一種辦法是在處理WM_CREATE消息是調用SetMenu函數來設置菜單:微信
SetMenu(hWnd, hMenu);
本文一直秉承一個原則,就是採用API的方式來建立而不是資源。由於用API來建立雖然麻煩一點,可是更加獨立,好比若是不是用VS環境,那就可能沒有資源編輯了,要是把咱們的源程序在非VS的環境下編譯就能顯示出通用性和可移植性了。微信公衆平臺
菜單消息編輯器
當用戶選擇一個菜單時,會產生WM_INITMENU消息和WM_MENUSELECT,WM_INITMENU消息使得咱們有機會在菜單的選中以前作一些事情,而WM_MENUSELECT消息是在菜單被選中或者光標移到該菜單時被髮送,咱們能夠利用這個消息進行菜單選中時的處理。函數
WM_INITMENUPOPUP消息在一個彈出菜單顯示前發送,能夠用來修改一些菜單顯示。工具
最重要、最經常使用的就是上面咱們提到的WM_COMMAND消息,當菜單被點擊時就會產生這個消息。上面的消息對應的參數意義請參考MSDN。學習
菜單建立
菜單相關的API有好幾十個,咱們這裏只用一些經常使用的API函數,這幾個函數基本能夠完成菜單的基本功能,更多的菜單函數和功能的請參考MSDN。
函數CreateMenu能夠建立一個菜單,CreatePopupMenu建立一個下拉式或彈出是菜單。函數AppendMenu能夠追加一個菜單項,函數InsertMenu能夠插入一個菜單項,TrackPopupMenu函數將在指定的位置顯示一個彈出菜單。這幾個菜單原型以下:
HMENU CreateMenu(VOID); HMENU CreatePopupMenu(VOID); BOOL AppendMenu(HMENU hMenu, UINT uFlags, UINT_PTR uIDNewItem, LPCTSTR lpNewItem); BOOL InsertMenu(HMENU hMenu, UINT uPosition, UINT uFlags, PTR uIDNewItem, LPCTSTR lpNewItem); BOOL TrackPopupMenu(HMENU hMenu, UINT uFlags, int x, int y, int nReserved, HWND hWnd, HWND prcRect);
其實菜單的經常使用部分大都是用這幾個函數完成的,並不複雜。不說了,直接一邊上代碼一邊解釋更直接,咱們經過如下demo演示運用這幾個常見的函數來建立和使用菜單:
#include <windows.h> #define IDM_FILE_NEW 1001 #define IDM_FILE_OPEN 1002 #define IDM_FILE_SAVE 1003 #define IDM_EDIT_COPY 1004 #define IDM_EDIT_PASTE 1005 #define IDM_EDIT_HL 1006 #define IDM_VIEW_FULL 1007 #define IDM_VIEW_HALF 1008 #define IDM_VIEW_PART 1009 #define IDM_FILE_OPEN_SOLUTION 10021 #define IDM_FILE_OPEN_PROJECT 10022 static TCHAR szAppName[] = TEXT("Menubar"); static LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { HWND hWnd; MSG msg; WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szAppName; if (!RegisterClass(&wndclass)) { MessageBox (NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR); return 0; } hWnd = CreateWindow(szAppName, // window class name szAppName, // window caption WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position 400, // initial x size 300, // initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL); // creation parameters ShowWindow(hWnd, iCmdShow); UpdateWindow(hWnd); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } HMENU CreateMenuBar(void) { //總菜單 HMENU hMenu = CreateMenu(); //文件菜單 HMENU hFileMenu = CreateMenu(); AppendMenu(hFileMenu, MF_STRING, IDM_FILE_NEW, TEXT("&New")); AppendMenu(hFileMenu, MF_SEPARATOR, 0, NULL); //插入一條橫條,請看運行效果 AppendMenu(hFileMenu, MF_STRING, IDM_FILE_SAVE, TEXT("&Save")); AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hFileMenu, TEXT("File(&F)")); //文件的二級子菜單 HMENU hSubMenu = CreateMenu(); AppendMenu(hSubMenu, MF_STRING, IDM_FILE_OPEN_SOLUTION, TEXT("So&lution")); AppendMenu(hSubMenu, MF_STRING, IDM_FILE_OPEN_PROJECT, TEXT("Pro&ject")); //將該二級菜單插入到第二條的位置 InsertMenu(hFileMenu, 1, MF_BYPOSITION|MF_POPUP, (UINT_PTR)hSubMenu, TEXT("Open")); //編輯菜單 hFileMenu = CreateMenu(); AppendMenu(hFileMenu, MF_STRING, IDM_EDIT_COPY, TEXT("&Copy")); AppendMenu(hFileMenu, MF_STRING, IDM_EDIT_PASTE, TEXT("&Paste")); AppendMenu(hFileMenu, MF_SEPARATOR, 0, NULL); AppendMenu(hFileMenu, MF_STRING|MF_CHECKED, IDM_EDIT_HL, TEXT("&Update"));//增長一個check選項 AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hFileMenu, TEXT("Edit(&E)")); //縮放菜單 hFileMenu = CreateMenu(); AppendMenu(hFileMenu, MF_STRING, IDM_VIEW_HALF, TEXT("&Half")); AppendMenu(hFileMenu, MF_SEPARATOR, 0, NULL); //設置一個灰色不可選的菜單,該菜單能夠用EnableMenuItem函數修改可選狀態 AppendMenu(hFileMenu, MF_STRING|MF_GRAYED, IDM_VIEW_PART, TEXT("P&art")); AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hFileMenu, TEXT("Zoom(&Z)")); return hMenu; } static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hDC; PAINTSTRUCT ps; switch (message) { case WM_CREATE: { HMENU hMenu = CreateMenuBar(); SetMenu(hWnd, hMenu); //以上只是建立了菜單,須要設置 } return 0; case WM_RBUTTONUP: { POINT point; point.x = LOWORD(lParam); point.y = HIWORD(lParam); ClientToScreen(hWnd, &point); //這裏的座標是相對於屏幕的,須要轉換爲客戶座標 HMENU hSubMenu = GetSubMenu(GetMenu(hWnd), 0); //獲取菜單的第0個子菜單,用這個菜單來演示彈出菜單 TrackPopupMenu(hSubMenu, TPM_RIGHTBUTTON, point.x, point.y, 0, hWnd, NULL); } return 0; case WM_COMMAND: switch (LOWORD(wParam)) { case IDM_FILE_NEW: MessageBox(hWnd, TEXT("you click new file button"), TEXT("hint"), MB_OK); break; default: break; } return 0; case WM_PAINT: hDC = BeginPaint(hWnd, &ps); ; EndPaint(hWnd, &ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0 ; } return DefWindowProc (hWnd, message, wParam, lParam); }
本demo運行後點擊「文件」菜單以下:
點擊「編輯」菜單以下:
鼠標右鍵彈出快捷菜單:
文篇只演示了經常使用的菜單,其餘好比位圖菜單、非客戶區彈出菜單等更多內容有興趣在討論,也能夠參考MSDN的相關函數本身進行測試。本文的菜單欄編程結合上一篇的工具欄和狀態欄內容以及第二篇的建立經常使用控件部分,基本能夠完成窗口應用程序的界面編程了。固然再次強調,咱們這些都是基於Windows API函數完成的,可能不少人會說,我用MFC,資源編輯器,對話框下的控件面板、甚至VB、C#均可以很快編寫出這些界面。沒錯,可是隱藏在這些的下面仍是會回到咱們這些基本的API上。
更多經驗交流能夠加入Windows編程討論QQ羣:454398517。
關注微信公衆平臺:程序員互動聯盟(coder_online),你能夠第一時間獲取原創技術文章,和(java/C/C++/Android/Windows/Linux)技術大牛作朋友,在線交流編程經驗,獲取編程基礎知識,解決編程問題。程序員互動聯盟,開發人員本身的家。
轉載請註明出處http://www.coderonline.net/,謝謝合做!