MFC 的 CSplitterWnd 支援靜態分割,允許在執行期建立固定行列的子視窗,每個窗格可關聯不同的 CView 衍生類,實現複雜的多視圖佈局。本文詳細說明混合靜態分割(巢狀分割)的三大核心步驟與關鍵 API。
CMainFrame 中定義 CSplitterWnd 資料成員OnCreateClient:建立靜態分割、填充視圖、設定列寬/列高CDocument::UpdateAllViews() 實現多視圖資料同步CreateStaticBOOL CreateStatic(
CWnd* pParentWnd, // 父視窗 (通常是 this)
int nRows, // 列數 (1~16)
int nCols, // 行數 (1~16)
DWORD dwStyle = WS_CHILD | WS_VISIBLE,
UINT nID = AFX_IDW_PANE_FIRST); // 巢狀分割時需用 IdFromRowCol() 產生唯一 ID
CreateViewBOOL CreateView(
int row, int col, // 目標窗格位置
CRuntimeClass* pViewClass, // 視圖類 (需 DECLARE_DYNCREATE)
SIZE sizeInit, // 初始大小
CCreateContext* pContext); // 來自 OnCreateClient 參數傳遞
SetColumnInfo(int col, int cxIdeal, int cxMin); // 設定欄寬/最小寬
SetRowInfo(int row, int cyIdeal, int cyMin); // 設定列高/最小高
RecalcLayout(); // 重新佈局 (必須呼叫)
SetActivePane(int row, int col, CWnd* pWnd = NULL); // 設定作用中窗格
在外層分割器的某窗格中再建立一個 CSplitterWnd 成員,於外層 CreateView 後、內層 OnCreateClient 中初始化:
// CMainFrame 成員
CSplitterWnd m_wndSplitterOuter;
CSplitterWnd m_wndSplitterInner; // 巢狀分割器
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT, CCreateContext* pContext) {
// 1. 外層 1列 2欄
if (!m_wndSplitterOuter.CreateStatic(this, 1, 2))
return FALSE;
// 2. 左欄放 CLeftView
if (!m_wndSplitterOuter.CreateView(0, 0,
RUNTIME_CLASS(CLeftView), CSize(200, 0), pContext))
return FALSE;
// 3. 右欄先放佔位視圖,稍後替換為內層分割器
if (!m_wndSplitterOuter.CreateView(0, 1,
RUNTIME_CLASS(CPlaceholderView), CSize(0, 0), pContext))
return FALSE;
// 4. 取得右欄窗格 HWND,作為內層分割器父視窗
CWnd* pRightPane = m_wndSplitterOuter.GetPane(0, 1);
// 內層分割器需為子視窗,故改用 pRightPane 為父
if (!m_wndSplitterInner.CreateStatic(pRightPane, 2, 1,
WS_CHILD | WS_VISIBLE, m_wndSplitterOuter.IdFromRowCol(0, 1)))
return FALSE;
// 5. 填充內層上下兩個視圖
if (!m_wndSplitterInner.CreateView(0, 0,
RUNTIME_CLASS(CTopView), CSize(0, 150), pContext))
return FALSE;
if (!m_wndSplitterInner.CreateView(1, 0,
RUNTIME_CLASS(CBottomView), CSize(0, 0), pContext))
return FALSE;
// 6. 尺寸微調
m_wndSplitterOuter.SetColumnInfo(0, 200, 50);
m_wndSplitterOuter.RecalcLayout();
m_wndSplitterInner.SetRowInfo(0, 150, 50);
m_wndSplitterInner.RecalcLayout();
return TRUE;
}
文檔類呼叫 UpdateAllViews(pSender, lHint, pHint),框架自動遍歷所有關聯視圖呼叫 OnUpdate():
pSender:觸發更新的視圖指標,傳 NULL 表全部更新lHint:自定義提示碼 (如 HINT_DATA_CHANGED)pHint:攜帶詳細資料的 CObject*視圖端覆寫:
void CMyView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) {
if (pSender == this) return; // 避免自我重繪
if (lHint == HINT_DATA_CHANGED) {
// 根據 pHint 重繪或局部更新
Invalidate();
}
}
利用 CCreateContext 的 m_pNewViewClass 指定新視圖類型,配合 DeleteView() + CreateView() 實現執行期視圖替換。注意需手動呼叫 OnInitialUpdate() 與 ShowWindow(SW_SHOW)。
混合靜態分割提供了極大的介面彈性,適用於資訊密集型應用(如 IDE、監控儀表板、郵件用戶端),是 MFC 多文檔介面 (MDI) 之外的另一種強大佈局選擇。