在 MFC 應用程式開發中,實現類似 Visual Studio 或 Office 這類專業軟體的「多模式顯示」(如正常模式、簡易模式、簡潔模式)是一項極具實用價值的技術。本文將深入解析如何在 SDI(單文檔介面)與 MDI(多文檔介面)架構下,透過動態載入/銷毀選單資源,實現界面模式的無縫切換。
MFC 預設會在框架視窗建立時自動載入選單資源(IDR_MAINFRAME)。若要實現多模式,第一步必須攔截並銷毀預設選單,改由程式碼動態控制。SDI 架構相對簡單,MDI 則因涉及子視窗選單自動切換機制,處理起來較為棘手。
重寫 CMainFrame::PreCreateWindow,在視窗建立前銷毀預設選單控制碼,並移除不必要的視窗樣式:
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
cs.style &= ~FWS_ADDTOTITLE;
cs.style &= ~(WS_SIZEBOX | WS_MINIMIZEBOX | WS_MAXIMIZEBOX);
if (cs.hMenu != NULL)
{
DestroyMenu(cs.hMenu);
cs.hMenu = NULL;
}
if (!CFrameWnd::PreCreateWindow(cs))
return FALSE;
return TRUE;
}
關鍵提醒:資源檔中 ID 為 IDR_MAINFRAME 的選單資源絕不可刪除,否則會觸發 MFC 斷言錯誤。
MDI 架構下,MFC 會在子視窗啟用時自動切換選單(IDR_xxxTYPE)。需採取三步驟:
IDR_MAINFRAME 選單資源,刪除子視窗專屬選單資源(防止資源洩漏)。CMainFrame::LoadFrame,移除預設載入邏輯。CMainFrame::OnCreateClient,傳入 NULL 給 CreateClient 以禁用預設選單切換。BOOL CMainFrame::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle,
CWnd* pParentWnd, CCreateContext* pContext)
{
return CFrameWnd::LoadFrame(nIDResource, dwDefaultStyle, pParentWnd, pContext);
}
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* /*pContext*/)
{
return CreateClient(lpcs, NULL); // 關鍵:傳入 NULL 禁止選單切換
}
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
cs.style &= ~FWS_ADDTOTITLE;
cs.style &= ~(WS_SIZEBOX | WS_MINIMIZEBOX | WS_MAXIMIZEBOX);
if (cs.hMenu != NULL)
{
DestroyMenu(cs.hMenu);
cs.hMenu = NULL;
}
if (!CFrameWnd::PreCreateWindow(cs))
return FALSE;
return TRUE;
}
完成上述初始化後,即可使用 Win32 API SetMenu 在執行期動態載入不同模式對應的選單資源:
// 切換至「簡易模式」選單
HMENU hMenu = LoadMenu(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MENU_SIMPLE));
SetMenu(hMenu);
搭配徐景周先生的「程式界面多模式顯示的實現」邏輯,即可實現工具列、狀態列、視圖佈局的同步切換。



掌握 PreCreateWindow、LoadFrame、OnCreateClient 這三個關鍵虛擬函數的重寫時機,配合 DestroyMenu/SetMenu API,即可在 SDI/MDI 架構下靈活實現多模式界面切換。此技術對於開發專業級、高可定製性的 MFC 應用程式具有重要參考價值。