第194章 拡張コンボボックス


今回は拡張コンボボックスについて解説します。 新しいコモンコントロールのひとつで、最大の特徴は アイテムにイメージをつけることができる点です。 また、ドロップダウンしたリストにインデントをつけることもできます。



左の図のようにアイテムにイメージを関連付けたり、インデントを つけることができます。選択されたアイテムのイメージを変えることもできます。 (フォントの変更は従来のコンボボックスでもできます。) VC++6.0ではリソース・エディタで作ることもできます。



作り方は比較的簡単です。

0.コモンコントロールの準備   INITCOMMONCONTROLSEX構造体のdwICCメンバはICC_USEREX_CLASSES   にします。 1.ウィンドウクラスをWC_COMBOBOXEXとしてCreateWindowEx関数で作ります。(hCombo) 2.イメージリストを用意します。(hImg) 3.hComboにCBEM_SETIMAGELISTメッセージを送ります。 4.COMBOBOXEXITEM構造体のメンバをセットしてCBEM_INSERTITEMメッセージを送ります。

これで、拡張コンボボックスに1つアイテムを追加することができます。 4.を繰り返すことによりアイテムを追加していきます。

CBEM_SETIMAGELIST wParam = 0; lParam = (LPARAM)(HIMAGELIST) himl;

himlはコントロールにセットするイメージリストのハンドルです。 イメージリストについて忘れてしまった方は 第70章を参照して下さい。

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

typedef struct { UINT mask; int iItem; LPTSTR pszText; int cchTextMax; int iImage; int iSelectedImage; int iOverlay; int iIndent; LPARAM lParam; } COMBOBOXEXITEM, *PCOMBOBOXEXITEM;

maskはこの構造体で使用するメンバを指定します。
CBEIF_DI_SETITEMCBEN_GETDISINFO通知メッセージを使う時のみ
CBEIF_IMAGEiImageメンバが有効
CBEIF_INDENTiIndentメンバが有効
CBEIF_LPARAMlParamメンバが有効
CBEIF_OVERLAYiOverlayメンバが有効
CBEIF_SELECTEDIMAGEiSelectedImageメンバが有効
CBEIF_TEXTpszTextメンバが有効

iItemはアイテムのインデックスです。(0から始まる)

pszTextはアイテムのテキストバッファのアドレスです。もしくは アイテムのテキストを取得するためのバッファのアドレスです。 この場合はバッファのサイズをcchTextMaxに指定しなくてはいけません。

cchTextMaxはpszTextの長さですがテキスト情報がセットされている時は 無視されます。

iImageはイメージリストのインデックスです。(0から始まる)

iSelectedImageはアイテムが選択された時のイメージリストのインデックスです。

iOverlayはオーバーレイイメージのインデックスです。(1から始まる)

iIndentはインデントスペースです。

lParamはアイテム固有の32ビット値です。

では、プログラムをみてみることにします。まず、

のようなビットマップを用意します(mybmp.bmp)。マスクする部分をイメージで使っていない 色(この場合「白」です)で塗りつぶしておいて下さい。 一区画の大きさは16*15にしてあります。 2区画ずつが組になっており、最初の区画が選択されていない時、後の区画が選択された時 のイメージとなります。左から順に0,1,..5番となります。 イメージエディタで作ってもよいのですが、面倒くさいので筆者はツールバーを 作る要領でリソース・エディタに作らせています。後から「挿入」「リソース」「インポート」 でこのビットマップをリソースとしてプロジェクトに参加させます。 この時の名前を"MYBMP"にしておいて下さい。

// comboex1.rcの一部 ///////////////////////////////////////////////////////////////////////////// // // Dialog // MYDLG DIALOG DISCARDABLE 0, 0, 99, 89 STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "新しいコンボボックス" FONT 9, "MS Pゴシック" BEGIN DEFPUSHBUTTON "OK",IDOK,7,68,41,14 PUSHBUTTON "キャンセル",IDCANCEL,50,68,41,14 END ///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "終了(&X)", IDM_END END POPUP "オプション(&O)" BEGIN MENUITEM "ダイアログを出す(&D)", IDM_DLG END END ///////////////////////////////////////////////////////////////////////////// // // Bitmap // MYBMP BITMAP DISCARDABLE "mybmp.bmp"

ダイアログボックスにはコンボボックスがないことに注意して下さい。

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

いつもと同じですが、インスタンスハンドルのグローバル変数が あることに注意して下さい。

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 = "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; switch (msg) { case WM_COMMAND: switch (LOWORD(wp)) { case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; case IDM_DLG: 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; }

メニューからIDM_DLGが選択されたらダイアログボックスを出します。

LRESULT CALLBACK MyDlgProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp) { static HWND hCombo; static HIMAGELIST hImg; int nIndex; INITCOMMONCONTROLSEX ic; COMBOBOXEXITEM citem; static HFONT hFont; TCHAR szStr[256]; switch (msg) { case WM_INITDIALOG: ic.dwSize = sizeof(INITCOMMONCONTROLSEX); ic.dwICC = ICC_USEREX_CLASSES; InitCommonControlsEx(&ic); hCombo = CreateWindowEx(0, WC_COMBOBOXEX, "", WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST, 5, 5, 150, 200, hDlg, (HMENU)100, hInst, NULL); hFont = CreateFont(20, 0, 0, 0, FW_NORMAL, FALSE, FALSE, 0, SHIFTJIS_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "DF勘亭流"); SendMessage(hCombo, WM_SETFONT, (WPARAM)hFont, 0); hImg = ImageList_LoadBitmap(hInst, "MYBMP", 16, 15, RGB(255, 255, 255)); if (hImg == NULL) MessageBox(hDlg, "hImg Error", "OK", MB_OK); SendMessage(hCombo, CBEM_SETIMAGELIST, 0, (LPARAM)hImg); citem.mask = CBEIF_TEXT | CBEIF_INDENT | CBEIF_IMAGE | CBEIF_SELECTEDIMAGE; citem.pszText = "粂井"; citem.iItem = 0; citem.iIndent = 0; citem.iImage = 0; citem.iSelectedImage = 1; SendMessage(hCombo, CBEM_INSERTITEM, 0, (LPARAM)&citem); citem.pszText = "康孝"; citem.iItem = 1; citem.iIndent = 1; citem.iImage = 2; citem.iSelectedImage = 3; SendMessage(hCombo, CBEM_INSERTITEM, 0, (LPARAM)&citem); citem.pszText = "ひとみ"; citem.iItem = 2; citem.iIndent = 2; citem.iImage = 4; citem.iSelectedImage = 5; SendMessage(hCombo, CBEM_INSERTITEM, 0, (LPARAM)&citem); SendMessage(hCombo, CB_SETCURSEL, (WPARAM)0, 0); return TRUE; case WM_COMMAND: switch (LOWORD(wp)) { case IDOK: nIndex = SendMessage(hCombo, CB_GETCURSEL, 0, 0); wsprintf(szStr, "選択されたのは %d番のアイテムです", nIndex); MessageBox(hDlg, szStr, "選択完了", MB_OK); ImageList_Destroy(hImg); DeleteObject(hFont); EndDialog(hDlg, IDOK); return TRUE; case IDCANCEL: ImageList_Destroy(hImg); DeleteObject(hFont); EndDialog(hDlg, IDCANCEL); return TRUE; default: return FALSE; } return FALSE; } return FALSE; }

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

WM_INITDIALOGのところで、コモンコントロールを初期化して CreateWindowEx関数で拡張コンボボックスを作ります。 この時拡張コンボボックスのIDを1とか2にするのは 避けて下さい。と、いうのもコントロールのIDはWM_COMMANDメッセージ でこれが参照されるからです。IDOKは1、IDCANCELは2とwinuser.h で定義されているので、混乱が起きます。ためしに、拡張コンボボックス のIDを1とするとアイテムを選択しただけで、ダイアログボックスが 終了してしまいます。

次におまけとして、拡張コンボボックスにWM_SETFONTメッセージを 送ってフォントを変更しています。これは、従来のコンボボックスでも 可能です。

WM_SETFONT wParam = (WPARAM) hfont; lParam = MAKELPARAM(fRedraw, 0);

このメッセージを送ることによりコントロールのフォントを変更できます。

hfontはフォントのハンドルです。

fRedrawはフォントがセットされたら直ちにコントロールを再描画するかどうか を指定します。TRUEなら直ちに再描画します。

ImageList_LoadBitmapの最後の引数はビットマップを作った時マスク領域を 塗りつぶした色(この場合「白」)を指定します。あとは順番に アイテムを挿入していきます。

拡張コンボボックスでもCB_SETCURSELメッセージは使用可能です。

OKボタンが押されたらCB_GETCURSELボタンで選択されている アイテムのインデックスを取得します。

ダイアログボックスを破棄する時にイメージリストとフォントハンドルを 破棄するのを忘れないでください。


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

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