我正在寫一個 MFC 的多文檔(MDI)應用。在父視窗中,我如何檢查所有的MDI子視窗是否都已經關閉?如果都關閉了,那麼我想在我的主視窗啟用一個窗格。
Ramesh
Windows 和 MFC 不提供任何專門的函數來擷取 MDI 子視窗數,但實現你想要的這個功能很容易。實際上,我可以想到半打方法來解決這個問題。你可以捕獲 WM_CREATE/WM_DESTROY 訊息;可以用 SetWindowsHookEx 安裝 Windows 鉤子;可以用 EnumWindows 來枚舉子視窗並計算它的數量。但最簡單的解決方案常常是最容易被忽視的方法。
這個問題說白了,無非就是——應用程式使用 MDI 介面或者其它你自己設計的多視窗使用者介面——說到底就是一個視窗列表。Figure 1 展示的是一個基於標準模板庫(STL) list 的類,很難說這樣封裝是否值得,但我只是覺得 Windows 程式員在代碼中敲入 “push_back”太不可思議。CWinList 使你用“Add”取而代之。為了使用 CWinList,只需要在某個地方添加一個全域執行個體,既可以是一個全域變數,也可以是主應用程式類中的一個資料成員:
class CMyApp : public CWinApp {
public:
CWinList m_winlist; // 開啟的惡視窗列表
};
為了跟蹤子視窗,你只需要在建立或銷毀子視窗時對此列表進行添加或刪除操作既可。顯然做這件事情的最佳地點是在擬跟蹤視窗的建構函式和解構函式中:
CMyView::CMyView()
{
theApp.m_winlist.Add(this);
}
CMyView::~CMyView()
{
theApp.m_winlist.Remove(this);
}
除此之外,你還可以從 OnCreate 和 OnDestroy 處理函數中調用 Add 和 Remove,以保證你的列表之包含具備有效 HWNDs 的視窗對象。因為 CWinList 是從 list<CWnd*> 派生而來的,所以處理過程中可以充分藉助 STL的威力。例如,你可以用 STL list 的迭代器(iterator)枚舉列表中的視窗:
CWinList& wl = theApp.m_winlist;
for (CWinList::iterator it=wl.begin(); it!=wl.end(); it++) {
CWnd* pWnd = *it;
// do something
}
我寫了一個小程式 WinCount,它用 CWinList 計數 MDI 子視窗。運行畫面如 Figure 2 所示。
Figure 2 計運算元視窗的 WinCount
WinCount 右下角有一個狀態列窗格顯示開啟的視窗數量,該程式的“關於”對話方塊列出了視窗的標題。這個“關於”對話方塊就是用 CWinList::iterator 來產生它的反饋訊息;該狀態列窗格是一個標準的 MFC 指標窗格,使用 ON_UPDATE_COMMAND_UI 來顯示視圖數量。
void CMainFrame::OnUpdateWinIndicator(CCmdUI* pCmdUI)
{
CString s;
s.Format(_T("Open:%d"), theApp.m_winlist.size());
pCmdUI->SetText(s);
}