第66章 ツールチップを付ける別の方法


今回は、表題の通りツールチップを付ける別の方法を解説します。 今回は、ツールチップをCreateWindowEx関数で作ります。 ウィンドウクラス名をTOOLTIPS_CLASS とします。ウィンドウスタイルはTTS_ALWAYSTIP にします。あとは、次の例を見てください。

hToolTip = CreateWindowEx( 0, //拡張ウィンドウスタイル TOOLTIPS_CLASS, //クラスネーム NULL, //ウィンドウネーム TTS_ALWAYSTIP, // ウィンドウスタイル CW_USEDEFAULT, // X座標 CW_USEDEFAULT, // Y座標 CW_USEDEFAULT, // 幅 CW_USEDEFAULT, // 高さ hWnd, // 親ウィンドウのハンドル NULL, // メニューハンドル hInstance, // インスタンスハンドル NULL); // WM_CREATEデータ

次に、TOOLINFO構造体を初期化します。

typedef struct { // ti UINT cbSize; UINT uFlags; HWND hwnd; UINT uId; RECT rect; HINSTANCE hinst; LPTSTR lpszText; } TOOLINFO, NEAR *PTOOLINFO, FAR *LPTOOLINFO;

cbSizeはこの構造体のサイズです。
uFlagは、TTF_CENTERTIP, TTF_IDISHWND, TTF_SUBCLASSなどから 1つまたはそれ以上の組み合わせを選択します。 ここでは、TTF_SUBCLASSを使います。
これは、ツールのウィンドウをサブクラス化してマウスのメッセージを 処理してくれることを意味しています。

hwndは、ツールのウィンドウハンドルです。ツールバーに ツールチップを付けたいのなら、ここはツールバーのウィンドウハンドルです。 うっかり、ツールチップのハンドルを指定してはいけません。 筆者はうっかりツールチップのハンドルを指定したため、 大変面倒なことになりました。

uIdは、ツールのアプリケーション定義識別子です。(関連づけるボタンのID)または、 uFlagにTTF_IDISHWNDが入っていれば、ツールのウィンドウハンドル。

rectは、ツールの境界の四角形領域。

hinstは、文字列リソースの入っているモジュールのインスタンス。

lpszTextは、文字列リソースの識別子。

ここで、rectメンバは、TB_GETITEMRECTメッセージを使って取得します。

TB_GETITEMRECT wParam = (WPARAM) iButton; lParam = (LPARAM) (LPRECT) lprc;

iButtonは、ボタンのインデックス。

lprcは、受け取るRECT構造体のポインタです。

TOOLINFO構造体をセットしたら、TTM_ADDTOOLメッセージで ツールチップをツールに登録します。

TTM_ADDTOOL wParam = 0; lParam = (LPARAM) (LPTOOLINFO) lpti;

最後に、TB_SETTOOLTIPSメッセージでツールチップコントロールを ツールバーに関連づけます。

TB_SETTOOLTIPS wParam = (WPARAM) (HWND) hwndToolTip; lParam = 0;

さて、こう見ると簡単そうに見えますが、実際プログラムを 書くと結構面倒なことが起こります。 前章でやったようにストリングテーブルのIDと WM_COMMANDで受け取るIDを別々に設定すると 面倒くさいです。文字列リソースのIDとWM_COMMANDで受け取る IDを同じにするとプログラムが楽です。(例題のように 文字列リソースのIDをIDM_何とかにする)

では、例題を見てみることにします。

左から、12個までがSTD系のボタン、右端がVIEW系のボタンです。 左の図では、マウスカーソルは表示されていませんが実際はバツ印 のボタンをポイントしています。

// thint01.h #define ID_MYTOOLBAR 2000

今回は、リソースエジタにリソースを作らせたので 自前のヘッダーファイルの中身はこれだけです。

// resource.hの一部 // 自前で作る人はこれを全部thint01.hに加えてください #define IDM_COPY 1 #define IDM_DELETE 2 #define IDM_CUT 3 #define IDM_NEW 4 #define IDM_OPEN 5 #define IDM_SAVE 6 #define IDM_FIND 7 #define IDM_HELP 8 #define IDM_PASTE 9 #define IDM_DETAILS 10 #define IDM_PRINT 11 #define IDM_REDOW 12 #define IDM_REPLACE 13

次に、リソーススクリプトです。

// thint01.rc // 自分で作る人はwindows.hとthint01.hをインクルードしてください。 ///////////////////////////////////////////////////////////////////////////// // // String Table // STRINGTABLE DISCARDABLE BEGIN IDM_COPY "コピーします" IDM_DELETE "削除します" IDM_CUT "切り取ります" IDM_NEW "新規ファイル作成" IDM_OPEN "ファイルをオープンします" IDM_SAVE "保存します" IDM_FIND "検索をします" IDM_HELP "ヘルプです" IDM_PASTE "貼り付け" IDM_DETAILS "詳細表示" IDM_PRINT "印刷をします" IDM_REDOW "元に戻します" IDM_REPLACE "置き換え"

ストリングテーブルのIDは、ボタンが押されたときにWM_COMMANDで処理される IDと同じになっています。(前章と比較してください。)

// thint01.cpp #define STRICT #include <windows.h> #include <commctrl.h> #include "thint01.h" #include "resource.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); BOOL InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); HWND CreateMyToolWnd(HWND); char szClassName[] = "thint01"; //ウィンドウクラス HINSTANCE hInstance; TBBUTTON tbb[] = { {STD_COPY, IDM_COPY, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0}, {STD_CUT, IDM_CUT, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0}, {STD_DELETE, IDM_DELETE, 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_FILESAVE, IDM_SAVE, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0}, {STD_FIND, IDM_FIND, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0}, {STD_HELP, IDM_HELP, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0}, {STD_PASTE, IDM_PASTE, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0}, {STD_PRINT, IDM_PRINT, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0}, {STD_REDOW, IDM_REDOW, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0}, {STD_REPLACE, IDM_REPLACE, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0}, {VIEW_DETAILS, IDM_DETAILS, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0} }; int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) { MSG msg; if (!hPrevInst) { if (!InitApp(hCurInst)) return FALSE; } // インスタンスをグローバル変数に保存 hInstance = hCurInst; if (!InitInstance(hCurInst, nCmdShow)) { return FALSE; } while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; }

後で便利なように、グローバル変数にインスタンスハンドルを保存している ことに注意してください。 コモンコントロールを使うときの注意はいつもと同じです。

//ウィンドウ・クラスの登録 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; static HWND hToolWnd; switch (msg) { case WM_CREATE: hToolWnd = CreateMyToolWnd(hWnd); break; case WM_SIZE: SendMessage(hToolWnd, WM_SIZE, wp, lp); break; case WM_COMMAND: MessageBox(hWnd, "ボタンが押されました!", "BUTTON", MB_OK | MB_ICONEXCLAMATION); 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; }

親ウィンドウが作られたらすぐにツールバーと、ツールチップを作ります。 ボタンが押されたときの処理は、メッセージボックスで「ボタンが押されました」 と表示するだけです。

前章のようにTTN_NEEDTEXTメッセージを処理していない 点に注意してください。

HWND CreateMyToolWnd(HWND hWnd) { HWND hTool, hToolTip; static TBADDBITMAP tbab; static TOOLINFO ti; static int stdid, id; InitCommonControls(); // ツールバーを作る hTool = CreateToolbarEx( hWnd, WS_CHILD | WS_VISIBLE, ID_MYTOOLBAR, 12, (HINSTANCE)HINST_COMMCTRL, IDB_STD_LARGE_COLOR, (LPCTBBUTTON)tbb, 12, 0, 0, 0, 0, sizeof(TBBUTTON)); tbab.hInst = HINST_COMMCTRL; tbab.nID = IDB_VIEW_LARGE_COLOR; stdid = SendMessage(hTool, TB_ADDBITMAP, 1, (LPARAM)&tbab); for (id = 12; id <= 12; id++) { tbb[id].iBitmap += stdid; } SendMessage(hTool, TB_ADDBUTTONS, 1, (LPARAM)&tbb[12]); SendMessage(hTool, TB_AUTOSIZE, 0, 0); // ツールチップを作る hToolTip = CreateWindowEx( 0, //拡張ウィンドウスタイル TOOLTIPS_CLASS, //クラスネーム NULL, //ウィンドウネーム TTS_ALWAYSTIP, // ウィンドウスタイル CW_USEDEFAULT, // X座標 CW_USEDEFAULT, // Y座標 CW_USEDEFAULT, // 幅 CW_USEDEFAULT, // 高さ hWnd, // 親ウィンドウのハンドル NULL, // メニューハンドル hInstance, // インスタンスハンドル NULL); // WM_CREATEデータ ti.cbSize = sizeof(TOOLINFO); ti.hwnd = hTool; ti.hinst = hInstance; ti.uFlags = TTF_SUBCLASS; for (id = 0; id <= 12; id++) { SendMessage(hTool, TB_GETITEMRECT, id, (LPARAM)&ti.rect); ti.uId = tbb[id].idCommand; ti.lpszText = (LPTSTR)tbb[id].idCommand; SendMessage(hToolTip, TTM_ADDTOOL, 0, (LPARAM)&ti); } SendMessage(hTool, TB_SETTOOLTIPS, (WPARAM)hToolTip, 0); return hTool; }

STD系のボタンは、CreateToolbarExで作ってしまい、残った VIEW系のボタンはTB_ADDBUTTONSメッセージで作っている(付け加えている) 点に注意してください。違う系のボタンを混在させるときは 間違えやすいので特に注意が必要です。

ツールチップは、最初に解説したように設定します。 TOOLINFO構造体のuFlagsをTTF_SUBCLASSに設定しているので TTN_NEEDTEXTメッセージの処理が不要になっています。


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

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