動的なメニューバー

メニューの表示1 メニューの表示2

いままで、メニューバーのアイテムは、リソースファイルで定義していました。条件によってメニューを表示させたいときや、メニューをオーナードローしたいときは、CreateMenu()でメニューを作成する必要があります。

メニュー - インコのWindowsSDK で作成したソースを修正します。

流れ

関数: MyRegisterClass()

WNDCLASSEX構造体のlpszMenuNameメンバをNULLにします。
これにより、メニューバーが表示されなくなります。
リソースも、メニューに関する箇所を削除します。

WM_CREATE

1.CreateMenu()メニューを作成

HMENU CreateMenu(VOID);

2.CreatePopupMenu()ドロップダウンメニュー、サブメニュー、ショートカットメニューのいずれかを作成。メニューは初期状態では空です。

HMENU CreatePopupMenu(VOID);

3.メニューアイテムの情報を定義するMENUITEMINFO構造体をセット。
先に構造体を初期化しておきます。

typedef struct tagMENUITEMINFO {
    UINT    cbSize;        // 構造体のサイズ
    UINT    fMask;         // 取得または設定するメンバ
    UINT    fType;         // アイテムのタイプ
    UINT    fState;        // アイテムの状態
    UINT    wID;           // アイテムID
    HMENU   hSubMenu;      // サブメニューのハンドル
    HBITMAP hbmpChecked;   // チェック表示時のビットマップ
    HBITMAP hbmpUnchecked; // チェック非表示時のビットマップ
    ULONG_PTR dwItemData;  // 任意の32ビット値
    LPTSTR  dwTypeData;    // アイテムの内容
    UINT    cch;           // アイテムの文字列の長さ
    HBITMAP hbmpItem;      // ビットマップハンドル
} MENUITEMINFO, *LPMENUITEMINFO;

構造体メンバ 定数と解説
cbSize 構造体のサイズ
fMask 有効にするメンバ
MIIM_STATE fStateが有効
MIIM_ID wIDが有効
MIIM_SUBMENU hSubMenuが有効
MIIM_CHECKMARKS hbmpCheckedとhbmpUncheckedが有効
MIIM_DATA dwItemDataが有効
MIIM_STRING dwTypeDataが有効
MIIM_BITMAP hbmpItemが有効
MIIM_FTYPE fTypeが有効
fType メニュー項目の種類・配置
MFT_OWNERDRAW オーナードロー
MFT_RADIOCHECK チェックマークからラジオボタンにします。
・hbmpCheckedメンバが0(NULL)のときのみ
MFT_SEPARATOR セパレーター
fState メニューアイテムの状態
MFS_ENABLED
MFS_UNCHECKED
MFS_UNHILITE
通常表示
MFS_GLAYED
MFS_DISABLED
アイテムを灰色で表示し、選択不可にします。
MFS_CHECKED アイテムにチェックマークをつけます。
MFS_HILITE アイテムをハイライト表示
MFS_DEFAULT デフォルトアイテムに設定
・1つのメニューに対して1つまで
・太字で表示されます。
wID メニューアイテムID
hSubMenu サブメニューまたはドロップダウンメニューのハンドル
サブメニューを持たない場合は0(NULL)
hbmpChecked アイテムがチェックされたときにアイテムの隣に表示するビットマップのハンドル
0(NULL):ラジオボタンまたは、チェックマーク。
ラジオボタンかチェックマークかは、fStateメンバで、MFT_RADIOCHECKを指定するかどうかで切り替え。
hbmpUnchecked アイテムがチェックされていないときにアイテムの隣に表示するビットマップのハンドル
0(NULL):表示なし
dwItemData アイテムに関連付けられたアプリケーション定義の32ビット値
dwTypeData メニューアイテムの内容
cch アイテムのテキストを格納するバッファのサイズ
hbmpItem ビットマップのハンドル

4.InsertMenuItem()で、メニューの項目を追加

BOOL InsertMenuItem(
    HMENU hMenu,           // メニューのハンドル
    UINT uItem,            // メニュー項目または位置を指定
    BOOL fByPosition,      // uItemの種別
    LPCMENUITEMINFO lpmii  // MENUITEMINFO構造体へのポインタ
);

hMenu メニューのハンドル
uItem メニュー項目または位置を指定
この項目の前に新しい項目が挿入されます
fByPosition uItemの種別
TRUE : uItemは位置
FALSE : uItemはメニュー項目のID
lpmii MENUITEMINFO構造体へのポインタ

5.SetMenu()で、新しいメニューを指定されたウィンドウに割り当てます。

BOOL SetMenu(
    HWND  hWnd,    // ウィンドウハンドル
    HMENU hMenu    // メニューハンドル
);

ソースコードの入力

ソースコードは下記のように入れてください。

test.cpp
#include <windows.h>
#include "resource.h"

// グローバル変数:
HMENU hMenu;                              // メニューのハンドル
HMENU hSubMenu1;                          // メニューのハンドル
HMENU hSubMenu2;                          // メニューのハンドル

// このコード モジュールに含まれる関数の宣言を転送します:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR lpCmdLine,
                     int nCmdShow)
{
    MSG msg;
    MyRegisterClass(hInstance);

    // アプリケーションの初期化を実行します:
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }
    // メイン メッセージ ループ:
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return (int) msg.wParam;
}

//
//  関数: MyRegisterClass()
//
//  目的: ウィンドウ クラスを登録します。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEX wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = WndProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    wcex.hIcon = LoadIcon(NULL , IDI_APPLICATION);
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName = NULL;
    wcex.lpszClassName = TEXT("HP");
    wcex.hIconSm = LoadIcon(NULL , IDI_APPLICATION);

    return RegisterClassEx(&wcex);
}

//
//   関数: InitInstance(HINSTANCE, int)
//
//   目的: メイン ウィンドウを作成します。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;

   hWnd = CreateWindow(TEXT("HP"), TEXT("HP"), WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

//
//  関数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  目的:  メイン ウィンドウのメッセージを処理します。
//
//  WM_CREATE  - ウインドウ作成時の処理
//  WM_COMMAND - アプリケーション メニューの処理
//  WM_DESTROY - 中止メッセージを表示して戻る
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int wmId, wmEvent;
    MENUITEMINFO mi;

    switch (message)
    {
        case WM_CREATE:
            hMenu = CreateMenu();
            hSubMenu1 = CreatePopupMenu();
            hSubMenu2 = CreatePopupMenu();

            memset(&mi, 0, sizeof(MENUITEMINFO));
            mi.cbSize = sizeof(MENUITEMINFO);
            mi.fMask = MIIM_TYPE | MIIM_SUBMENU;
            mi.fType = MFT_STRING;
            mi.fState = MFS_ENABLED;
            mi.wID = 0;
            mi.hSubMenu = hSubMenu1;
            mi.dwTypeData = TEXT("ファイル(&F)");
            InsertMenuItem(hMenu, 0, TRUE, &mi);

            mi.wID = 1;
            mi.hSubMenu = hSubMenu2;
            mi.dwTypeData = TEXT("ヘルプ(&H)");
            InsertMenuItem(hMenu, 1, TRUE, &mi);

            // サブメニュー
            mi.fMask = MIIM_TYPE | MIIM_ID;
            mi.fType = MFT_STRING;
            mi.wID = IDM_EXIT;
            mi.dwTypeData = TEXT("アプリケーションの終了(&X)");
            InsertMenuItem(hSubMenu1, 0, TRUE, &mi);
            mi.wID = IDM_ABOUT;
            mi.dwTypeData = TEXT("バージョン情報(&A)...");
            InsertMenuItem(hSubMenu2, 0, TRUE, &mi);

            SetMenu(hWnd, hMenu);
            break;

        case WM_COMMAND:
            wmId = LOWORD(wParam);
            wmEvent = HIWORD(wParam);
            // 選択されたメニューの解析:
            switch (wmId)
            {
                case IDM_EXIT:
                    DestroyWindow(hWnd);
                    break;
                default:
                    return DefWindowProc(hWnd, message, wParam, lParam);
            }
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

上記の太線で示している箇所のみ追加です。

resource.h (変更なし)
#define IDM_ABOUT 104
#define IDM_EXIT 105
#define IDC_HP 109


test.rc リソースファイル

リソースファイルは中身を削除しました。