今回作成するアプリケーションは、アイコンを付け、メニューの選択をできるようにし、メニューの上にマウスをのせると、 色が反転するようにします。
メニューのフォントと色は、Windowsの設定を取得します。
メニュー・オーナードロー1 - インコのWindowsSDK で作成したソースを修正します。
流れ
#define
_WIN32_WINNT
0x0501 を追加
これがないと、Windows XP、Windows 2000では、Windowsの設定から、メニューのフォントが取得できません。
これは、後で紹介するNONCLIENTMETRICS構造体が、Windows Vistaで追加されたためです。
WM_CREATE
1.NONCLIENTMETRICS構造体のサイズを取得し、NONCLIENTMETRICS構造体のメンバcbSizeにセット。
NONCLIENTMETRICS構造体は、メニューやタイトルバーに使われている情報を管理しています。
typedef struct tagNONCLIENTMETRICS { UINT cbSize; // 構造体のサイズ int iBorderWidth; // 境界線の幅 int iScrollWidth; // 垂直スクロールバーの幅 int iScrollHeight; // 水平スクロールバーの幅 int iCaptionWidth; // タイトルバーの幅 int iCaptionHeight; // タイトルバーの高さ LOGFONT lfCaptionFont; // タイトルバーのフォント int iSmCaptionWidth; // 小さいタイトルバーの幅 int iSmCaptionHeight; // 小さいタイトルバーの高さ LOGFONT lfSmCaptionFont; // 小さいタイトルバーのフォント int iMenuWidth; // メニューバーの幅 int iMenuHeight; // メニューバーの高さ LOGFONT lfMenuFont; // メニューバーのフォント LOGFONT lfStatusFont; // ステータスバーのフォント LOGFONT lfMessageFont; // メッセージボックスのフォント #if (WINVER >= 0x0600) // Windows Vista以降 int iPaddedBorderWidth; #endif } NONCLIENTMETRICS, *LPNONCLIENTMETRICS;
2.SystemParametersInfo()で、Windowsのシステム全体に関するパラメータを取得・設定する
必ず、先にNONCLIENTMETRICS構造体のメンバcbSizeに構造体のサイズをセットしてください。
3.NONCLIENTMETRICS構造体のメンバlfMenuFontから、メニューのフォントを取得。
4.GetSystemMetrics()で、システム設定や画面構成についての情報を取得。
int GetSystemMetrics( int nIndex );
nIndexに、SM_CXSMICONや、SM_CYSMICONを入れると、小さいアイコンの推奨サイズを取得できます。
5.LoadIcon()で、アイコンリソースをロード
6.GetSysColor()で、システムカラーを取得します。
DWORD GetSysColor( int nIndex // システムカラーのインデックス );
nIndex | 色を取得するディスプレイ要素を指定 | |
COLOR_SCROLLBAR | スクロールバーの軸の色 | |
COLOR_BACKGROUND COLOR_DESKTOP |
デスクトップの色 | |
COLOR_ACTIVECAPTION | アクティブウィンドウのタイトルバーの色 グラデーション有効の場合はアクティブウィンドウのタイトルバーの左側の色 |
|
COLOR_INACTIVECAPTION | 非アクティブウィンドウのタイトルバーの色 グラデーション有効の場合は非アクティブウィンドウのタイトルバーの左側の色 |
|
COLOR_MENU | メニューの背景色 | |
COLOR_WINDOW | ウィンドウの背景色 | |
COLOR_WINDOWFRAME | ウィンドウの枠の色 | |
COLOR_MENUTEXT | メニュー内のテキストの色 | |
COLOR_WINDOWTEXT | ウィンドウ内のテキストの色 | |
COLOR_CAPTIONTEXT | アクティブウィンドウのタイトルバーのテキストの色 | |
COLOR_ACTIVEBORDER | アクティブウィンドウの境界の色 | |
COLOR_INACTIVEBORDER | 非アクティブウィンドウの境界色 | |
COLOR_APPWORKSPACE | MDI(マルチドキュメントインターフェイス)アプリケーションの背景色 | |
COLOR_HIGHLIGHT | コントロール内における選択された項目の色 | |
COLOR_HIGHLIGHTTEXT | コントロール内における選択された項目のテキストの色 | |
COLOR_BTNFACE COLOR_3DFACE |
3Dオブジェクトの表面色 | |
COLOR_BTNSHADOW COLOR_3DSHADOW |
3Dオブジェクトの影の色 | |
COLOR_GRAYTEXT | 無効状態のテキストの色 | |
COLOR_BTNTEXT | プッシュボタンのテキストの色 | |
COLOR_INACTIVECAPTIONTEXT | 非アクティブウィンドウのタイトルバーのテキストの色 | |
COLOR_BTNHIGHLIGHT COLOR_3DHIGHLIGHT COLOR_3DHILIGHT COLOR_BTNHILIGHT |
3Dオブジェクトの最も明るい色 | |
COLOR_3DDKSHADOW | 3Dオブジェクトの暗い影の色 | |
COLOR_3DLIGHT | 3Dオブジェクトの明るい色 | |
COLOR_INFOTEXT | ツールチップコントロールのテキストの色 | |
COLOR_INFOBK | ツールチップコントロールの背景色 |
WM_MEASUREITEM
WM_DRAWITEM
1.CreateFontIndirect()で、フォントハンドルにセット
2.SelectObject()で、指定されたデバイスコンテキストのオブジェクトを選択。
WM_DRAWITEM
3.LPDRAWITEMSTRUCT構造体の、itemDataメンバが指定するコントロールの項目 が、ODS_SELECTED(項目が選択状態のとき)のビットが立っているときは、 CreateSolidBrush()で、指定された色(メニュー選択時の色)の論理ブラシを作成。
HBRUSH CreateSolidBrush( COLORREF crColor // ブラシの色を表す値 );
4.SetBkColor()で、現在の背景色を、指定された色の値に設定
5.SetTextColor()で、指定されたデバイスコンテキストのテキストの色を指定された色に設定
6.FillRect()で、指定されたブラシを使って、長方形を塗りつぶします。
int FillRect( HDC hDC, // デバイスコンテキストのハンドル CONST RECT *lprc, // 長方形 HBRUSH hbr // ブラシのハンドル );
7.DeleteObject()で、作成したオブジェクトを削除。
8.DrawIconEx()で、指定されたアイコンまたはマウスカーソルを指定されたデバイスに描画。
BOOL DrawIconEx( HDC hDC, // 描画先のデバイスコンテキストのハンドル int x, // アイコンまたはマウスカーソルの左上端のx座標 int y, // アイコンまたはマウスカーソルの左上端のy座標 HICON hIcon, // アイコンまたはマウスカーソルのハンドル int width, // アイコンまたはマウスカーソルの実際の描画幅 int height, // アイコンまたはマウスカーソルの実際の描画高さ UINT iStepAniCur, // (アニメーションカーソル時)フレームインデックス HBRUSH hbrFlicker, // ブラシのハンドル UINT uFlags // フラグ );
引数 uFlags の定数 | 機能 |
---|---|
DI_MASK | マスクを使ってアイコン、マウスカーソルを描画 |
DI_IMAGE | イメージを使ってアイコン、マウスカーソルを描画 |
DI_NORMAL | DI_IMAGE と DI_MASK |
DI_DEFAULTSIZE | widthメンバとheightメンバに 0 が指定されている場合、アイコンまたはマウスカーソルをデフォルトのサイズで描画 |
ソースコードの入力
ソースコードは下記のように入れてください。
#define _WIN32_WINNT 0x0501 #include <windows.h> #include "resource.h" #define MENU_WIDTH_PLUS 5 // グローバル変数: HINSTANCE hInst; // 現在のインターフェイス HMENU hMenu; // メニューのハンドル LPMEASUREITEMSTRUCT lpMI; // LPMEASUREITEMSTRUCT構造体 LPDRAWITEMSTRUCT lpDI; // DRAWITEMSTRUCT構造体 // このコード モジュールに含まれる関数の宣言を転送します: 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 = MAKEINTRESOURCE(IDC_HP); wcex.lpszClassName = TEXT("HP"); wcex.hIconSm = LoadIcon(NULL , IDI_APPLICATION); return RegisterClassEx(&wcex); } // // 関数: InitInstance(HINSTANCE, int) // // 目的: メイン ウィンドウを作成します。 // BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { HWND hWnd; hInst = hInstance; // グローバル変数にインスタンス処理を格納します。 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_COMMAND - アプリケーション メニューの処理 // WM_DESTROY - 中止メッセージを表示して戻る // // LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; HDC hdc; RECT rc; POINT pt; SIZE sz; LPCTSTR str[] = {TEXT("メニュー1"), TEXT("メニュー2"), TEXT("メニュー3")}; NONCLIENTMETRICS NCMetrics; HFONT hFont, hFontOld; static LOGFONT g_menufont; static int g_icon_vx, g_icon_vy; static DWORD g_menu_backcolor; static DWORD g_menu_textcolor; static HICON hIcon; HBRUSH hBrush; switch (message) { case WM_CREATE: hMenu = CreatePopupMenu(); AppendMenu(hMenu, MF_OWNERDRAW, IDM_MENU1, (LPCTSTR)0); AppendMenu(hMenu, MF_OWNERDRAW, IDM_MENU2, (LPCTSTR)1); AppendMenu(hMenu, MF_OWNERDRAW, IDM_MENU3, (LPCTSTR)2); NCMetrics.cbSize = sizeof(NONCLIENTMETRICS); SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &NCMetrics, 0); g_menufont = NCMetrics.lfMenuFont; g_icon_vx = (int)GetSystemMetrics(SM_CXSMICON); g_icon_vy = (int)GetSystemMetrics(SM_CYSMICON); hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_TEST)); g_menu_backcolor = GetSysColor(COLOR_HIGHLIGHT); g_menu_textcolor = GetSysColor(COLOR_HIGHLIGHTTEXT); break; case WM_MEASUREITEM: lpMI = (LPMEASUREITEMSTRUCT)lParam; hdc = GetDC(hWnd); hFont = CreateFontIndirect(&g_menufont); hFontOld = (HFONT)SelectObject(hdc, hFont); GetTextExtentPoint32(hdc, str[lpMI->itemData], lstrlen(str[lpMI->itemData]) - 1, &sz); lpMI->itemWidth = sz.cx + g_icon_vx + MENU_WIDTH_PLUS; lpMI->itemHeight = sz.cy + 5; ReleaseDC(hWnd, hdc); break; case WM_DRAWITEM: lpDI = (LPDRAWITEMSTRUCT)lParam; rc = lpDI->rcItem; hdc = lpDI->hDC; hFont = CreateFontIndirect(&g_menufont); hFontOld = (HFONT)SelectObject(hdc, hFont); switch (lpDI->itemID) { case IDM_MENU1: if (lpDI->itemState & ODS_SELECTED) { hBrush = CreateSolidBrush(g_menu_backcolor); SetBkColor(hdc, g_menu_backcolor); SetTextColor(hdc, g_menu_textcolor); } else { hBrush = CreateSolidBrush(GetBkColor(hdc)); } FillRect(hdc, &rc, hBrush); DeleteObject(hBrush); DrawIconEx(hdc, rc.left, rc.top + 1, hIcon, g_icon_vx, g_icon_vy, 0, NULL, DI_IMAGE | DI_MASK); TextOut(hdc, rc.left + g_icon_vx + MENU_WIDTH_PLUS, rc.top, str[0], lstrlen(str[0])); break; case IDM_MENU2: if (lpDI->itemState & ODS_SELECTED) { hBrush = CreateSolidBrush(g_menu_backcolor); SetBkColor(hdc, g_menu_backcolor); SetTextColor(hdc, g_menu_textcolor); } else { hBrush = CreateSolidBrush(GetBkColor(hdc)); } FillRect(hdc, &rc, hBrush); DeleteObject(hBrush); DrawIconEx(hdc, rc.left, rc.top + 1, hIcon, g_icon_vx, g_icon_vy, 0, NULL, DI_IMAGE | DI_MASK); TextOut(hdc, rc.left + g_icon_vx + MENU_WIDTH_PLUS, rc.top, str[1], lstrlen(str[1])); break; case IDM_MENU3: if (lpDI->itemState & ODS_SELECTED) { hBrush = CreateSolidBrush(g_menu_backcolor); SetBkColor(hdc, g_menu_backcolor); SetTextColor(hdc, g_menu_textcolor); } else { hBrush = CreateSolidBrush(GetBkColor(hdc)); } FillRect(hdc, &rc, hBrush); DeleteObject(hBrush); DrawIconEx(hdc, rc.left, rc.top + 1, hIcon, g_icon_vx, g_icon_vy, 0, NULL, DI_IMAGE | DI_MASK); TextOut(hdc, rc.left + g_icon_vx + MENU_WIDTH_PLUS, rc.top, str[2], lstrlen(str[2])); break; } SelectObject(hdc, hFontOld); DeleteObject(hFont); break; case WM_RBUTTONDOWN: pt.x = LOWORD(lParam); pt.y = HIWORD(lParam); ClientToScreen(hWnd, &pt); TrackPopupMenu(hMenu, TPM_LEFTALIGN, pt.x, pt.y, 0, hWnd, NULL); break; case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // 選択されたメニューの解析: switch (wmId) { case IDM_MENU1: MessageBox(hWnd, TEXT("メニュー1が押されました"), TEXT("確認"), MB_OK); break; case IDM_MENU2: MessageBox(hWnd, TEXT("メニュー2が押されました"), TEXT("確認"), MB_OK); break; case IDM_MENU3: MessageBox(hWnd, TEXT("メニュー3が押されました"), TEXT("確認"), MB_OK); break; 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; }
上記の太線で示している箇所のみ追加です。
#define IDM_ABOUT 104
#define IDM_EXIT 105
#define IDI_TEST 107
#define IDM_MENU1 111
#define IDM_MENU2 112
#define IDM_MENU3 113
#define IDC_HP 109
上記の太線で示している箇所のみ追加です。
#include "resource.h"
/////////////////////////////////////////////////////////////////////////////
//
// アイコン
//
IDI_TEST ICON "test.ico"
/////////////////////////////////////////////////////////////////////////////
//
// メニュー
//
IDC_HP MENU
BEGIN
POPUP "ファイル(&F)"
BEGIN
MENUITEM "アプリケーションの終了(&X)", IDM_EXIT
END
POPUP "ヘルプ(&H)"
BEGIN
MENUITEM "バージョン情報(&A)...", IDM_ABOUT
END
END
上記の太線で示している箇所のみ追加です。