第183章 レバーコントロールにボタンとコンボボックスを置く


では、前章の知識をもとにレバーコントロールのプログラムを作ってみましょう。

// rebar01.cpp #ifndef STRICT #define STRICT #endif #include <windows.h> #include <commctrl.h> #define ID_BUT1 100 #define ID_COMBO 101 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); ATOM InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); HWND MakeMyRebar(HWND); HWND MakeMyCombo(HWND); char szClassName[] = "rebar01"; //ウィンドウクラス HINSTANCE hInst;

ボタンとコンボボックスはリソースエディタを利用しないので 自分でそのIDを定義しておきます。

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, "猫でもわかるレバーコントロール", //タイトルバーにこの名前が表示されます 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; }

このへんは、いつもと同じです。WinMain関数が始まったらすぐに インスタンスハンドルをグローバル変数にコピーしています。

//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id, no; INITCOMMONCONTROLSEX ic; static HWND hRebar, hBut, hCombo; REBARBANDINFO rbBand; HDC hdc; PAINTSTRUCT ps; static char szStr[256]; char szData[16]; RECT rc; switch (msg) { case WM_CREATE: ic.dwSize = sizeof(INITCOMMONCONTROLSEX); ic.dwICC = ICC_COOL_CLASSES; InitCommonControlsEx(&ic); hRebar = MakeMyRebar(hWnd); ZeroMemory(&rbBand, sizeof(REBARBANDINFO)); rbBand.cbSize = sizeof(REBARBANDINFO); rbBand.fMask = RBBIM_TEXT | RBBIM_STYLE | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE; rbBand.fStyle = RBBS_CHILDEDGE; rbBand.cxMinChild = 0; rbBand.cyMinChild = 25; hBut = CreateWindow("BUTTON", "押す", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 0, 0, 0, 0, hRebar, (HMENU)ID_BUT1, hInst ,NULL); rbBand.lpText = "ボタン"; rbBand.hwndChild = hBut; rbBand.cx = 100; SendMessage(hRebar, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rbBand); hCombo = MakeMyCombo(hRebar); rbBand.lpText = "コンボボックス"; rbBand.hwndChild = hCombo; GetWindowRect(hRebar, &rc); rbBand.cx = rc.right - rc.left - 100; SendMessage(hRebar, RB_INSERTBAND,(WPARAM)-1, (LPARAM)&rbBand); break; case WM_SIZE: SendMessage(hRebar, WM_SIZE, wp, lp); break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); GetWindowRect(hRebar, &rc); TextOut(hdc, 5, rc.bottom - rc.top + 5, szStr, strlen(szStr)); EndPaint(hWnd, &ps); break; case WM_COMMAND: switch (LOWORD(wp)) { case ID_BUT1: MessageBox(hWnd, "ボタンが押されました", "OK", MB_OK); break; case ID_COMBO: if (HIWORD(wp) == CBN_SELCHANGE) { no = SendMessage(hCombo, CB_GETCURSEL, 0, 0); SendMessage(hCombo, CB_GETLBTEXT, (WPARAM)no, (LPARAM)szData); wsprintf(szStr, "選択されているのは「%s」です", szData); InvalidateRect(hWnd, NULL, TRUE); UpdateWindow(hRebar); } break; } break; case WM_NOTIFY: { LPNMHDR lpnmhdr; lpnmhdr = (LPNMHDR)lp; if (lpnmhdr->hwndFrom == hRebar && lpnmhdr->code == RBN_HEIGHTCHANGE) { InvalidateRect(hWnd, NULL, TRUE); UpdateWindow(hRebar); } } break; case WM_CLOSE: id = MessageBox(hWnd, "終了してもよいですか", "終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { DestroyWindow(hBut); DestroyWindow(hCombo); DestroyWindow(hRebar); DestroyWindow(hWnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0; }

WM_CREATEメッセージが来たら、レバーコントロールに関する諸準備をします。 まず、ICC_COOL_CLASSESでコモンコントロールを初期化します。

次に自作関数MakeMyRebarでレバーコントロールを作ります。

CreateWindow関数でボタンを作ってREBARBANDINFO構造体に必要なものを 設定します。

cbSizeメンバは必須です。

fMaskメンバにはRBBIM_TEXT(lpTextメンバを有効にする)、RBBIM_STYLE(fStyleメンバを 有効にする)、RBBIM_CHILD(hwndChildメンバを有効にする)、RBBIM_CHILDSIZE (cxMinChild, cyMinChild, cyChild, cyMaxChild, cyIntegralメンバを有効にする)、 RBBIM_SIZE(cxメンバを有効にする)を設定しておきます。 さて、RBBIM_CHILDSIZEを設定してもfStyleにRBBS_VARIABLEHEIGHTが設定 されていないとcyChild, cyMaxChild, cyIntegralメンバは無視されます。 (このプログラムでは特に必要ないので無視してもらう)

fStyleメンバはRBBS_CHILDEDGEを指定します。

cxMinChildを0にしておくとバンドが縮まった時lpTextのみが表示されます。

ここまでが今回作るプログラムでREBARBANDINFO構造体の共通のメンバです。 あとは、コントロールを作るたびに設定します。

次にボタンを作ります。大きさは幅、高さとも0にしておきます。 (自動的に調整してくれる)

REBARBANDINFO構造体の残りのメンバを設定します。

lpText, hwndChild, cxメンバを設定して、RB_INSERTBANDメッセージを送ります。

コンボボックスを作り、lpText, hwndChild, cxメンバを設定します。 そして、RB_INSERTBANDメッセージを送ります。

これで、一応レバーハンドルとその上に乗っているボタン、コンボボックス ができあがりました。

WM_SIZEメッセージが来たら(親の大きさが変わった)レバーハンドルに このメッセージをそっくりそのまま送ります。

WM_PAINTメッセージが来たらszStrを親のクライアント領域に表示します。 この時クライアント領域の上のほうはレバーコントロールで覆われている ことに注意して下さい。

各コントロールからの通知メッセージは親のプロシージャにやってきます。 ここで、やりたい処理を行います。

さて、コンボボックスに選択されている項目が変化した時 InvalidateRect関数で親ウィンドウにWM_PAINメッセージを発生させて クライアント領域の書きなおしをさせていますが、この後 UpdateWindow関数でレバーコントロールも書きなおして下さい。

次にレバーコントロールが1列から2列になったり、この逆のことが 起こるとクライアント領域に表示した文字列も書きなおす必要があります。 そこでレバーコントロールからの通知メッセージを処理します。

RBN_HEIGHTCHANGE lpnmhdr = (LPNMHDR) lParam;

この通知メッセージはレバーコントロールの高さが変化した時送られます。

プログラム終了時一応hBut, hComboを破棄しています。(hRebarが破棄される時 自動的に破棄されるので省略してもよい)

HWND MakeMyRebar(HWND hWnd) { HWND hRebar; REBARINFO rbi; hRebar = CreateWindowEx(WS_EX_TOOLWINDOW, REBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | RBS_BANDBORDERS | WS_CLIPCHILDREN | CCS_NODIVIDER, 0, 0, 0, 0, hWnd, NULL, hInst, NULL); ZeroMemory(&rbi, sizeof(REBARINFO)); rbi.cbSize = sizeof(REBARINFO); SendMessage(hRebar, RB_SETBARINFO, 0, (LPARAM)&rbi); return hRebar; }

レバーコントロールを作る自作関数です。

ウィンドウスタイルからRBS_BANDBORDERSを取り除くと、バンドとバンドの 間の細い境界がなくなります。また、CCS_NODIVIDERを取り除くと タイトルバーとレバーコントロールの間に細い境界が入ります。

HWND MakeMyCombo(HWND hRebar) { HWND hCombo; hCombo = CreateWindow("COMBOBOX", "", WS_CHILD | WS_VISIBLE | CBS_DROPDOWN, 0, 0, 0, 120, hRebar, (HMENU)ID_COMBO, hInst, NULL); SendMessage(hCombo, CB_INSERTSTRING, -1, (LPARAM)"粂井康孝"); SendMessage(hCombo, CB_INSERTSTRING, -1, (LPARAM)"粂井櫻都"); SendMessage(hCombo, CB_INSERTSTRING, -1, (LPARAM)"粂井志麻"); SendMessage(hCombo, CB_INSERTSTRING, -1, (LPARAM)"粂井ひとみ"); SendMessage(hCombo, CB_SETCURSEL, 0, 0); return hCombo; }

コンボボックスを作る自作関数です。ボタンの時は幅、高さとも0に すれば良かったのですが、コンボボックスの場合は高さを0にすると ドロップダウンするリストボックスが表示されません。適当な高さを 指定しておいて下さい。

今回は、ちょっと面倒くさいところもありましたが、プログラム的には そんなに難しいものではありませんでした。


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

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