インターネット・エクスプローラ(IE)のメニュー・バーを見てください。
一見通常のメニュー・バーのように見えますが大きく違うところがあります。
それは、「取っ手」がついていて、別の段に移動したり、他のレバーバンドを
メニューと同じ段に移動したりできる点です。ちょっと考えるとツールバーとレバーコントロールで実現できそうに思われます。 しかし、実際にはいろいろ面倒なことが起こります。今回はIE様メニュー・バーを試作して 問題点を洗い出してみます。
イメージ無しのツールバーを作って、これをレバーコントロールにのせます。
そして、ボタンがクリックされるとTrackPopupMenu関数でサブメニューを表示します。
これでは、ポップアップメニューが出たときに、「挿入」ボタンが押されていない
状態になってしまいます。これは、TB_SETSTATEメッセージで解決できます。
現段階では、ポップアップメニューが出た段階で左右のカーソルキーを押しても反応しません。 (IEでは通常のメニューのように反応します。)また、ALTキーを押しても反応しません。
メニュー・バーを移動することもできます。また、表示しきれないときは
シェブロンを出します。
では、具体的に作り方を考えてみます。dllのバージョンは5.81以降が
必要です。IE5.0以降がインストールされていれば大丈夫です。また、
生のVC++6.0ではコンパイルできません。SPをインストールしてもヘッダファイルや
ライブラリは更新されないので、マイクロソフトのページなどから
プラットフォームSDKを更新する必要があります。
TBBUTTON tbButtonMenu[] = {
{I_IMAGENONE, IDM_FILE, TBSTATE_ENABLED, TBSTYLE_BUTTON | BTNS_AUTOSIZE, 0, 0, 0},
{I_IMAGENONE, IDM_EDIT, TBSTATE_ENABLED, TBSTYLE_BUTTON | BTNS_AUTOSIZE, 0, 0, 0},
{I_IMAGENONE, IDM_INSERT, TBSTATE_ENABLED, TBSTYLE_BUTTON | BTNS_AUTOSIZE, 0, 0, 0},
{I_IMAGENONE, IDM_BRVIEW, TBSTATE_ENABLED, TBSTYLE_BUTTON | BTNS_AUTOSIZE, 0, 0, 0},
{I_IMAGENONE, IDM_OPTION, TBSTATE_ENABLED, TBSTYLE_BUTTON | BTNS_AUTOSIZE, 0, 0, 0}
};
と、こんな感じになります。「ファイル」「編集」などのメニュー項目の文字はiStringメンバに
設定することになります。ここでは、まだ0にしておきます。
左の図のように表示したいメニュー項目をテーブルに設定します。
ストリングテーブルについては第64章を参照してください。
hTool = CreateToolbarEx(hRebar, //親ウィンドウ
WS_CHILD | WS_VISIBLE | CCS_NODIVIDER |
CCS_NORESIZE | TBSTYLE_LIST | TBSTYLE_FLAT, //ウィンドウスタイル
ID_TOOLMENU, //ID
0, //ボタンイメージの数
NULL,//hInst, //ビットマップリソースの入っているモジュール
NULL,//IDR_TOOLBAR1, //ビットマップリソースのID
tbButtonMenu, //TBBUTTON構造体のアドレス
0, //ツールバーに加えるボタンの数
0, 0, 0, 0, //ボタンの幅、高さ、イメージの幅、高さ
sizeof(TBBUTTON)); //TBBUTTON構造体の大きさ
と、こんな感じになります。ヘルプによるとスタイルにさらにTBSTYLE_DROPDOWNを
加えて通知メッセージTBN_DROPDOWNを捕まえる処理を推奨していますが、ここでは、これを加えないで
WM_COMMANDメッセージで何とかします。
LoadString(hInst, IDS_FILE, szBuf, sizeof(szBuf) - 1);
iFile = SendMessage(hTool, TB_ADDSTRING, 0, (LPARAM)szBuf);
tbButtonMenu[0].iString = iFile;
というような感じで、ストリングテーブルから文字列を読み出して、ツールバーに加えます。文字列をセットし終わったら、
SendMessage(hTool, TB_ADDBUTTONS, 5, (LPARAM)tbButtonMenu);で完成です。ツールバーができても、これをレバーコントロールにのせなくてはいけません。
rbinfo.cbSize = sizeof(REBARBANDINFO);
rbinfo.fMask = RBBIM_STYLE | RBBIM_CHILD | RBBIM_CHILDSIZE |
RBBIM_SIZE | RBBIM_IDEALSIZE;
rbinfo.fStyle = RBBS_CHILDEDGE | RBBS_USECHEVRON;
rbinfo.hwndChild = hToolMenuW;
rbinfo.cxMinChild = 0;
rbinfo.cyMinChild = 22;
rbinfo.cxIdeal = 280;
rbinfo.cx = 280;
SendMessage(hRebar, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rbinfo);
と、いう感じでレバーコントロールにのせます。cxIdealメンバの値は、メニュー項目が
ちょうど全部あらわれる長さです。これより短くなるとシェブロンが出てきます。
ここでは、TBSTYLE_DROPDOWNを設定していないので、通常のメニューのように WM_COMMANDメッセージが来たときにLOWORD(wParam)で場合分けして、 IDM_FILE, IDM_EDITなどを捕まえます。
switch (msg) {
...
case WM_COMMAND:
switch (LOWORD(wp)) {
...
case IDM_FILE:
ShowMyPopMenu(hWnd, hToolMenuW, "MYMENU", 0, hEdit, hTool2);
break;
case IDM_EDIT:
ShowMyPopMenu(hWnd, hToolMenuW, "MYMENU", 1, hEdit, hTool2);
break;
...
ここでは、以前に使った通常のメニューのリソース("MYMENU")を再利用しています。ShowMyPopMenu関数の中身は想像がつくと思いますが、TrackPopupMenu関数を呼び出す前に TB_SETSTATEメッセージを使ってボタンが押されたままの状態を作らなくてはいけません。 この時、LPARAMの値をMAKELONG(TBSTATE_PRESSED,0)にすると、ボタンが灰色表示されてしまいます。
MAKELONG(TBSTATE_ENABLED | TBSTATE_PRESSED, 0)
にしなくてはいけませんね。TrackPopupMenu関数のあとでまた、ボタンを元に戻すのを 忘れないでください。
シェブロンが押されたときのメニューはトップレベルのメニュー項目は
ダミーです。
具体的なプログラムは次章で解説します。
Update 02/Jul/2001 By Y.Kumei