編輯框控制項右鍵彈出的標準內容選單,若要加入自訂選單項,常面臨 WM_INITMENUPOPUP 訊息無法觸發的困擾。編輯控制項似乎以空 HWND 或 TPM_NONOTIFY 呼叫 TrackPopupMenu,導致選單不發送通知訊息,MFC 的 CCmdUI 更新機制因而失效。
本文提供 CEitMenuHandler 小類別完整解決此問題,三步驟即可整合:
class CMyEdit : public CEdit {
protected:
CEditMenuHandler m_editMenuHandler;
virtual void PreSubclassWindow();
};
void CMyEdit::PreSubclassWindow() {
// IDR_EDITMENU 為自訂內容選單資源 ID
m_editMenuHandler.Install(this, IDR_EDITMENU);
}
// 訊息對應
ON_COMMAND_RANGE(ID_EDIT_FIRST, ID_EDIT_LAST, OnEditCommand)
ON_UPDATE_COMMAND_UI_RANGE(ID_EDIT_FIRST, ID_EDIT_LAST, OnUpdateEditCommand)
void CMyEdit::OnUpdateEditCommand(CCmdUI* pCmdUI) {
m_editMenuHandler.OnUpdateEditCommand(pCmdUI);
}
void CMyEdit::OnEditCommand(UINT nID) {
m_editMenuHandler.OnEditCommand(nID);
}
CEitMenuHandler 內建處理剪下、複製、貼上等標準編輯命令,依選取狀態與剪貼簿內容自動啟用/停用選單項。若命令已處理回傳 TRUE,否則 FALSE 讓衍生類別自行處理其他命令(如檔案類型選單)。
CEitMenuHandler 巧妙重用 CPopupMenuInitHandler(詳見作者另一文章)與 CSubclassWnd 類別:
CPopupMenuInitHandler:代表視窗攔截 WM_INITMENUPOPUP,完成 MFC 選單更新機制,讓非框架視窗也能使用 ON_UPDATE_COMMAND_UICSubclassWnd:可子類化任意 CWnd 物件// 在 CEditMenuHandler::OnUpdateEditCommand 中
switch (nID) {
case ID_EDIT_PASTE:
pCmdUI->Enable(::IsClipboardFormatAvailable(CF_TEXT));
break;
// ... 其他標準編輯命令同理
}
期望標準 MFC 選單 ID(ID_EDIT_CUT、ID_EDIT_COPY 等)。命令執行時發送 WM_CUT、WM_COPY 等訊息至編輯控制項,或呼叫 CEdit::Cut、CEdit::Copy 等方法。
完整原始碼與範例請見文末下載。