第311章 IE様メニューの試作 その1


インターネット・エクスプローラ(IE)のメニュー・バーを見てください。 一見通常のメニュー・バーのように見えますが大きく違うところがあります。 それは、「取っ手」がついていて、別の段に移動したり、他のレバーバンドを メニューと同じ段に移動したりできる点です。

ちょっと考えるとツールバーとレバーコントロールで実現できそうに思われます。 しかし、実際にはいろいろ面倒なことが起こります。今回はIE様メニュー・バーを試作して 問題点を洗い出してみます。



イメージ無しのツールバーを作って、これをレバーコントロールにのせます。 そして、ボタンがクリックされるとTrackPopupMenu関数でサブメニューを表示します。 これでは、ポップアップメニューが出たときに、「挿入」ボタンが押されていない 状態になってしまいます。これは、TB_SETSTATEメッセージで解決できます。

現段階では、ポップアップメニューが出た段階で左右のカーソルキーを押しても反応しません。 (IEでは通常のメニューのように反応します。)また、ALTキーを押しても反応しません。


メニュー・バーを移動することもできます。また、表示しきれないときは シェブロンを出します。



では、具体的に作り方を考えてみます。dllのバージョンは5.81以降が 必要です。IE5.0以降がインストールされていれば大丈夫です。また、 生のVC++6.0ではコンパイルできません。SPをインストールしてもヘッダファイルや ライブラリは更新されないので、マイクロソフトのページなどから プラットフォームSDKを更新する必要があります。

TBBUTTON構造体のセット

通常のツールバーを作るときと同様にTBBUTTON構造体を用意します。
最初のメンバはI_IMAGENONEにします。
次のメンバはコマンドIDとなりますが、今まではこのIDはなかったので 新規に適当なIDを作ります。また、リソース・エディタは使わないので このIDに適当な番号を割り付ける必要があります。ここでは、htmledit.hに defineすることにしました。
また、ボタンスタイルにBTNS_AUTOSIZEを加えないと、みっともない状態となります。
ボタンスタイルは、今まではTBSTYLE_XXXで表しましたがバージョン5.80以降は BTNS_XXXで表します。従来のTBSTYLE_XXXも使用可能です。

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章を参照してください。



ツールバーを作る

通常のツールバーと同様にしますが、スタイルに必ずTBSTYLE_LISTとTBSTYLE_FLATを 加えます。

    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メンバの値は、メニュー項目が ちょうど全部あらわれる長さです。これより短くなるとシェブロンが出てきます。

ツールバーのボタン(メニュー項目)が押されたときの処理

ツールバーのボタンが押されたら自前でTrackPopupMenu関数を使って ポップアップメニュー(サブメニュー)を出す必要があります。

ここでは、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自作関数の最初の引数は親ウィンドウのハンドル、2番目の引数はメニュー用の ツールバーのハンドル、3番目の引数はメニューリソースの名前、4番目はどのサブメニューを 表示するかの指定、5番め、6番目はこの関数のなかからCheckMyMenu(メニュー項目を 使用可能・不能にする自作関数)を呼び出すために 仕方なく付け加えたものです。

ShowMyPopMenu関数の中身は想像がつくと思いますが、TrackPopupMenu関数を呼び出す前に TB_SETSTATEメッセージを使ってボタンが押されたままの状態を作らなくてはいけません。 この時、LPARAMの値をMAKELONG(TBSTATE_PRESSED,0)にすると、ボタンが灰色表示されてしまいます。

MAKELONG(TBSTATE_ENABLED | TBSTATE_PRESSED, 0)

にしなくてはいけませんね。TrackPopupMenu関数のあとでまた、ボタンを元に戻すのを 忘れないでください。

シェブロンがクリックされたときの処理

これは、第309章と同様です。RBN_CHEVRONPUSHED通知メッセージを捕まえて ポップアップメニューを出します。ここでは、簡単のためにメニューリソースを 新たに作りした("MYMENU2")。無駄なような気もしますが、"MYMENU"を再利用するとなると 結構面倒くさいので新規に作った方が簡単です。

シェブロンが押されたときのメニューはトップレベルのメニュー項目は ダミーです。



具体的なプログラムは次章で解説します。


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

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