←HSPハック トップへ

IE風メニューバーを作る 1

IE風メニューバーを作ります。

最終更新:2017/12/02

初版:2017/12/02




はじめに


Internet Explorerのメニューバーは通常のメニューと異なり、ウィンドウの上端に張り付いていませんし、左端にドラッグ移動が可能なグリップが付いています。
msdnにIE風メニューバーを作成する手順が載っているドキュメント(英語)があったので、それを参考にしながら作ります。


手順


この章では基本的な実装をします。
  1. レバーコントロールを作成する
  2. ツールバーを作成し、TNS_DROPDOWNスタイルのボタンを追加する
  3. レバーコントロールにツールバーを乗せる
  4. TBN_DROPDOWN 通知が送信されたらメニューが表示されるようにする

レバーコントロールを作成する


winobj命令でレバーコントロールを作成します。
ウィンドウスタイルには、WS_CHILD、WS_VISIBLE、WS_CLIPSIBLINGS、WS_CLIPCHILDREN、RBS_BANDBORDERS、RBS_VARHEIGHTを指定します。

ツールバーを作成し、TNS_DROPDOWNスタイルのボタンを追加する


winobj命令でツールバーを作成します。
ウィンドウスタイルには、WS_CHILD、WS_VISIBLE、WS_CLIPSIBLINGS、WS_CLIPCHILDREN、TBSTYLE_TRANSPARENT、TBSTYLE_REGISTERDROP、TBSTYLE_CUSTOMERASE、TBSTYLE_LIST、TBSTYLE_FLAT、CCS_NODIVIDER、CCS_NOPARENTALIGN、CCS_NORESIZE、CCS_TOPを指定します。

作成できたら、TBBUTTON 構造体を用意します。
TBBUTTON構造体は以下のように定義されています。
typedef struct {
  int       iBitmap;
  int       idCommand;
  BYTE      fsState;
  BYTE      fsStyle;
  DWORD_PTR dwData;
  INT_PTR   iString;
} TBBUTTON, *PTBBUTTON, *LPTBBUTTON;
fsStyleにはI_IMAGENONEを指定します。
fsStyleにはBTNS_DROPDOWNとBTNS_AUTOSIZEを指定します。BTNS_AUTOSIZEを指定することで、文字列の幅に合わせたボタンの幅になるように調整されます。
iStringにボタンの文字列へのポインタを指定します。
指定したら、ツールバーにTB_ADDBUTTONSメッセージを送信してボタンを追加します。

BTNS_DROPDOWNを指定することでボタンの右端に「▼」マークが表示されますが、それはカスタムドローで隠せるため問題ありません。 → ツールバーにTBSTYLE_EX_DRAWDDARROWSを指定せずTB_SETEXTENDEDSTYLEメッセージを送信すれば表示されません。

レバーコントロールにツールバーを乗せる


レバーコントロールにRB_INSERTBANDメッセージを送信することでできます。 lParamには、REBARBANDINFO構造体へのポインタを指定します。
REBARBANDINFO構造体は以下のように定義されています。
typedef struct {
  UINT     cbSize;
  UINT     fMask;
  UINT     fStyle;
  COLORREF clrFore;
  COLORREF clrBack;
  LPTSTR   lpText;
  UINT     cch;
  int      iImage;
  HWND     hwndChild;
  UINT     cxMinChild;
  UINT     cyMinChild;
  UINT     cx;
  HBITMAP  hbmBack;
  UINT     wID;
  UINT     cyChild;
  UINT     cyMaxChild;
  UINT     cyIntegral;
  UINT     cxIdeal;
  LPARAM   lParam;
  UINT     cxHeader;
  RECT     rcChevronLocation;
  UINT     uChevronState;
} REBARBANDINFO, *LPREBARBANDINFO;
cbSizeに構造体のサイズ、88を指定します。
fMaskに使用するメンバが有効であるかを示すフラグを指定します。今回はRBBIM_STYLE、RBBIM_SIZE、RBBIM_CHILD、RBBIM_CHILDSIZE、RBBIM_IDを指定します。
fStyleにスタイルを指定します。RBBS_BREAK、RBBS_GRIPPERALWAYSを指定します。
hwndChildにレバーコントロールに乗せるウィンドウのハンドルを指定します。今回はツールバーのウィンドウハンドルを指定します。
cyMinChildにはバンドの最小の高さを指定します。

TBN_DROPDOWN 通知が送信されたらメニューが表示されるようにする


ツールバーのボタンがクリックされると、通知コードがTBN_DROPDOWNのWM_NOTIFYメッセージが送信されます。
受信できたらクリックされたボタンに対応するメニューをTrackPopupMenuEx関数で表示させます。

ソースコード


このサンプルでは、メッセージが受信されたら、直ちに別の関数を呼ぶようにしています。(ウィンドウメッセージを処理しているときにウィンドウメッセージが来た場合、iparam、wparam、lparam値が上書きされるためです。)
#include "user32.as"

#define RBS_TOOLTIPS        0x00000100
#define RBS_VARHEIGHT       0x00000200
#define RBS_BANDBORDERS     0x00000400
#define RBS_FIXEDORDER      0x00000800
#define RBS_REGISTERDROP    0x00001000
#define RBS_AUTOSIZE        0x00002000
#define RBS_VERTICALGRIPPER 0x00004000 
#define RBS_DBLCLKTOGGLE    0x00008000

#define TBSTYLE_ALTDRAG               0x00000400
#define TBSTYLE_AUTOSIZE              0x00000010
#define TBSTYLE_BUTTON                0x00000000
#define TBSTYLE_CHECK                 0x00000002
#define TBSTYLE_CHECKGROUP            0x00000006
#define TBSTYLE_CUSTOMERASE           0x00002000
#define TBSTYLE_DROPDOWN              0x00000008
#define TBSTYLE_EX_DRAWDDARROWS       0x00000001
#define TBSTYLE_EX_HIDECLIPPEDBUTTONS 0x00000010
#define TBSTYLE_EX_MIXEDBUTTONS       0x00000008
#define TBSTYLE_FLAT                  0x00000800
#define TBSTYLE_GROUP                 0x00000004
#define TBSTYLE_LIST                  0x00001000
#define TBSTYLE_NOPREFIX              0x00000020
#define TBSTYLE_REGISTERDROP          0x00004000
#define TBSTYLE_SEP                   0x00000001
#define TBSTYLE_TOOLTIPS              0x00000100
#define TBSTYLE_TRANSPARENT           0x00008000
#define TBSTYLE_WRAPABLE              0x00000200

#define CCS_ADJUSTABLE      0x00000020
#define CCS_BOTTOM          0x00000003
#define CCS_LEFT            0x00000081
#define CCS_NODIVIDER       0x00000040
#define CCS_NOMOVEX         0x00000082
#define CCS_NOMOVEY         0x00000002
#define CCS_NOPARENTALIGN   0x00000008
#define CCS_NORESIZE        0x00000004
#define CCS_RIGHT           0x00000083
#define CCS_TOP             0x00000001
#define CCS_VERT            0x00000080

#define RBBIM_STYLE         0x00000001
#define RBBIM_COLORS        0x00000002
#define RBBIM_TEXT          0x00000004
#define RBBIM_IMAGE         0x00000008
#define RBBIM_CHILD         0x00000010
#define RBBIM_CHILDSIZE     0x00000020
#define RBBIM_SIZE          0x00000040
#define RBBIM_BACKGROUND    0x00000080
#define RBBIM_ID            0x00000100
#define RBBIM_IDEALSIZE     0x00000200
#define RBBIM_LPARAM        0x00000400
#define RBBIM_HEADERSIZE    0x00000800
#define RBBIM_CHEVRONLOCATION 0x00001000
#define RBBIM_CHEVRONSTATE  0x00002000

#define RBBS_BREAK          0x00000001
#define RBBS_FIXEDSIZE      0x00000002
#define RBBS_CHILDEDGE      0x00000004
#define RBBS_HIDDEN         0x00000008
#define RBBS_NOVERT         0x00000010
#define RBBS_FIXEDBMP       0x00000020
#define RBBS_VARIABLEHEIGHT 0x00000040
#define RBBS_GRIPPERALWAYS  0x00000080
#define RBBS_NOGRIPPER      0x00000100
#define RBBS_USECHEVRON     0x00000200
#define RBBS_HIDETITLE      0x00000400
#define RBBS_TOPALIGN       0x00000800

#define WS_CLIPCHILDREN     0x02000000
#define WS_CLIPSIBLINGS     0x04000000
#define WS_VISIBLE          0x10000000
#define WS_CHILD            0x40000000

#define RB_INSERTBAND       0x0401
#define TB_CHECKBUTTON	    0x0402
#define TB_ADDBUTTONS       0x0414
#define TB_BUTTONSTRUCTSIZE 0x041E
#define TB_GETRECT	        0x0433
#define TB_SETEXTENDEDSTYLE 0x0454

#define I_IMAGENONE         -2
#define TBSTATE_ENABLED     0x04
#define BTNS_DROPDOWN       0x08
#define BTNS_AUTOSIZE       0x10

#define WM_NOTIFY           0x004E
#define WM_MY_SHOWMENU      0x8000 + 1
#define TBN_DROPDOWN        -710

#define REBARBANDINFO_SIZE  22

#define MF_POPUP            0x00000010
#define MF_INSERT           0x00000000
#define MF_SEPARATOR        0x00000800

#enum IDM_NEW = 100
#enum IDM_OPEN
#enum IDM_EXIT
#enum IDM_UNDO
#enum IDM_OPTION
#enum IDM_ABOUT

onexit *exit
oncmd gosub *l_OnNotify, WM_NOTIFY
oncmd gosub *l_OnMyShowMenu, WM_MY_SHOWMENU

//メニュー項目を作成
hMenu(3) = CreatePopupMenu()
AppendMenu hMenu(3), MF_INSERT, IDM_ABOUT, "バージョン情報(&A)"

hMenu(2) = CreatePopupMenu()
AppendMenu hMenu(2), MF_INSERT, IDM_OPTION, "オプション(&O)"

hMenu(1) = CreatePopupMenu()
AppendMenu hMenu(1), MF_INSERT, IDM_UNDO, "元に戻す(&U)\tCtrl+Z"

hMenu(0) = CreatePopupMenu()
AppendMenu hMenu(0), MF_INSERT, IDM_NEW, "新規作成(&N)\tCtrl+N"
AppendMenu hMenu(0), MF_INSERT, IDM_OPEN, "開く(&O)\tCtrl+O"
AppendMenu hMenu(0), MF_SEPARATOR, 0, 0
AppendMenu hMenu(0), MF_INSERT, IDM_EXIT, "終了(&X)\tAlt+F4"

hMainMenu = CreateMenu() //トップレベルメニュー
AppendMenu hMainMenu, MF_POPUP, hMenu(0), "file"
AppendMenu hMainMenu, MF_POPUP, hMenu(1), "edit"
AppendMenu hMainMenu, MF_POPUP, hMenu(2), "tool"
AppendMenu hMainMenu, MF_POPUP, hMenu(3), "help"

//IE風メニューバーを作成
winobj "ToolbarWindow32", "", 0, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TBSTYLE_TRANSPARENT | TBSTYLE_REGISTERDROP | TBSTYLE_CUSTOMERASE | TBSTYLE_LIST | TBSTYLE_FLAT | CCS_NODIVIDER | CCS_NOPARENTALIGN | CCS_NORESIZE | CCS_TOP,200, 20, 0, 0
hToolBar = objinfo_hwnd(stat)
sendmsg hToolBar, TB_BUTTONSTRUCTSIZE, 20, 0
sendmsg hToolBar, TB_SETEXTENDEDSTYLE, 0, 0
MenuName = "ファイル(&F)", "編集(&E)", "ツール(&T)", "ヘルプ(&H)" //メニューの名前
MenuHnd  = hMenu(0), hMenu(1), hMenu(2), hMenu(3) //メニューのハンドル
//ボタン追加
foreach MenuName
	TBB = I_IMAGENONE, cnt, ((BTNS_DROPDOWN|BTNS_AUTOSIZE) << 8) | TBSTATE_ENABLED, 0, varptr(MenuName(cnt))
	sendmsg hToolBar, TB_ADDBUTTONS, 1, varptr(TBB)
loop

//レバーコントロールを作成
winobj "ReBarWindow32", "", 0, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | RBS_BANDBORDERS | RBS_VARHEIGHT, 0, 20, 0, 0
hReBar = objinfo_hwnd(stat)

dim RBBI, REBARBANDINFO_SIZE
RBBI(0)  = REBARBANDINFO_SIZE*4 //cbSize
RBBI(1)  = RBBIM_STYLE | RBBIM_SIZE | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_ID //fMask
RBBI(2)  = RBBS_BREAK | RBBS_GRIPPERALWAYS //fStyle
RBBI(8)  = hToolBar //hwndChild
RBBI(10) = 26 //cyMinChild
sendmsg hReBar, RB_INSERTBAND, -1, varptr(RBBI) //バンド追加
stop

*exit
	DestroyMenu hMainMenu //トップレベルメニューを削除
end

*l_OnNotify
return OnNotify(ginfo(24), iparam, wparam , lparam)
*l_OnMyShowMenu
return OnMyShowMenu(ginfo(24), iparam, wparam , lparam)

#defcfunc OnNotify int msg_wndid, int msg_msg, int msg_wp, int msg_lp //OnNotify 処理用関数
	dupptr Nmhdr, msg_lp, 4*3
	if ((Nmhdr(0) == hToolBar) && (Nmhdr(2) == TBN_DROPDOWN)){ //ツールバーボタンが押された
		dupptr nmtoolbar, msg_lp, 44
		PostMessage hwnd, WM_MY_SHOWMENU, nmtoolbar(3), 0 //WM_MY_SHOWMENUメッセージを発行してメニューを表示。
	}
return 0

#defcfunc OnMyShowMenu int msg_wndid, int msg_msg, int msg_wp, int msg_lp //OnMyShowMenu 処理用関数
	//wParam に表示するメニューIDが入ります。
	
	dim rc,4
	sendmsg hToolBar ,TB_GETRECT, msg_wp, varptr(rc) //ツールバーボタンの座標を取得
	pt = rc(0),rc(3)
	ClientToScreen hToolBar, varptr(pt)
	sendmsg hToolBar, TB_CHECKBUTTON, msg_wp, 1 //ボタンを押した状態にする
	TrackPopupMenuEx MenuHnd(msg_wp), 0, pt(0), pt(1), hwnd, 0 //メニュー表示
	sendmsg hToolBar, TB_CHECKBUTTON, msg_wp, 0 //ボタンを離した状態にする
return 0
今回のはIEのメニューバーに近いですが、通常のメニューにはある「メニューを表示させているときに、マウスカーソルが別のメニュー項目の上に乗った瞬間にそのメニューが表示される」機能がありません。それを次回実装しようと思います。




[前へ] [戻る] [次へ]

(C)2019 inonote / 無断転載禁止