S-JIS[2002-08-11]

右クリックでポップアップメニューを出す方法

よくウィンドウの中で右クリックをすると、ポップアップメニューが出ますね。 これを実現する方法は簡単です。


ポップアップメニューを右クリックで出したいので、 まずCViewの派生クラス(ここではCTestViewとします)の WM_RBUTTONDOWNのハンドラのOnRButtonDownを用意します。
そして、CMenuのCreatePopupMenuでメニューを初期化し、 AppendMenu等でメニューを準備して TrackPopupMenuで表示し、最後にDesytroyMenuを呼び出して終了です。

TestView.h:
class CTestView : public CView
{
〜
// 生成されたメッセージ マップ関数
protected:
	//{{AFX_MSG(CTestView)
	afx_msg void OnRButtonDown(UINT nFlags, CPoint point);
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};
TestView.cpp:
〜
BEGIN_MESSAGE_MAP(CTestView, CView)
	//{{AFX_MSG_MAP(CTestView)
	ON_WM_RBUTTONDOWN()
	//}}AFX_MSG_MAP
	〜
END_MESSAGE_MAP()
〜
void CTestView::OnRButtonDown(UINT nFlags, CPoint point) 
{
	// TODO: この位置にメッセージ ハンドラ用のコードを追加するかまたはデフォルトの処理を呼び出してください

	CMenu menu;
	menu.CreatePopupMenu();
	menu.AppendMenu(MF_STRING|MF_ENABLED,ID_EDIT_UNDO ,"元に戻す(&U)");
	menu.AppendMenu(MF_SEPARATOR);
	menu.AppendMenu(MF_STRING|MF_ENABLED,ID_EDIT_CUT  ,"切り取り(&T)");
	menu.AppendMenu(MF_STRING|MF_ENABLED,ID_EDIT_COPY ,"コピー(&C)");
	menu.AppendMenu(MF_STRING|MF_ENABLED,ID_EDIT_PASTE,"貼り付け(&P)");

	ClientToScreen(&point);
	menu.TrackPopupMenu(
		TPM_LEFTALIGN  |	//クリック時のX座標をメニューの左辺にする
		TPM_RIGHTBUTTON,	//右クリックでメニュー選択可能とする
		point.x,point.y,	//メニューの表示位置
		this            	//このメニューを所有するウィンドウ
	);
	menu.DestroyMenu();

//	CView::OnRButtonDown(nFlags, point);
}

通常のメニューバーのメニューだと、メニュー描画時に メニューID毎に作られた「OnUpdateほにゃらら」関数が呼び出されて 選択不可になったりチェックが付いたりするのですが、 AppendMenuの時はそれは行われません。
したがって、自分で選択可能(MF_ENABLED)・選択不可(MF_GRAYED)・ チェック(MF_CHECKED/MF_UNCHECKED)を指定してやらないといけません。

メニューIDに対してハンドラを作ってやらないと 実際に メニューをクリックした時に何も動作しません。 が、メニューIDがメニューリソースに入っていないIDだった場合、 ClassWizardの「オブジェクトID」リストにメニューIDが表示されません。 この場合は、自分でハンドラをコーディングするか、もしくは 他のどこにも使わないメニューリソースを作って そこに メニューIDを加えてClassWizardを使ってください。


上記の例だと、実はメニューバーのデフォルトの「編集」メニューのサブメニューと同じ内容ですね。 これを一々コーディングせずに、メニューバーから持ってくることが出来ます。

TestView.cpp:
void CTestView::OnRButtonDown(UINT nFlags, CPoint point) 
{
	CWnd  *pFrm =GetParentFrame();        //メインフレーム取得
	CMenu *pMain=pFrm ->GetMenu();     //メニュー取得
	CMenu *pMenu=pMain->GetSubMenu(1); //「編集」メニュー取得

	ClientToScreen(&point);
	pMenu->TrackPopupMenu(
		TPM_LEFTALIGN  |	//クリック時のx座標をメニューの左辺にする
		TPM_RIGHTBUTTON,	//右クリックでメニュー選択可能とする
		point.x,point.y,	//メニューの表示位置
		this            	//このメニューを所有するウィンドウ
	);
}

この場合は、DestroyMenuは不要です。というか、実行したら、 メニューバーのメニューを選択する時にハングアップする(爆)


これを応用して、メニューリソースを使って オリジナルのポップアップメニューを作ることが出来ます。

IDR_MENU_POPUPというメニューリソースを新規に作成し、 popup1配下のメニューを作りました。

TestView.cpp:
void CTestView::OnRButtonDown(UINT nFlags, CPoint point) 
{
	CMenu menu;
	menu.LoadMenu(IDR_MENU_POPUP);
	CMenu *pMenu=menu.GetSubMenu(0);	//「popup1」メニューを取得

	ClientToScreen(&point);
	pMenu->TrackPopupMenu(
		TPM_LEFTALIGN  |	//クリック時のx座標をメニューの左辺にする
		TPM_RIGHTBUTTON,	//右クリックでメニュー選択可能とする
		point.x,point.y,	//メニューの表示位置
		this            	//このメニューを所有するウィンドウ
	);
	menu.DestroyMenu();
}

GetSubMenuの使い方に関して、「メニューリソースが変更された時に GetSubMenuの引数も コーディングし直さなちゃいけないじゃないか」という正常な感覚をお持ちの方は、 メニューバーの説明を参考にしてみて下さい。


VC++ページへ戻る / 技術メモへ戻る
メールの送信先:ひしだま