今回はレバーコントロール(クールバー、リバーコントロール)をつけます。
レバーコントロール上にボタンをのせます。
レバーコントロール間のサイズは、マウスのドラッグ&ドロップでサイズ変更ができます。
また、マウスのドラッグ&ドロップで、レバーコントロールを2行にもできます。
ボタンの上では、マウスのドラッグ&ドロップができません。レバーコントロールの左側の縁でできます。
メニュー - インコのWindowsSDK で作成したソースを修正します。
流れ
1.Windows XPに対応することを示す#define _WIN32_WINNT 0x0501 を追加
0x0501はWindows XPを示します。
#define _WIN32_WINNT version
上記のversionは、そのWindowsのバージョンまでに追加された機能を使用します。
version | Windowsのバージョン |
---|---|
0x0500 | Windows 2000 |
0x0501 | Windows XP |
0x0502 | Windows Server 2003 |
0x0600 | Windows Vista / Windows Server 2008 |
0x0601 | Windows 7 ※1 |
0x0602 | Windows 8 ※2 |
0x0603 | Windows 8.1 |
※1 Visual C++ 2008の場合は、Windows 7で追加した機能を使えないため、versionに0x0601を指定しても意味がありません。
※2 Visual C++ 2010/2008の場合は、Windows 8で追加した機能を使えないため、versionに0x0602を指定しても意味がありません。
● _WIN32_WINNTを指定しない場合の動作
_WIN32_WINNTを定義しないと、Windows XP、Windows 2000では、レバーコントロールが表示できません。
これは、後で紹介するREBARBANDINFO構造体のメンバが、Windows Vistaで追加されたためです。
● _WIN32_WINNTを定義しない別の方法(非推奨)
_WIN32_WINNTを定義せず、REBARBANDINFO構造体のcbSizeメンバに、直接80を入れてもWindows XP、Vistaともにレバーコントロールが表示できますが、
_WIN32_WINNTを定義しない場合の、構造体のサイズは100なので、意図しない動作が起こる可能性があるため、やめておきましょう。
_WIN32_WINNTを定義せず、REBARBANDINFO構造体のcbSizeメンバに、直接80を入れた場合、誤って追加されたREBARBANDINFO構造体のメンバにセットしてもコンパイルエラーにはなりません。
● _WIN32_WINNTを指定しない場合のデフォルト値
Visual C++ のバージョン | _WIN32_WINNT のデフォルト値 |
---|---|
2013 | 0x0603 |
2012 | 0x0602 |
2010 | 0x0601 |
2008 | 0x0600 |
● _WIN32_WINNTを定義する場所
#include <windows.h> の前に定義してください。
後に定義すると以下のようなwarningが出ますが、動作上の問題はありません。
warning C4005: '_WIN32_WINNT' : マクロが再定義されました。
c:\program files\microsoft sdks\windows\v7.0a\include\sdkddkver.h(197) : '_WIN32_WINNT' の前の定義を確認してください
2.commctrl.h をインクルード
3.comctl32.lib を読み込む
WM_CREATE
WM_CREATEは、ウインドウが生成されたときに1回だけ実行されます。
1.特定のコモンコントロールクラスを登録するINITCOMMONCONTROLSEX構造体にセット
今回はレバーコントロール[ICC_COOL_CLASSES]をセットします。
typedef struct tagINITCOMMONCONTROLSEX { DWORD dwSize; // 構造体のサイズ DWORD dwICC; // ロードするクラス } INITCOMMONCONTROLSEX, *LPINITCOMMONCONTROLSEX;
構造体のメンバー dwICC の定数 | ロードされるコントロールクラス |
---|---|
ICC_LISTVIEW_CLASSES | リストビュー、ヘッダーコントロール |
ICC_TREEVIEW_CLASSES | ツリービュー、ツールチップ |
ICC_BAR_CLASSES | ツールバー、ステータスバー、トラックバー、ツールチップ |
ICC_TAB_CLASSES | タブコントロール、ツールチップ |
ICC_UPDOWN_CLASS | アップダウンコントロール |
ICC_PROGRESS_CLASS | プログレスバー |
ICC_HOTKEY_CLASS | ホットキーコントロール |
ICC_ANIMATE_CLASS | アニメートコントロール |
ICC_WIN95_CLASSES | 以上のすべてのコントロール |
ICC_DATE_CLASSES | DTP コントロール |
ICC_USEREX_CLASSES | 拡張コンボボックス |
ICC_COOL_CLASSES | レバーコントロール |
ICC_INTERNET_CLASSES | IP アドレスコントロール |
ICC_PAGESCROLLER_CLASS | ページャーコントロール |
2.InitCommonControlsEx()で、コントロールを初期化。
InitCommonControls()でもかまいません。
この場合、INITCOMMONCONTROLSEX構造体にセットする必要はありません。
BOOL InitCommonControlsEx( LPINITCOMMONCONTROLSEX pInitCtrls // INITCOMMONCONTROLSEX構造体のアドレス );
3.CreateWindowEx()で、レバーコントロールのウインドウを生成する。
ここでは、とりあえず、サイズが0×0のウインドウを生成します。
ウインドウスタイルは、コモンコントロールのスタイルも使えます。
CreateWindowEx()の第11引数hInstanceには、アプリケーションインスタンスのハンドルを入れますが、GetWindowLong()を使ってインスタンスのハンドルを取得します。
4.レバーコントロールのスタイルを決めるREBARBANDINFO構造体をセット。
typedef struct tagREBARBANDINFO{ UINT cbSize; // 構造体のサイズ(80または100) UINT fMask; // どのメンバを使用するかを指定 UINT fStyle; // スタイル COLORREF clrFore; COLORREF clrBack; LPTSTR lpText; // コントロールの左に挿入する文字列 UINT cch; int iImage; HWND hwndChild; // コントロールに入れるコントロール(子ウインドウ)のハンドル UINT cxMinChild; // 横幅の最小値 UINT cyMinChild; // 高さの最小値 UINT cx; // 横幅の初期値 HBITMAP hbmBack; // 背景用ビットマップのハンドル UINT wID; // コントロールのID UINT cyChild; UINT cyMaxChild; UINT cyIntegral; UINT cxIdeal; LPARAM lParam; UINT cxHeader; #if (_WIN32_WINNT >= 0x0600) // Windows Vista以上 RECT rcChevronLocation; UINT uChevronState; #endif } REBARBANDINFO, *LPREBARBANDINFO;
構造体のメンバー fMask の定数 | 有効のメンバ |
---|---|
RBBIM_STYLE | fStyleが有効 |
RBBIM_COLORS | clrFore,clrBackが有効 |
RBBIM_TEXT | lpText,cchが有効 |
RBBIM_IMAGE | iImageが有効 |
RBBIM_CHILD | hwndChildが有効 |
RBBIM_CHILDSIZE | cxMinChild,cyMinChildが有効 |
RBBIM_SIZE | cxが有効 |
RBBIM_BACKGROUND | hbmBackが有効 |
RBBIM_ID | wIDが有効 |
RBBIM_IDEALSIZE | cxIdealが有効 |
RBBIM_LPARAM | lParamが有効 |
RBBIM_HEADERSIZE | cxHeaderが有効 |
構造体のメンバー fStyle の定数 | スタイル |
---|---|
RBBS_BREAK | バンドの列を変える |
RBBS_FIXEDSIZE | バンドのサイズを固定 |
RBBS_CHILDEDGE | 子ウィンドウの周りに隙間を入れます |
RBBS_HIDDEN | バンドを表示しません |
RBBS_NOVERT | レバーコントロールがCCS_VERTスタイルを使った時、バンドは表示されません |
RBBS_FIXEDBMP | バンドがリサイズしてもビットマップを移動しません |
RBBS_VARIABLEHEIGHT | バンドの高さを可変にします |
RBBS_GRIPPERALWAYS | サイズグリップ(取っ手の部分)を常に表示する(通常はバンドの数が1個のときは表示されない) |
RBBS_NOGRIPPER | サイズグリップを表示しない |
5.コントロールに入れるコントロール(子ウインドウ)に、ボタンのハンドルを入れる。
CreateWindowEx()でボタンを作成
6.RB_INSERTBANDメッセージで、レバーコントロールのバンドを挿入。
lResult = SendMessage( (HWND) hRebar, // ウィンドウハンドル (UINT) RB_INSERTBAND, (WPARAM) wParam, // バンドが挿入される位置、-1を指定すると最後に挿入 (LPARAM) lParam // REBARBANDINFO構造体へのアドレス );
7.GetClientRect()で、ウィンドウのクライアント領域の座標を取得。
クライアント領域とは、タイトルバー、メニューバー、 ツールバー、ステータスバー、ウィンドウ枠、スクロールバーを除いた領域のこと。
BOOL GetClientRect( HWND hWnd, // ウィンドウハンドル PRECT pRect // RECT構造体へのポインタ );
RECT構造体は座標を指定する構造体のことです。領域の左上の座標は常に(0,0)です。
WM_SIZE
WM_SIZEは、ウインドウのサイズが変わったとき(ウインドウ初回生成時も)に、実行されます。
MoveWindow()で、リッチエディットのウインドウサイズを変える。
ソースコードの入力
ソースコードは下記のように入れてください。
#define _WIN32_WINNT 0x0501 #include <windows.h> #include <commctrl.h> #include "resource.h" #pragma comment(lib, "comctl32.lib") // レバーコントロールの作成に必要 // このコード モジュールに含まれる関数の宣言を転送します: 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; 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_SIZE - ウインドウサイズ変更時の処理 // WM_COMMAND - アプリケーション メニューの処理 // WM_DESTROY - 中止メッセージを表示して戻る // // LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; static HWND hRebar; // レバーコントロールのハンドル RECT Rect; // RECT構造体 INITCOMMONCONTROLSEX ic; // INITCOMMONCONTROLSEX構造体 REBARBANDINFO rbBand; // REBARBANDINFO構造体 switch (message) { case WM_CREATE: //コモンコントロールの初期化 ic.dwICC = ICC_COOL_CLASSES; ic.dwSize = sizeof(INITCOMMONCONTROLSEX); InitCommonControlsEx(&ic); //レバーコントロールの作成 hRebar = CreateWindowEx(0,REBARCLASSNAME,TEXT(""), WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS |WS_CLIPCHILDREN | CCS_NODIVIDER, 0, 0, 0, 0, hWnd, (HMENU)ID_COOL, (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL); // REBARBANDINFO構造体 ZeroMemory(&rbBand, sizeof(REBARBANDINFO)); // 構造体のサイズ rbBand.cbSize = sizeof(REBARBANDINFO); // マスクフラグ rbBand.fMask = RBBIM_STYLE | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE; // バンドのスタイルフラグ rbBand.fStyle = RBBS_CHILDEDGE; // 最小値の高さ rbBand.cyMinChild = 30; // 最小値の幅 rbBand.cxMinChild = 100; // レバーコントロールにのせる対象の子ウインドウのハンドル rbBand.hwndChild = CreateWindowEx(0, TEXT("BUTTON"), TEXT("Button1"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 0, 0, 0, 0, hRebar, (HMENU)ID_BUTTON1, (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE) ,NULL); // レバーコントロールにボタン1を挿入 SendMessage(hRebar, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rbBand); // レバーコントロールにボタン2を挿入 rbBand.hwndChild = CreateWindowEx(0, TEXT("BUTTON"), TEXT("Button2"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 0, 0, 0, 100, hRebar, (HMENU)ID_BUTTON2, (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL); GetClientRect(hRebar, &Rect); rbBand.cx = Rect.right - 100; SendMessage(hRebar, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rbBand); break; case WM_SIZE: SendMessage(hRebar, WM_SIZE, wParam, lParam); 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; }
上記の太線で示している箇所のみ追加です。
#define IDM_ABOUT 104
#define IDM_EXIT 105
#define IDC_HP 109
#define ID_COOL 150
#define ID_BUTTON1 151
#define ID_BUTTON2 152
#define IDC_BUTTON1 161
#define IDC_BUTTON2 162
上記の太線で示している箇所のみ追加です。
#include "resource.h" ///////////////////////////////////////////////////////////////////////////// // // メニュー // IDC_HP MENU BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "アプリケーションの終了(&X)", IDM_EXIT END POPUP "ヘルプ(&H)" BEGIN MENUITEM "バージョン情報(&A)...", IDM_ABOUT END END