第208章 タブコントロールにエディットコントロールをつける


前章ではダイアログボックスに縦型タブコントロールをつけました。 今回は親ウィンドウに縦型タブコントロールを貼りつけます。



タブコントロールの大きさはいろいろに変えることができます。 しかし、左の図が最小の場合を示しています。 つまり、タブが2列以上にならないようにしています。

また、選択されているタブが変化した時にはエディットコントロールに 記入されているテキストも変更しなくてはいけません。



ウィンドウの大きさを制限するにはWM_GETMINMAXINFOメッセージを 処理します。

WM_GETMINMAXINFO lpmmi = (LPMINMAXINFO) lParam;

このメッセージはウィンドウのサイズや位置が変化しようとしている時に 送られてきます。このメッセージを捕まえてデフォルトの位置サイズを 変更することができます。

MINMAXINFO構造体は次のように定義されています。

typedef struct tagMINMAXINFO { // mmi POINT ptReserved; POINT ptMaxSize; POINT ptMaxPosition; POINT ptMinTrackSize; POINT ptMaxTrackSize; } MINMAXINFO;

ptReservedは予約されているので使えません。
ptMaxSizeは最大のサイズを指定します。 (このメンバがPOINT構造体であることに注意)
ptMaxPositionは最大サイズの時の左上の座標を指定。
ptMinTrackSizeには最小サイズを指定。
ptMaxTrackSizeには最大サイズを指定。

では、選択されているタブが変化した時の処理はどうすればよいのでしょうか。 TCN_SELCHANGE通知メッセージは変化した時に送られます。 変更前の情報を保存しなくてはいけません。 これには、TCN_SELCHANGING通知メッセージを捕まえれば よいのです。

TCN_SELCHANGING lpnmhdr = (LPNMHDR) lParam;

これは、現在選択されているタブが変えられようとしている 時に送られてきます。これを捕まえることにより タブ変更前の情報を保存することができます。

では、プログラムを見てみましょう。

// newtab03.cpp #ifndef STRICT #define STRICT #endif #include <windows.h> #include <windowsx.h> #include <commctrl.h> #define ID_TAB 101 #define ID_STATIC 102 #define ID_EDIT 103 #define X_MIN 240 #define Y_MIN 177 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK MyStaticProc(HWND, UINT, WPARAM, LPARAM); ATOM InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); char szClassName[] = "newtab03"; //ウィンドウクラス HINSTANCE hInst; HWND hTab; WNDPROC OrgStaticProc; //元もとのスタティックコントロールのプロシージャ

ウィンドウの最小値をX_MIN, Y_MINに定義しておきます。 実際にウィンドウを作ってみてこの値を調整します。

コモンコントロールの前準備も忘れないでください。

int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) { MSG msg; hInst = hCurInst; if (!InitApp(hCurInst)) return FALSE; if (!InitInstance(hCurInst, nCmdShow)) return FALSE; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } //ウィンドウ・クラスの登録 ATOM InitApp(HINSTANCE hInst) { WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; //プロシージャ名 wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInst;//インスタンス wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszMenuName = NULL; //メニュー名 wc.lpszClassName = (LPCSTR)szClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); return (RegisterClassEx(&wc)); } //ウィンドウの生成 BOOL InitInstance(HINSTANCE hInst, int nCmdShow) { HWND hWnd; hWnd = CreateWindow(szClassName, "猫でもわかるTabControl", //タイトルバーにこの名前が表示されます WS_OVERLAPPEDWINDOW, //ウィンドウの種類 CW_USEDEFAULT, //X座標 CW_USEDEFAULT, //Y座標 CW_USEDEFAULT, //幅 CW_USEDEFAULT, //高さ NULL, //親ウィンドウのハンドル、親を作るときはNULL NULL, //メニューハンドル、クラスメニューを使うときはNULL hInst, //インスタンスハンドル NULL); if (!hWnd) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; }

このへんはいつもと同じです。

//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id, nTab; static HWND hStatic, hEdit; static RECT rc; TCITEM ti; INITCOMMONCONTROLSEX ic; LPMINMAXINFO lpmm; static char szStr[3][256]; switch (msg) { case WM_CREATE: ic.dwSize = sizeof(INITCOMMONCONTROLSEX); ic.dwICC = ICC_TAB_CLASSES; InitCommonControlsEx(&ic); GetClientRect(hWnd, &rc); hTab = CreateWindowEx(0, WC_TABCONTROL, "", WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | TCS_VERTICAL | TCS_RIGHT, 0, 0, rc.right, rc.bottom, hWnd, (HMENU)ID_TAB, hInst, NULL); hStatic = CreateWindowEx(0, "Static", "", WS_CHILD | WS_VISIBLE, 0, 0, CW_USEDEFAULT, CW_USEDEFAULT, hWnd, (HMENU)ID_STATIC, hInst, NULL); hEdit = CreateWindowEx(0, "Edit", "", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_MULTILINE, 20, 50, 150, 50, hStatic, (HMENU)ID_EDIT, hInst, NULL); SendMessage(hTab, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), 0); ti.mask = TCIF_TEXT; ti.pszText = "住所"; TabCtrl_InsertItem(hTab, 0, &ti); ti.pszText = "氏名"; TabCtrl_InsertItem(hTab, 1, &ti); ti.pszText = "年齢"; TabCtrl_InsertItem(hTab, 2, &ti); //スタティックコントロールのサブクラス化 OrgStaticProc = (WNDPROC)GetWindowLong(hStatic, GWL_WNDPROC); if (SetWindowLong(hStatic, GWL_WNDPROC, (LONG)MyStaticProc) == 0) MessageBox(hWnd, "Error", "Error", MB_OK); break; case WM_SIZE: GetClientRect(hWnd, &rc); TabCtrl_AdjustRect(hTab, FALSE, &rc); MoveWindow(hTab, 0, 0, LOWORD(lp), HIWORD(lp), TRUE); MoveWindow(hStatic, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE); break; case WM_NOTIFY: switch (((NMHDR *)lp)->code) { case TCN_SELCHANGE: InvalidateRect(hTab, NULL, TRUE); InvalidateRect(hStatic, NULL, TRUE); nTab = TabCtrl_GetCurSel(hTab); Edit_SetText(hEdit, szStr[nTab]); break; case TCN_SELCHANGING: nTab = TabCtrl_GetCurSel(hTab); Edit_GetText(hEdit, szStr[nTab], sizeof(szStr[nTab])); break; } break; case WM_GETMINMAXINFO: lpmm = (LPMINMAXINFO)lp; lpmm->ptMinTrackSize.x = X_MIN; lpmm->ptMinTrackSize.y = Y_MIN; break; case WM_CLOSE: id = MessageBox(hWnd, "終了してもよいですか", "終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { if (SetWindowLong(hStatic, GWL_WNDPROC, (LONG)OrgStaticProc) == 0) MessageBox(hWnd, "サブクラス化解除失敗", "Error", MB_OK); if (DestroyWindow(hEdit) == 0) MessageBox(hWnd, "エディットコントロール破棄失敗", "Error", MB_OK); if (DestroyWindow(hStatic) == 0) MessageBox(hWnd, "hStatic破棄失敗", "ERROR", MB_OK); if (DestroyWindow(hTab) == 0) MessageBox(hWnd, "hTab破棄失敗", "Error", MB_OK); DestroyWindow(hWnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0; }

WM_CREATEメッセージが来たら、コモンコントロールを初期化して、 タブコントロール、スタティックコントロール、エディットコントロールを 作ります。また、スタティックコントロールをサプクラス化しておきます。

WM_SIZEメッセージが来たらタブコントロールとスタティックコントロールの サイズを調整しておきます。

TCN_SELCHANGEはタブが変化してしまった時に来ますので 現在のタブのインデックスを取得してエディットコントロールに テキストを表示します。

TCN_SELCHANGINGはタブが変化しようとしている時に来るので この時のエディットコントロールのテキストを保存しておきます。

この2つの通知メッセージの処理でエディットコントロールのテキストは タブにあった表示となります。

WM_GETMINMAXINFOメッセージが来たらX_MIN, Y_MINを設定します。 MINMAXINFO構造体のメンバはすべてPOINT構造体であることに 注意して下さい。

//サブクラス化されたスタティックコントロールのプロシージャ LRESULT CALLBACK MyStaticProc(HWND hStatic, UINT msg, WPARAM wp, LPARAM lp) { HDC hdc; PAINTSTRUCT ps; int nNo; static char szStr[3][64] = {"住所を入力", "氏名を入力", "年齢を入力"}; switch (msg) { case WM_PAINT: hdc = BeginPaint(hStatic, &ps); nNo = TabCtrl_GetCurSel(hTab); SetBkMode(hdc, TRANSPARENT); TextOut(hdc, 10, 10, szStr[nNo], lstrlen(szStr[nNo])); EndPaint(hStatic, &ps); break; default: return CallWindowProc(OrgStaticProc, hStatic, msg, wp, lp); } return 0; }

サブクラス化されたスタティックコントロールのプロシージャです。 内容は第206章とほぼ同じです。 スタティックコントロールの内容を表示します。
[SDK第3部 Index] [総合Index] [Previous Chapter] [Next Chapter]

Update 14/Jun/1999 By Y.Kumei
当ホーム・ページの一部または全部を無断で複写、複製、 転載あるいはコンピュータ等のファイルに保存することを禁じます。