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
までメールをいただければ幸いです。