図のようなタブコントロールをもつウインドウを作成します。
メニュー - インコのWindowsSDK で作成したソースを修正します。
流れ
タブコントロールは、コモンコントロールですので、下記1、2、3が必要です。
1.commctrl.hをインクルード
2.comctl32.libを読み込む
WM_CREATE
3.InitCommonControlsEx()でコモンコントロールの初期化
4.GetClientRect()でウィンドウのクライアント領域の座標を取得。
取得した座標は、次の5でタブコントロールのウインドウを生成するときに使います。
5. CreateWindowEx()で、タブコントロールのウインドウを生成。
CreateWindowEx()の引数 lpClassName (登録されているクラス名)は、WC_TABCONTROL (タブコントロール)になります。
CreateWindowEx()の引数 dwStyle (ウィンドウスタイル)は下記。 共通のウィンドウスタイル、 タブコントロールのスタイルが使えます。
タブコントロールのスタイル ●以下は、lpClassNameでWC_TABCONTROLを指定したときのみ有効 |
|
TCS_SCROLLOPPOSITE | 選択されていないタブを反対に移動 |
TCS_RIGHT |
タブを右側に表示 「TCS_VERTICAL」と同時に使用 |
TCS_FLATBUTTONS | タブをフラットで表示 |
TCS_FORCEICONLEFT | アイコンを左詰め、真ん中に文字を表示 |
TCS_FORCELABELLEFT | アイコンと文字を左詰め |
TCS_HOTTRACK | マウスカーソルの下のタブを強調表示 |
TCS_VERTICAL |
タブを右側に表示 「TCS_RIGHT」と同時に使用 |
TCS_TABS | デフォルトスタイル |
TCS_BUTTONS | タブをプッシュボタンとして表示 |
TCS_SINGLELINE | タブが一行で表示(デフォルト) |
TCS_MULTILINE | 一行で全てのタブを表示できない場合 タブを改行し、複数行で表示します。 |
TCS_RIGHTJUSTIFY | 全てのタブの合計の幅が、タブコントロール全体のサイズになるまで拡大 |
TCS_FIXEDWIDTH | 全てのタブを同じサイズで表示 |
TCS_RAGGEDRIGHT | タブを左詰めで表示 |
TCS_FOCUSONBUTTONDOWN | 「TCS_BUTTONS」を設定した時フォーカスを受け取ります |
TCS_OWNERDRAWFIXED | オーナードロー |
TCS_TOOLTIPS | ツールチップ表示 |
TCS_FOCUSNEVER | フォーカスを受け付けません |
6.フォントを変更するため、WM_SETFONTメッセージをセット。
GetStockObject()で、システムで定義されているのフォントを取得。
7.INITCOMMONCONTROLSEX()構造体を定義。
8.タブの情報を格納しているTCITEM構造体に必要な情報をセット。
typedef struct tagTCITEM { UINT mask; // 有効なメンバ DWORD dwState; // アイテム状態 DWORD dwStateMask; // dwStateの有効ビットを示すマスク LPTSTR pszText; // タブの文字列 int cchTextMax; // pszTextのサイズ int iImage; // イメージインデックス LPARAM lParam; // アプリケーション定義値 } TCITEM, FAR *LPTCITEM;
構造体のメンバー mask の定数 | 構造体のどのメンバが有効かを示すフラグ |
---|---|
TCIF_TEXT | pszTextが有効 |
TCIF_IMAGE | iImageが有効 |
TCIF_PARAM | lParamが有効 |
TCIF_STATE | dwStateが有効 |
9.TabCtrl_InsertItem()で、タブコントロールにタブを追加。
int TabCtrl_InsertItem( HWND hwnd, // タブコントロールのハンドル int iItem, // 追加するタブのインデックス const LPTCITEM pitem // TCITEM構造体のポインタ );
TabCtrl_InsertItem()の代わりに、SendMessage(hwnd, TCM_INSERTITEM, iItem, pitem)を使うこともできます。
WM_SIZE
1.GetClientRect()でウィンドウのクライアント領域の座標を取得。
クライアント領域とは、タイトルバー、メニューバー、 ツールバー、ステータスバー、ウィンドウ枠、スクロールバーを除いた領域のこと。
2.TabCtrl_AdjustRect()で、タブコントロールのウィンドウ領域から表示領域を計算。
VOID TabCtrl_AdjustRect( HWND hwnd, // タブコントロールのハンドル BOOL fLarger, // RECT *prc // RECT構造体 );
TabCtrl_AdjustRect()の代わりに、SendMessage(hwnd, TCM_ADJUSTRECT, fLarger, *prc)を使うこともできます。
fLarger | どちら向きに変換するのかを指定 | |
FALSE | コントロールウィンドウ領域を表示領域に変換 | |
TRUE | 表示領域をコントロールウィンドウ領域に変換 | |
*prc | 変換前の領域を格納したRECT構造体のアドレスを指定 関数実行後は、この構造体には変換後の領域が格納されます。 |
3.MoveWindow()で、タブコントロールのウインドウサイズを変える。
TCN_SELCHANGE(WM_NOTIFYメッセージ形式)
TCN_SELCHANGEメッセージは、タブコントロールの親ウィンドウに、選択されているタブが変更されたことを通知します。
この通知メッセージはWM_NOTIFYメッセージ形式で送信されます。
1.InvalidateRect()を実行することで、WM_PAINTメッセージを発生させて、タブコントロールを再描画します。
2.TabCtrl_GetCurSel()で、現在選択されているタブのインデックスを取得。
int TabCtrl_GetCurSel( HWND hwnd );
SendMessage(hwnd, TCM_GETCURSEL, 0, 0)と同等。
TCN_SELCHANGING(WM_NOTIFYメッセージ形式)
TCN_SELCHANGINGメッセージは、タブコントロールの親ウィンドウに、選択されているタブが変更されることを通知します。
この通知メッセージはWM_NOTIFYメッセージ形式で送信されます。
1.TabCtrl_GetCurSel()で、現在選択されているタブのインデックスを取得。
WM_GETMINMAXINFO
WM_GETMINMAXINFOメッセージは、ウィンドウのサイズまたは位置を変更しようとしているときに、そのウィンドウに送られます。
WM_GETMINMAXINFOメッセージが発生した時に、現在の関数 WndProc() の引数、wParam、lParamには下記がセットされます。
WM_GETMINMAXINFOメッセージのwParam:
常に0
WM_GETMINMAXINFOメッセージのlParam:
データを受け取るMINMAXINFO構造体のポインタ
1.LPMINMAXINFO構造体のメンバptMinTrackSizeに、ウインドウサイズの最小値をセット。
ウインドウサイズの最小値は、先ほど取得した MINMAXINFO構造体のポインタから取得します。
typedef struct tagMINMAXINFO { POINT ptReserved; // 予約済み POINT ptMaxSize; // 最大化ボタンを押した時の大きさ POINT ptMaxPosition; // 最大サイズの時の左上の座標 POINT ptMinTrackSize; // マウスで大きさを変えた時の最小ウインドウサイズ POINT ptMaxTrackSize; // マウスで大きさを変えた時の最大ウインドウサイズ } MINMAXINFO, *PMINMAXINFO, *LPMINMAXINFO;
LPMINMAXINFO構造体のメンバは、すべて座標を格納する構造体であるPOINT構造体になっています。
ソースコードの入力
ソースコードは下記のように入れてください。
#include <windows.h> #include <commctrl.h> #include "resource.h" #define X_MIN 240 #define Y_MIN 177 #pragma comment(lib, "comctl32.lib") // ステータスバーの作成に必要 // グローバル変数: HINSTANCE hInst; // 現在のインターフェイス HWND hTab; // タブコントロールのハンドル // このコード モジュールに含まれる関数の宣言を転送します: 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_CREATE - ウインドウ作成時の処理 // WM_SIZE - ウインドウサイズ変更時の処理 // WM_GETMINMAXINFO - ウインドウサイズ・位置変更時の処理 // WM_COMMAND - アプリケーション メニューの処理 // WM_DESTROY - 中止メッセージを表示して戻る // // LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; int nTab; static RECT rc; TCITEM ti; INITCOMMONCONTROLSEX ic; LPMINMAXINFO lpmm; switch (message) { case WM_CREATE: ic.dwSize = sizeof(INITCOMMONCONTROLSEX); ic.dwICC = ICC_TAB_CLASSES; InitCommonControlsEx(&ic); GetClientRect(hWnd, &rc); hTab = CreateWindowEx(0, WC_TABCONTROL, TEXT(""), WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE , 0, 0, rc.right, rc.bottom, hWnd, (HMENU)ID_TAB, hInst, NULL); SendMessage(hTab, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), 0); ti.mask = TCIF_TEXT; ti.pszText = TEXT("タブ0"); TabCtrl_InsertItem(hTab, 0, &ti); ti.pszText = TEXT("タブ1"); TabCtrl_InsertItem(hTab, 1, &ti); ti.pszText = TEXT("タブ2"); TabCtrl_InsertItem(hTab, 2, &ti); break; case WM_SIZE: GetClientRect(hWnd, &rc); TabCtrl_AdjustRect(hTab, FALSE, &rc); MoveWindow(hTab, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE); break; case WM_NOTIFY: switch (((NMHDR *)lParam)->code) { case TCN_SELCHANGE: InvalidateRect(hTab, NULL, TRUE); nTab = TabCtrl_GetCurSel(hTab); break; case TCN_SELCHANGING: nTab = TabCtrl_GetCurSel(hTab); break; } break; case WM_GETMINMAXINFO: lpmm = (LPMINMAXINFO)lParam; lpmm->ptMinTrackSize.x = X_MIN; lpmm->ptMinTrackSize.y = Y_MIN; 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 ID_TAB 1001
#define IDM_ABOUT 104
#define IDM_EXIT 105
#define IDC_HP 109
上記の太線で示している箇所のみ追加です。
#include "resource.h" ///////////////////////////////////////////////////////////////////////////// // // メニュー // IDC_HP MENU BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "アプリケーションの終了(&X)", IDM_EXIT END POPUP "ヘルプ(&H)" BEGIN MENUITEM "バージョン情報(&A)...", IDM_ABOUT END END