第62章 ツールバーを作る その2


今回は、TB_ADDBUTTONSメッセージを使ってツールバーボタンを 追加する方法を解説します。同時にいろいろなアプリケーションで よく使われる「新規作成」「開く」ボタンなど既成のボタンの付け方も 解説します。

左の図は見ての通り、左から2つまでが自作のボタンです。 後の4つははじめから用意されているものです。既成のボタンには、 STD系のものと、VIEW系のものがあります。

前者には、コピー、切り取り、削除、新規作成、開く、保存、検索などがあります。 後者には、詳細、大きいアイコンで表示、一覧表示などがあります。 また、それぞれのビットマップには大、小の2種類があります。

STD系のものは、インデックス値がSTD_COPY, STD_CUT, STD_DELETE, STD_NEW, STD_FILEOPEN, STD_FILESAVE, STD_FINDなどとなっています。だいたい想像が つきますね。VIEW系のもののインデックス値はVIEW_DETAILS, VIEW_LARGEICONS, VIEW_LISTなどとなっています。

これらの既成のボタンを組み込む具体的な方法を示します。

まず、TBBUTTON構造体の配列を用意します。

TBBUTTON tbMyButton[] = { {0, IDM_MARU, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0}, {1, IDM_SANKAKU, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0}, {STD_FILENEW, IDM_NEW, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0}, {STD_FILEOPEN, IDM_OPEN, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0}, {STD_DELETE, IDM_DELETE, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0}, {VIEW_PARENTFOLDER, IDM_PARENT, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0} };

とこんな具合になります。最初の2つは、自作のボタンです。 この二つは、前章の方法で組み込みます。従ってTB_ADDBUTTONSメッセージで 組み込むのは残りの4つということになります。

まず、STD系のビットマップをTBADDBITMAP構造体にセットします。

typedef struct { // tbab HINSTANCE hInst; UINT nID; } TBADDBITMAP, *LPTBADDBITMAP;

hInstは、既成のもの(system-defined button bitmaps)であればHINST_COMMCTRLとなります。 nIDは大きいアイコンはIDB_STD_LARGE_COLOR, IDB_VIEW_LARGE_COLORとなります。小さいアイコン の場合は、IDB_STD_SMALL_COLOR, IDB_VIEW_SMALL_COLORとなります。

なお、自作のものを使うときはhInstはNULL、nIDはビットマップIDとなります。TBADDBITMAP 構造体をセットしたなら、TB_ADDBITMAPメッセージを送信します。

TB_ADDBITMAP wParam = (WPARAM) nButtons; lParam = (LPARAM) (LPTBADDBITMAP) lptbab;

nButtonsはボタンイメージの数です。lptbabは、TBADDBITMAP構造体へのポインタです。 これを送信すると、SendMessage関数の戻り値として最初のイメージのインデックスが 戻ってきます。 TBBUTTON構造体のiBitmapメンバにこの値を加えたもの新しいiBitmapメンバにします。 上の例でいえば、STD_FILENEWはtbMyButton[2]のメンバで、iBitmapです。 したがってこの値にTB_ADDBITMAPメッセージの戻り値を足したものをiBitmapと します。

ここまでできたら、後はTB_ADDBUTTONメッセージを送信すれば終わりです。

TB_ADDBUTTONS wParam = (WPARAM) (UINT) uNumButtons; lParam = (LPARAM) (LPTBBUTTON) lpButtons;

uNumButtonsは、加えるボタンの数です。
lpButtonsは、TBBUTTON構造体の配列へのポインタです。



では、サンプルの例題を見てみましょう。

////////////////////////////////////////////////////////////// // // Bitmap // IDB_MYBMP BITMAP DISCARDABLE "mybmp.bmp"

リソーススクリプトです。自前で作る人はwindows.hのインクルードを忘れないでください。

mybmp.bmpです。

// tool0x.cpp #define STRICT #include <windows.h> #include <commctrl.h> #define ID_MYTOOLBAR 102 #define IDB_MYBMP 103 #define IDM_NEW 1000 #define IDM_OPEN 1001 #define IDM_DELETE 1002 #define IDM_PARENT 1003 #define IDM_MARU 1004 #define IDM_SANKAKU 1005 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); BOOL InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); char szClassName[] = "tool0x"; //ウィンドウクラス TBBUTTON tbMyButton[] = { {0, IDM_MARU, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0}, {1, IDM_SANKAKU, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0}, {STD_FILENEW, IDM_NEW, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0}, {STD_FILEOPEN, IDM_OPEN, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0}, {STD_DELETE, IDM_DELETE, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0}, {VIEW_PARENTFOLDER, IDM_PARENT, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0} }; TBBUTTON tbSPACE = {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0L}; int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) { MSG msg; if (!hPrevInst) { if (!InitApp(hCurInst)) return FALSE; } if (!InitInstance(hCurInst, nCmdShow)) { return FALSE; } while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; }

毎度おなじみの注意ですが、commctrl.hのインクルードと comctl32.libのプロジェクトへの参加を忘れないでください。 初期?TBBUTTON構造体の配列は、すでに説明しました。 また、前章同様スペースを入れるためのtbSPACE構造体も別に用意しました。 実は、この構造体はtbMyButton構造体の配列の中に入れてしまってもかまいません。 どのようになるか考えてみてください。

WinMain関数はいつもと同じです。

//ウィンドウ・クラスの登録 BOOL InitApp(HINSTANCE hInst) { WNDCLASS wc; 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; return (RegisterClass(&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, stdid; HINSTANCE hInst; static HWND hToolWnd; TBADDBITMAP tb; switch (msg) { case WM_CREATE: hInst = (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE); InitCommonControls(); hToolWnd = CreateToolbarEx( hWnd, WS_CHILD | WS_VISIBLE, ID_MYTOOLBAR, 2, hInst, IDB_MYBMP, tbMyButton, 2, 0, 0, 0, 0, sizeof(TBBUTTON)); tb.hInst = HINST_COMMCTRL; tb.nID = IDB_STD_SMALL_COLOR; stdid = SendMessage(hToolWnd, TB_ADDBITMAP, 3, (LPARAM)&tb); tbMyButton[2].iBitmap += stdid; tbMyButton[3].iBitmap += stdid; tbMyButton[4].iBitmap += stdid; SendMessage(hToolWnd, TB_ADDBUTTONS, 3, (LONG)&tbMyButton[2]); tb.hInst = HINST_COMMCTRL; tb.nID = IDB_VIEW_SMALL_COLOR; stdid = SendMessage(hToolWnd, TB_ADDBITMAP, 1, (LPARAM)&tb); tbMyButton[5].iBitmap += stdid; SendMessage(hToolWnd, TB_ADDBUTTONS, 1, (LONG)&tbMyButton[5]); SendMessage(hToolWnd, TB_INSERTBUTTON, 2, (LPARAM)&tbSPACE); SendMessage(hToolWnd, TB_INSERTBUTTON, 6, (LPARAM)&tbSPACE); break; case WM_SIZE: SendMessage(hToolWnd, WM_SIZE, wp, lp); break; case WM_COMMAND: switch(LOWORD(wp)){ case IDM_MARU: case IDM_SANKAKU: case IDM_NEW: case IDM_OPEN: case IDM_DELETE: case IDM_PARENT: MessageBox(hWnd, "ボタンが押されました!", "!", MB_OK); break; } break; case WM_CLOSE: id = MessageBox(hWnd, (LPCSTR)"終了してもよいですか", (LPCSTR)"終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { DestroyWindow(hWnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0L; }

さて、TB_INSERTBUTTONメッセージを送信しないと0番から5番までの 6つのボタンが隙間なく横1列に並びます。隙間を入れたいのは2番の左と 5番の左側です。

最初の隙間は

SendMessage(hToolWnd, TB_INSERTBUTTON, 2, (LPARAM)&tbSPACE);

で文句はないでしょう。では次の隙間は

SendMessage(hToolWnd, TB_INSERTBUTTON, 5, (LPARAM)&tbSPACE);

でしょうか?
答えはNOです。最初のTB_INSERTBUTTONメッセージでもう隙間が入ってしまっているので 目的の場所は1つずれます。

SendMessage(hToolWnd, TB_INSERTBUTTON, 6, (LPARAM)&tbSPACE); が正解です。


[SDK Index] [総合Index] [Previous Chapter] [Next Chapter]

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