MFC: Disable Recent File List (MRU) menu items
記錄一下這個 MFC 的技巧:將 recent file list (MRU) 選單 disable。
MFC 支援 most recent used file list (MRU) 的方法是:
- 在
CWinApp::InitInstance()裡呼叫LoadStdProfileSettings(),從 registry 裡載入設定,包含 MRU 檔案清單。 - MRU 的選單 ID 固定為
ID_FILE_MRU_FILE#,其中#為數字,從 1 開始。不過從 class wizard 裡,我們僅能操作ID_FILE_MRU_FILE1。 - MFC 會自動幫我們管理 MRU,預設的 MRU 選單項目點選動作為:依據 Doc/View 架構的開檔程序開檔。
一切都是這麼美好,直到我們有需要修改、增強預設的行為。
在 MFC 裡,可以實作 UPDATE_COMMAND_UI 這個 message 的 handler,在顯示選單 (menu) 前,修改選單的屬性,比如 disable 選單項目 (menu item)。
好比說要等到文件有對應的儲存路徑之後,Save 選單項目才 enable。我們就可以針對 ID_FILE_SAVE 實作 UPDATE_COMMAND_UI 的 message handler,依據有否對應的儲存路徑,決定是否要 enable 選單項目。如下:
void MyView::OnUpdateFileSave(CCmdUI* pCmdUI)
{
pCmdUI->Enable(!GetDocument()->GetPathName().IsEmpty());
}
然而,對於 MRU 選單項目來說,其 ID 卻有很多個,總不可能替每一個 ID 都實作完全一樣的 UPDATE_COMMAND_UI 的 message handler 吧?若是以後要修改 MRU 清單數量的話,豈不很麻煩?
還好,就如同在 MFC 的 message loop 裡,ON_COMMAND() 有對應的 ON_COMMAND_RANGE(),讓我們可以對一組 ID 設定 handler 一樣,ON_UPDATE_COMMAND_UI() 也有對應的 ON_UPDATE_COMMAND_UI_RANGE()。我們先用 class wizard 設定實作 ID_FILE_MRU_FILE1 的 UPDATE_COMMAND_UI 的 message handler,但把函式名稱最後的 File1 去掉,改為 OnUpdateFileMru(),如下:
void MyView::OnUpdateFileMru(CCmdUI* pCmdUI)
{
pCmdUI->Enable(CanOpenFile());
}
然後到 message loop 處,將下面這行:
ON_UPDATE_COMMAND_UI(ID_FILE_MRU_FILE1, MyView::OnUpdateFileMru)
改成這樣:
ON_UPDATE_COMMAND_UI_RANGE(ID_FILE_MRU_FILE1, ID_FILE_MRU_LAST, MyView::OnUpdateFileMru)
其中,因為我們不知道 MRU 最多有幾個 ID 可以用 (VC6 可以到 ID_FILE_MRU_FILE16),所以 MFC 有提供 ID_FILE_MRU_LAST,代表最後一個 MRU 的 ID。
理論上,這樣就搞定了。但測試的結果卻發現,MRU 清單顯示不出來了,看來是我們的修改,破壞了 MFC 原來對 MRU 的支援。所以要想個辦法,再把 MFC 原來處理 MRU 的程式,給「接」回來。
在 Google 裡,找不到解法,最後是靠 VC 的 browse info,找出 CWinApp 有個 protected member function 叫 OnUpdateRecentFileMenu(),顧名思義,看來就是負責在選單裡,列出 MRU 清單的函式。
因為是 protected member function,所以必須在 MyApp 裡也實作一個同名的函式,直接轉呼叫 CWinApp::OnUpdateRecentFileMenu(),然後在 MyView::OnUpdateFileMru(),呼叫 MyApp::OnUpdateRecentFileMenu()。如下:
void MyView::OnUpdateFileMru(CCmdUI* pCmdUI)
{
((MyApp*)AfxGetApp())->OnUpdateRecentFileMenu();
pCmdUI->Enable(CanOpenFile());
}
要先呼叫 OnUpdateRecentFileMenu(),然後再填上我們自己的程式邏輯。
至此,大功告成,測試結果一切正常,如我們所願。
最後啃一下:為什麼有影印機/印表機的型號,取做 MFC-* 的?害我要找 MFC 的資料,google 出來,一半都是影印機/印表機的型錄。XD



One Comment
"M"ulti-"F"unction......Center(?)
多功能事務機
Post a Comment