第207章 ダイアログボックス上のタブコントロール


前章ではタブコントロールの新しいスタイルを使うと 表示がうまくいかないことを書きました。 これは、どうもTabCtrl_AdjustRectマクロが 正しい値を教えてくれないことも原因の一つのようです。 そこで、タブコントロールの大きさが変化しないものを 作ればよいことになります。今回はタブコントロールを ダイアログボックス上に作ります。リソースエディタで ダイアログボックス上にタブコントロールを作ります。



左の図はダイアログボックス上に縦型のタブコントロールが 貼りついています。また、現在ポイントされているタブが 青色にハイライトされています。

「年齢」を記入するとこの値が自動的に構造体に 記憶されて、次回ダイアログボックスを呼び出した時にも その値を保持しているようにしています。 (プログラムそのものを終了した時は無効)



リソースエディタで上の図を参考にダイアログボックスと タブコントロール、スタティックコントロール、 エディットコントロール、ボタンの配置を決めて下さい。 タブコントロールのプロパティは「右に揃える」「ホットトラック」 「垂直方向」にチェックをつけておいて下さい。

// newtab02.rcの一部 ///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "終了(&X)", IDM_END END POPUP "ダイアログ(&D)" BEGIN MENUITEM "ダイアログボックス(&T)", IDM_TAB END END ///////////////////////////////////////////////////////////////////////////// // // Dialog // MYDLG DIALOG DISCARDABLE 0, 0, 131, 131 STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "TabControl" FONT 9, "MS Pゴシック" BEGIN DEFPUSHBUTTON "OK",IDOK,10,110,35,14 PUSHBUTTON "キャンセル",IDCANCEL,84,110,35,14 LTEXT "test",IDC_STATIC1,36,19,83,31,SS_CENTERIMAGE | SS_SUNKEN LTEXT "Static",IDC_STATIC2,67,61,51,12 EDITTEXT IDC_EDIT1,68,80,30,12,ES_AUTOHSCROLL LTEXT "年齢 :",IDC_STATIC,37,80,18,8 LTEXT "住所 :",IDC_STATIC,36,61,18,8 CONTROL "Tab1",IDC_TAB1,"SysTabControl32",TCS_HOTTRACK | TCS_VERTICAL,7,7,116,102 END

リソースエディタでダイアログ中のコントロールの配置を決めると 上のようなスクリプトができあがります。

// newtab02.cpp #ifndef STRICT #define STRICT #endif #include <windows.h> #include <windowsx.h> #include "resource.h" #include "commctrl.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK MyDlgProc(HWND, UINT, WPARAM, LPARAM); ATOM InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); void SetMyData(void); char szClassName[] = "newtab02"; //ウィンドウクラス typedef struct { char szName[16]; char szAddress[32]; char szAge[8]; } MYDATA; MYDATA MyData[4];

今回はデータを蓄える変数として、構造体を独自に定義してみました。

int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) { MSG msg; 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 = "MYMENU"; //メニュー名 wc.lpszClassName = (LPCSTR)szClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); return (RegisterClassEx(&wc)); } //ウィンドウの生成 BOOL InitInstance(HINSTANCE hInst, int nCmdShow) { HWND hWnd; hWnd = CreateWindow(szClassName, "猫でもわかるタブコントロール", //タイトルバーにこの名前が表示されます 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; HINSTANCE hInst; switch (msg) { case WM_CREATE: SetMyData(); break; case WM_COMMAND: switch (LOWORD(wp)) { case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; case IDM_TAB: hInst = (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE); DialogBox(hInst, "MYDLG", hWnd, (DLGPROC)MyDlgProc); break; } break; case WM_CLOSE: id = MessageBox(hWnd, "終了してもよいですか", "終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { DestroyWindow(hWnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0; }

WM_CREATEメッセージが来たら構造体に規定値の データ(名前、住所)をセットします。

メニューで「ダイアログボックス」(IDM_TAB)が選択されたら ダイアログボックスを表示させます。

LRESULT CALLBACK MyDlgProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp) { static HWND hTab, hStatic1, hStatic2, hEdit; TCITEM ti; static int nNo; static HFONT hFont; char str[256]; switch (msg) { case WM_INITDIALOG: hFont = CreateFont(30, 0, 0, 0, FW_NORMAL, FALSE, FALSE, 0, SHIFTJIS_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "MS Pゴシック"); hTab = GetDlgItem(hDlg, IDC_TAB1); hStatic1 = GetDlgItem(hDlg, IDC_STATIC1); hStatic2 = GetDlgItem(hDlg, IDC_STATIC2); hEdit = GetDlgItem(hDlg, IDC_EDIT1); memset(&ti, 0, sizeof(TCITEM)); ti.mask = TCIF_TEXT; ti.pszText = MyData[0].szName; TabCtrl_InsertItem(hTab, 0, &ti); ti.pszText = MyData[1].szName; TabCtrl_InsertItem(hTab, 1, &ti); ti.pszText = MyData[2].szName; TabCtrl_InsertItem(hTab, 2, &ti); ti.pszText = MyData[3].szName; TabCtrl_InsertItem(hTab, 3, &ti); SendMessage(hStatic1, WM_SETFONT, (WPARAM)hFont, (LPARAM)MAKELONG(TRUE, 0)); TabCtrl_SetCurSel(hTab, nNo); SetWindowText(hStatic1, MyData[nNo].szName); SetWindowText(hStatic2, MyData[nNo].szAddress); SetWindowText(hEdit, MyData[nNo].szAge); return TRUE; case WM_COMMAND: switch (LOWORD(wp)) { case IDOK: case IDCANCEL: DeleteObject(hFont); EndDialog(hDlg, IDOK); return TRUE; } if (lp == (LPARAM)hEdit && HIWORD(wp) == EN_CHANGE) { Edit_GetText(hEdit, str, sizeof(str)); strcpy(MyData[nNo].szAge, str); return TRUE; } return FALSE; case WM_NOTIFY: switch (((NMHDR *)lp)->code) { case TCN_SELCHANGE: nNo = TabCtrl_GetCurSel(hTab); switch (nNo) { case 0: SetWindowText(hStatic1, MyData[0].szName); SetWindowText(hStatic2, MyData[0].szAddress); SetWindowText(hEdit, MyData[0].szAge); return TRUE; case 1: SetWindowText(hStatic1, MyData[1].szName); SetWindowText(hStatic2, MyData[1].szAddress); SetWindowText(hEdit, MyData[1].szAge); return TRUE; case 2: SetWindowText(hStatic1, MyData[2].szName); SetWindowText(hStatic2, MyData[2].szAddress); SetWindowText(hEdit, MyData[2].szAge); return TRUE; case 3: SetWindowText(hStatic1, MyData[3].szName); SetWindowText(hStatic2, MyData[3].szAddress); SetWindowText(hEdit, MyData[3].szAge); return TRUE; } return FALSE; } return FALSE; } return FALSE; }

ダイアログボックスのプロシージャです。

WM_INITDIALOGメッセージが来たら、 各コントロールのウィンドウハンドルをスタティックな変数に取得します。 次にタブを挿入します。そして、インデックスをnNoにして、その内容を 表示します。nNoはスタティックなのでずっと値を保持しています。 また、また名前部分のスタティクコントロールのフォントを 大きめに設定します。(WM_SETFONT)

「OK」ボタンや「キャンセル」ボタンが押されたらhFontを破棄して ダイアログボックスを閉じます。

エジットボックスの内容が変えられたら(EN_CHANGE) その内容を読みとって(Edit_GetText)構造体に記憶させます。 この手の通知メッセージは何回も出てきているのであえて説明しません。

選択されているタブか変更された時(TCN_SELCHANGE)には、そのインデックス によってコントロールに表示する内容を変えます。

void SetMyData() { memset(&MyData, 0, sizeof(MYDATA)); strcpy(MyData[0].szName , "粂井康孝"); strcpy(MyData[0].szAddress, "北海道旭川市"); strcpy(MyData[1].szName, "粂井ひとみ"); strcpy(MyData[1].szAddress, "妹背牛町"); strcpy(MyData[2].szName, "粂井志麻"); strcpy(MyData[2].szAddress, "東京都港区"); strcpy(MyData[3].szName, "粂井櫻都"); strcpy(MyData[3].szAddress, "中富良野町"); return; }

規定値のデータを構造体にセットする関数です。あんまり意味はありません。

さて、今回縦型タブコントロールがうまくいったのはタブコントロール自体の 大きさが変化しないからです。こういう場合は新しいタブコントロールの スタイルがすべて使えます。いろいろ試してみてください。


[SDK第3部 Index] [総合Index] [Previous Chapter] [Next Chapter]

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