VC++4.xではコンポーネントギャラリで右ボタンを簡単に実装することができます。
しかし、実際にやってみた人は気がついたかもしれませんが、メニューのオーナがフレームウィンドウで
ないとメニューアイテムのアップデート(無効なメニューアイテムはグレイアウトされる等)がちゃんと動作しません。
では、ダイアログなどのようにフレームウィンドウでないものをオーナにしたい場合はどうしたらよいのでしょう?
コマンドの更新ハンドラにブレークポイントを仕掛け、メニュー操作を行うことで、
更新ハンドラがどこからコールされているかを知ることができます。実際にやってみると、
更新ハンドラを呼んでいるのは CFrameWnd::OnInitMenuPopup だということが解ります。
だから、右ボタンメニューのオーナがフレームウィンドウ
(またはその派生クラス)でないと、メニューアイテムが更新されないんですね。
だって、CView はそのようなメソッドを持っていませんから。
CFrameWnd::OnInitMenuPopup ではメニューの各アイテムを調べ、そのコマンドターゲットに対し
OnCmdMsg(m_nID, CN_UPDATE_COMMAND_UI, this, NULL) を実行することで、メニューアイテムの更新ハンドラ
を呼び出し、グレイアウト等の処理を行っています。
では、フレームウィンドウ以外をオーナとするとき、右ボタンメニューでの更新処理を行うには
どうしたらいいでしょうか?答えは、自分で(あなたが)OnInitMenuPopup 相当のものを実装するってことです。
具体的には、以下の様にします。
void CMenuCustomizePage::OnContextMenu(CWnd *pWnd, CPoint point)
{
UNUSED_ALWAYS (pWnd); CMenu menu;
VERIFY(menu.LoadMenu(IDR_POPUP_MENU_CUSTOMIZE_PAGE));
CMenu* pPopup = menu.GetSubMenu(0);
ASSERT(pPopup != NULL);
if (pPopup != NULL) {
OnInitMenuPopup(pPopup); // ←これを加える
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this);
}
}
void CMenuCustomizePage::OnInitMenuPopup(CMenu* pMenu)
{
ASSERT(pMenu != NULL);
// check the enabled state of various menu items
CCmdUI state;
state.m_pMenu = pMenu;
ASSERT(state.m_pOther == NULL);
ASSERT(state.m_pParentMenu == NULL);
state.m_nIndexMax = pMenu->GetMenuItemCount();
for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax;
state.m_nIndex++)
{
state.m_nID = pMenu->GetMenuItemID(state.m_nIndex);
if (state.m_nID == 0)
continue; // menu separator or invalid cmd - ignore it
ASSERT(state.m_pOther == NULL);
ASSERT(state.m_pMenu != NULL);
if (state.m_nID == (UINT)-1)
{
// possibly a popup menu, route to first item of that popup
state.m_pSubMenu = pMenu->GetSubMenu(state.m_nIndex);
if (state.m_pSubMenu == NULL ||
(state.m_nID = state.m_pSubMenu->GetMenuItemID(0)) == 0 ||
state.m_nID == (UINT)-1)
{
continue; // first item of popup can't be routed to
}
state.DoUpdate(this, FALSE); // popups are never auto disabled
}
else
{
// normal menu item
// Auto enable/disable if frame window has 'm_bAutoMenuEnable'
// set and command is _not_ a system command.
state.m_pSubMenu = NULL;
state.DoUpdate(this, /*m_bAutoMenuEnable &&*/ state.m_nID < 0xF000);
}
// adjust for menu deletions and additions
UINT nCount = pMenu->GetMenuItemCount();
if (nCount < state.m_nIndexMax)
{
state.m_nIndex -= (state.m_nIndexMax - nCount);
while (state.m_nIndex < nCount &&
pMenu->GetMenuItemID(state.m_nIndex) == state.m_nID)
{
state.m_nIndex++;
}
}
state.m_nIndexMax = nCount;
}
}
前のTips
次のTips
津田伸秀 のホームページに戻る。
Last Updated on 6-Oct-1996, Copyright (c) 1996 by Nobuhide Tsuda, All Right Reserved.
このホームページに関するご質問、ご要望、バグレポート等は
Nobuhide_Tsuda@jsn.justnet.or.jp
までメールをいただければ幸いです。