傳統 GetMenu()->AppendMenu/ModifyMenu 程式碼分散、難維護。MFC ON_UPDATE_COMMAND_UI 機制在選單即將顯示前自動呼叫更新處理函數,集中管理啟用/禁用、文字、勾選狀態,邏輯清晰。
ON_UPDATE_COMMAND_UI(ID, Handler) 將選單項 ID 與更新函數綁定afx_msg void Handler(CCmdUI* pCmdUI);CCmdUI 提供:Enable()、SetText()、SetCheck()、SetRadio()彈出選單本身無 ID,無法直接映射。MFC 規定:彈出選單第一個項目的更新函數會被呼叫兩次:
pCmdUI->m_pSubMenu == NULLpCmdUI->m_pSubMenu != NULL (此時需手動啟用/禁用整個彈出選單)Test Menu
Item One ID_ITEM_ONE
Item Two ID_ITEM_TWO
Popup ►
Popup One ID_POPUP_ONE
Popup Two ID_POPUP_TWO
class CMyDoc : public CDocument {
BOOL m_bItemOne, m_bItemTwo, m_bPopupOne, m_bPopupTwo;
afx_msg void OnUpdateItemOne(CCmdUI*);
afx_msg void OnUpdateItemTwo(CCmdUI*);
afx_msg void OnUpdatePopupOne(CCmdUI*);
afx_msg void OnUpdatePopupTwo(CCmdUI*);
DECLARE_MESSAGE_MAP()
};
BEGIN_MESSAGE_MAP(CMyDoc, CDocument)
ON_UPDATE_COMMAND_UI(ID_ITEM_ONE, OnUpdateItemOne)
ON_UPDATE_COMMAND_UI(ID_ITEM_TWO, OnUpdateItemTwo)
ON_UPDATE_COMMAND_UI(ID_POPUP_ONE, OnUpdatePopupOne)
ON_UPDATE_COMMAND_UI(ID_POPUP_TWO, OnUpdatePopupTwo)
END_MESSAGE_MAP()
void CMyDoc::OnUpdateItemOne(CCmdUI* p) {
p->Enable(m_bItemOne);
p->SetText(m_bItemOne ? _T("Item One") : _T("Item One (Disabled)"));
}
void CMyDoc::OnUpdateItemTwo(CCmdUI* p) {
p->Enable(m_bItemTwo);
p->SetText(m_bItemTwo ? _T("Item Two") : _T("Item Two (Disabled)"));
}
void CMyDoc::OnUpdatePopupOne(CCmdUI* p) {
if(p->m_pSubMenu) { // 父選單列繪製 Popup 標題
BOOL bEnable = m_bPopupOne || m_bPopupTwo;
p->m_pMenu->EnableMenuItem(p->m_nIndex, MF_BYPOSITION | (bEnable ? MF_ENABLED : MF_DISABLED|MF_GRAYED));
return;
}
p->Enable(m_bPopupOne); // 彈出選單內繪製 Popup One 項目
}
void CMyDoc::OnUpdatePopupTwo(CCmdUI* p) {
p->Enable(m_bPopupTwo);
}
SetTextUpdateUIState() 供所有 Handler 呼叫善用 ON_UPDATE_COMMAND_UI 讓選單/工具列狀態與資料模型即時同步,是 MFC 專業級 UI 開發的標誌性技能。