今回は、右クリックをしたときなどに表示されるショートカットメニュー(コンテキストメニュー)を表示させてみましょう。前回の内容を理解できていれば、さほど難しいことはありません。
ショートカットメニューを作成するには、前回ドロップダウンメニューの作成に使用したのと同じCreatePopupMenu関数を呼び出します。その後、やはり前回と同様にAppendMenu関数でメニューにメニュー項目を追加します。前回と同じなので、何も難しいことはありません。
前回は、作成されたメニューオブジェクトをメニューバーに表示される項目として追加すれば、ドロップダウンメニューやサブメニューとして使いましたが、今回は、作成したメニューオブジェクトをショートカットメニューとして任意の場所に表示させます。ショートカットメニューを表示させるには、TrackPopupMenuEx関数を呼び出します。
BOOL TrackPopupMenuEx( HMENU hMenu, // メニューハンドル UINT fuFlags, // オプションフラグ int x, // x座標 int y, // y座標 HWND hWnd, // ウィンドウハンドル LPTPMPARAMS ptpm // オーバーラップ禁止範囲 );
hMenuパラメータは、表示するメニューを識別するメニューハンドルです。ここには、CreatePopupMenu関数で作成したメニューのハンドルを指定します。
fuFlagsパラメータには、どのように表示するかを指定するビットフラグ値を指定します。このパラメータは、以下の表の値を組み合わせて指定することになります。通常は、デフォルト動作である0を指定しておけば大丈夫でしょう。
定数名 | 値 | 意味 |
---|---|---|
TPM_LEFTALIGN | 0x0000 | xパラメータがショートカットメニューの左端のX座標になるように表示(デフォルト) |
TPM_CENTERALIGN | 0x0004 | xパラメータがショートカットメニューの中央のX座標になるように表示 |
TPM_RIGHTALIGN | 0x0008 | xパラメータがショートカットメニューの右端のX座標になるように表示 |
TPM_TOPALIGN | 0x0000 | yパラメータがショートカットメニューの上端のY座標になるように表示(デフォルト) |
TPM_VCENTERALIGN | 0x0010 | yパラメータがショートカットメニューの中央のY座標になるように表示 |
TPM_BOTTOMALIGN | 0x0020 | yパラメータがショートカットメニューの下端のY座標になるように表示 |
TPM_NONOTIFY | 0x0080 | 項目がクリックされたとき通知メッセージ送信しない |
TPM_RETURNCMD | 0x0100 | 選択された項目IDを関数の戻り値として返す |
TPM_LEFTBUTTON | 0x0000 | メニュー項目をマウスの左ボタンで選択可能(デフォルト) |
TPM_RIGHTBUTTON | 0x0002 | メニュー項目をマウスの左右両方のボタンで選択可能 |
TPM_HORPOSANIMATION | 0x0400 | 右から左へアニメーション表示 |
TPM_HORNEGANIMATION | 0x0800 | 左から右へアニメーション表示 |
TPM_VERPOSANIMATIO | 0x1000 | 上から下へアニメーション表示 |
TPM_VERNEGANIMATION | 0x2000 | 下から上へアニメーション表示 |
TPM_NOANIMATION | 0x4000 | アニメーションなしで表示 |
TPM_RECURSE | 0x0001 | 別のメニューがすでに表示されている場合でも表示(メニューの中でコンテキストメニューを表示する目的で使用) |
TPM_HORIZONTAL | 0x0000 | ptpmパラメータで指定した領域に重なる場合は水平方向の配置を優先(デフォルト) |
TPM_VERTICAL | 0x0040 | ptpmパラメータで指定した領域に重なる場合は垂直方向の配置を優先 |
x, yパラメータにはショートカットメニューを表示する座標を指定します。この座標はスクリーン座標で指定しなければなりません。
ptpmパラメータはオーバーラップ(重なり)禁止領域を指定します。特に、禁止領域を指定する必要がない場合には0 (NULL) を指定します。
この関数によってショートカットメニューが表示されると、hWndパラメータで指定されたウィンドウにメッセージが送られます。これは前回までと同様に
メッセージです。なお、TrackPopupMenuEx関数でショートカットメニューを表示する場合、 メッセージによる通知以外にも、どのアイテムが選択されたのかを取得する手段があります。fuFlagsパラメータに0x0100 (TPM_RETURNCMD) を指定すると、この関数の戻り値として、選択されたメニュー項目のIDが返されます。また、何も選択されなれば戻り値が0になります。
この場合、アイテムが選択されたことで0x0080 (TPM_NONOTIFY) も組み合わせて指定しておきましょう。このようにすると、 メッセージが発生しないようになります。
メッセージが発生してしまうので、これによって問題が生じてしまう場合には、関数呼び出し時に同時に以前にも一度説明しましたが、作成されたメニューオブジェクトは、他のWindowsオブジェクトの場合と同様、必要なくなった時点で削除しなければいけません。ただ、前回までのスクリプトで作成されていたメニューはすべてウィンドウに関連付けられたものであったため、それらはウィンドウが破棄されるときに同時に削除されていました。しかし、今回はそうではないので、明示的に削除する必要があります。
メニューオブジェクトを削除することを、一般的に「メニューを破棄する」と呼びます。メニューを破棄するにはDestroyMenu関数を使います。
BOOL DestroyMenu( HMENU hMenu // メニューハンドル );
この関数にメニューハンドルを渡すことで、そのメニューが破棄されます。メニューを破棄したら、それ以降はそのメニューハンドルは無効なものになるので、そのハンドルをメニュー操作関数に渡してはいけません。
では、実際にスクリプトを作成してみましょう。
今回のサンプルでは、あらかじめメニューを作成しておき、右クリックされた時にマウスの位置に表示します。今回は、上で説明した
メッセージを受け取らずに、戻り値で選択メニュー項目を取得する方法を使ってみることにします。今回はマウスクリックを検出するのに、onclick命令を使うことにします。メニューの表示位置にはスクリーン座標を指定するので、マウスの位置をスクリーン座標で取得できるginfo_mxとginfo_myを参照します。
#uselib "user32.dll" #cfunc CreatePopupMenu "CreatePopupMenu" #func AppendMenu "AppendMenuA" int,int,int,sptr #func TrackPopupMenuEx "TrackPopupMenuEx" int,int,int,int,int,int #func DestroyMenu "DestroyMenu" int #define NULL 0 #define MF_POPUP 0x10 #define MF_SEPARATOR 0x800 #define TPM_NONOTIFY 0x0080 #define TPM_RETURNCMD 0x0100 #define TPM_RIGHTBUTTON 0x0002 ; メニュー項目IDを定義 #define CMD_ID_OPEN 1 ; 「開く」項目のID #define CMD_ID_SAVE 2 ; 「保存」項目のID #define CMD_ID_QUIT 3 ; 「終了」項目のID ; ショートカットメニューの作成 hPopupMenu = CreatePopupMenu() AppendMenu hPopupMenu, 0, CMD_ID_OPEN, "開く(&O)" AppendMenu hPopupMenu, 0, CMD_ID_SAVE, "保存(&S)" AppendMenu hPopupMenu, MF_SEPARATOR, 0, NULL AppendMenu hPopupMenu, 0, CMD_ID_QUIT, "終了(&Q)" onclick gosub *OnMouseClicked ; マウスクリック時ジャンプ onexit gosub *OnAppExit ; 終了時ジャンプ stop *OnMouseClicked ; マウス右クリックされた場合はメニューを表示 if iparam == 3 { fOptions = TPM_NONOTIFY | TPM_RETURNCMD | TPM_RIGHTBUTTON TrackPopupMenuEx hPopupMenu, fOptions, ginfo_mx, ginfo_my, hwnd, NULL if stat != 0 { commandID = stat ; 選択されたメニュー項目IDを保持 gosub *ExecuteMenuCommand } } return *ExecuteMenuCommand ; 選択されたメニュー項目に応じて処理を実行 switch commandID case CMD_ID_OPEN dialog "*", 16 if stat { dialog refstr + "を開きました" } swbreak case CMD_ID_SAVE dialog "*", 17 if stat { dialog refstr + "を保存しました" } swbreak case CMD_ID_QUIT gosub *OnAppExit swbreak swend return *OnAppExit ; 終了処理 dialog "終了します", 0 ; ポップアップメニューの破棄 DestroyMenu hPopupMenu end