1. 程式人生 > >Windows c++介面開發初學(三)win32

Windows c++介面開發初學(三)win32

選單新增

選單新增有兩種方式,一種是利用程式碼建立選單資源,一種是利用資原始檔獲取資源。

1、程式碼建立

利用CreateMenu()、CreatePopupMenu()、GetSystemMenu()函式建立頂層選單、彈出式選單,獲取系統選單;
利用AppendMenu()、InsertMenuItem()、InsertMenu()函式插入選單項。

  • 各函式程式碼原型及說明如下:(建議直接戳連結看文件,還有示例程式碼)

    • Parameters
      This function has no parameters.

      Return Value
      Type: HMENU
      If the function succeeds, the return value is a handle to the newly created menu.
      If the function fails, the return value is NULL. To get extended error information, call GetLastError.

      Remarks
      Resources associated with a menu that is assigned to a window are freed automatically. If the menu is not assigned to a window, an application must free system resources associated with the menu before closing.
      An application frees menu resources by calling the DestroyMenu function.

    • Parameters


      This function has no parameters.
      Return Value
      Type: HMENU
      If the function succeeds, the return value is a handle to the newly created menu.
      If the function fails, the return value is NULL. To get extended error information, call GetLastError.
      Remarks
      The application can add the new menu to an existing menu, or it can display a shortcut menu by calling the TrackPopupMenuEx or TrackPopupMenu functions.
      Also remember to free the resources if not assgined to a window.

    • Parameters
      hWnd
      Type: HWND
      A handle to the window that will own a copy of the window menu.
      bRevert
      Type: BOOL
      The action to be taken. If this parameter is FALSE, GetSystemMenu returns a handle to the copy of the window menu currently in use. The copy is initially identical to the window menu, but it can be modified. If this parameter is TRUE, GetSystemMenu resets the window menu back to the default state. The previous window menu, if any, is destroyed.

      Return Value
      Type: HMENU
      If the bRevert parameter is FALSE, the return value is a handle to a copy of the window menu. If the bRevert parameter is TRUE, the return value is NULL.

      Remarks
      Any window that does not use the GetSystemMenu function to make its own copy of the window menu receives the standard window menu.
      The window menu initially contains items with various identifier values, such as SC_CLOSE, SC_MOVE, and SC_SIZE.
      Menu items on the window menu send WM_SYSCOMMAND messages.
      All predefined window menu items have identifier numbers greater than 0xF000. If an application adds commands to the window menu, it should use identifier numbers less than 0xF000.
      The system automatically grays items on the standard window menu, depending on the situation. The application can perform its own checking or graying by responding to the WM_INITMENU message that is sent before any menu is displayed.

    • 4、BOOL AppendMenu(
      HMENU hMenu,
      UINT uFlags,
      UINT_PTR uIDNewItem,
      LPCWSTR lpNewItem
      );

      Parameters
      hMenu
      Type: HMENU
      A handle to the menu bar, drop-down menu, submenu, or shortcut menu to be changed.
      uFlags
      Type: UINT
      Controls the appearance and behavior of the new menu item.
      uIDNewItem
      Type: UINT_PTR
      The identifier of the new menu item or, if the uFlags parameter is set to MF_POPUP, a handle to the drop-down menu or submenu.
      lpNewItem
      Type: LPCTSTR
      The content of the new menu item.

      Return Value
      Type: BOOL
      If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get extended error information, call GetLastError.

      Remarks
      The following groups of flags cannot be used together:
      MF_BITMAP, MF_STRING, and MF_OWNERDRAW
      MF_CHECKED and MF_UNCHECKED
      MF_DISABLED, MF_ENABLED, and MF_GRAYED
      MF_MENUBARBREAK and MF_MENUBREAK

    • Parameters
      hmenu
      TBD(To Be Determined ,什麼鬼…)
      item
      TBD
      fByPosition
      Type: BOOL
      Controls the meaning of uItem. If this parameter is FALSE, uItem is a menu item identifier. Otherwise, it is a menu item position.
      lpmi
      TBD

      Return Value
      Type: BOOL
      If the function succeeds, the return value is nonzero.
      If the function fails, the return value is zero. To get extended error information, use the GetLastError function.

      Remarks
      The application must call the DrawMenuBar function whenever a menu changes, whether the menu is in a displayed window.
      In order for keyboard accelerators to work with bitmap or owner-drawn menu items, the owner of the menu must process the WM_MENUCHAR message. See Owner-Drawn Menus and the WM_MENUCHAR Message for more information.

    • Parameters
      hMenu
      Type: HMENU
      A handle to the menu to be changed.
      uPosition
      Type: UINT
      The menu item before which the new menu item is to be inserted, as determined by the uFlags parameter.
      uFlags
      Type: UINT
      Controls the interpretation of the uPosition parameter and the content, appearance, and behavior of the new menu item.
      uIDNewItem
      Type: UINT_PTR
      The identifier of the new menu item or, if the uFlags parameter has the MF_POPUP flag set, a handle to the drop-down menu or submenu.
      lpNewItem
      Type: LPCTSTR
      The content of the new menu item. The interpretation of lpNewItem depends on whether the uFlags parameter includes the MF_BITMAP, MF_OWNERDRAW, or MF_STRING flag

      Return Value
      Type: BOOL
      If the function succeeds, the return value is nonzero.
      If the function fails, the return value is zero. To get extended error information, call GetLastError.

      Remarks
      The application must call the DrawMenuBar function whenever a menu changes, whether the menu is in a displayed window.
      The following groups of flags cannot be used together:
      MF_BYCOMMAND and MF_BYPOSITION
      MF_DISABLED, MF_ENABLED, and MF_GRAYED
      MF_BITMAP, MF_STRING, MF_OWNERDRAW, and MF_SEPARATOR
      MF_MENUBARBREAK and MF_MENUBREAK
      MF_CHECKED and MF_UNCHECKED

  • 一段建立彈出式選單的例子:

/*資源id*/
#define IDM_OPT1     301
#define IDM_OPT2     302

HMENU hRoot;//頂層選單控制代碼

void createMyMenu() {
    hRoot = CreateMenu();//建立頂層選單

    if (!hRoot) {
        printf("%s", "request for menu resource fail!");
        return;
    }

    HMENU pop1 = CreatePopupMenu();//建立彈出式選單
    AppendMenu(hRoot, MF_POPUP, (UINT_PTR)pop1, L"操作");//往頂層選單插入彈出式選單
    AppendMenu(pop1, MF_STRING, IDM_OPT1, L"操作1");//往彈出式選單插入選單項

    MENUITEMINFO menuInfo;
    menuInfo.cbSize = sizeof(MENUITEMINFO);
    menuInfo.cch = 100;
    menuInfo.dwItemData = NULL;
    menuInfo.dwTypeData = L"操作2";
    menuInfo.fMask = MIIM_ID | MIIM_STRING | MIIM_STATE;
    menuInfo.fState = MFS_ENABLED;
    menuInfo.fType = MIIM_STRING;
    menuInfo.wID = IDM_OPT2;

    InsertMenuItem(pop1, IDM_OPT2, FALSE, &menuInfo);//往彈出式選單插入選單項
    InsertMenu(pop1, ID_OPTION3, MF_BYCOMMAND | MF_STRING, ID_OPTION3, L"操作3");//往彈出式選單插入選單項
}

int CALLBACK WinMain(
    _In_ HINSTANCE hInstance,
    _In_ HINSTANCE hPrevInstance,
    _In_ LPSTR lpCmdLine,
    _In_ int nCmdShow
) {
    ...
    createMyMenu();
    ...
    HWND hWnd = CreateWindow(
        szWindowClass,
        szTitle,
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT,
        500, 300,
        NULL,
        hRoot, //選單資源
        hInstance,
        NULL
    );
    ...
}

執行效果如下:
這裡寫圖片描述

2、利用資原始檔新增選單

在vs2015中,點選選單欄中的檢視 – 其他視窗 – 資源檢視,開啟資源檢視視窗,
這裡寫圖片描述
然後右鍵點選你的專案,點選新增–資源,選中Menu,點選新建
這裡寫圖片描述
在彈出的視覺化選單視窗中建立你想要的選單:
這裡寫圖片描述
雙擊(或右鍵)選單項設定其屬性,可以在ID欄中更改其資源id為你想要的id名
這裡寫圖片描述
儲存,還可以在解決方案資源管理器中的標頭檔案看到”resource.h”一項,資原始檔中出現字尾名為.rc的檔案。
右鍵該rc檔案,點選檢視程式碼,可以看到建立的選單結構如下:
這裡寫圖片描述

這樣就建好了選單資源,而將選單新增到視窗有兩種方法
第一種方法是設計視窗類時, 直接指定給WNDCLASS結構的lpszMenuName成員,這樣做意味著,在呼叫CreateWindow函式建立視窗時,無論你是否為視窗指定選單,最終顯示的視窗上都會有選單,因為它是基於整個視窗類的。

wcex.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);

第二種是不設定為類級別的選單,而是在呼叫CreateWindow時指定給hMenu引數

HWND hWnd = CreateWindow(
        szWindowClass,
        szTitle,
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT,
        500, 300,
        NULL,
        LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MENU1)),
        hInstance,
        NULL
    );

這樣就設定好我們的選單了。

3、訊息響應

新增好選單後我們還想根據選擇選單的不同項做出不同的響應。如何獲取選單,如何知道選擇的選單項,再做出響應呢?
在WindowProc函式中,我們針對不同的訊息做出不同的響應,其實點選選單時也會有訊息,因此我們的訊息響應將在WindowProc中處理。
首先我們需要獲取選單:

HMENU hmenu = GetMenu(hwnd); // 獲取選單
HMENU hSubMenu = GetSubMenu(hmenu, 0); //獲取選單的第0個子選單

選單項傳送的是WM_COMMAND訊息,因此在訊息處理中加入對WM_COMMAND訊息的處理:

switch (uMsg)
    {
    case WM_COMMAND:
        ...
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
        break;
    }

在WM_COMMAND型別的訊息中,wParam的低位記錄了選單項的id,因此利用這個資訊就可以知道是選擇了哪個選單項:

case WM_COMMAND:    
        switch (LOWORD(wParam)) {
        case ID_OPTION1:
            MessageBox(hwnd, L"操作1", L"提示", MB_OK);
            break;
        case ID_OPTION2:
            MessageBox(hwnd, L"操作2", L"提示", MB_OK);
            break;
        case ID_OPTION3:
            MessageBox(hwnd, L"操作3", L"提示", MB_OK);
            break;
        default:
            break;
        }
        break;

還可以給選擇了的選單項新增已選擇的提示:

//圓點項
//四個引數分別表示選單控制代碼,選單項的選擇範圍的起始、終止,要判斷的選單項,以及引數的型別是id還是pos
CheckMenuRadioItem(hSubMenu, ID_OPTION1, ID_OPTION3, ID_OPTION1, MF_BYCOMMAND);

//勾選項
//三個引數分別表示選單控制代碼,要判斷的選單項,以及選中的表示方法
CheckMenuItem(hSubMenu, ID_OPTION1, MF_CHECKED);