分割視圖技術可在單一框架視窗同時呈現多個視圖,顯著提升資訊密度與操作友好度,是 MFC 應用開發常見需求。本文提出一套可擴充、可複用的分割視圖創建框架,解決標準 CSplitterWnd 客製化受限的問題。
為賦予分割視窗自定義行為(如禁止拖曳調整大小),必須從 CSplitterWnd 衍生專屬類別:
class CFixSplitterWnd : public CSplitterWnd {
// 重寫滑鼠移動處理,禁止分割條拖曳
void OnMouseMove(UINT nFlags, CPoint point) {
CWnd::OnMouseMove(nFlags, point); // 防止出現拖曳游標
// CSplitterWnd::OnMouseMove(nFlags, point); // 原版會顯示拖曳狀態
}
};
在 CMainFrame 中宣告兩個分割器成員,於 OnCreateClient 建立巢狀分割結構:
// 成員變數
CFixSplitterWnd m_wndSplitterH; // 水平分割(上下)
CFixSplitterWnd m_wndSplitterV; // 垂直分割(左右)
BOOL m_bCreateSplitter;
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) {
// 第一層:主框架左右分割(1行2列)
BOOL bResult = m_wndSplitterV.CreateStatic(this, 1, 2);
ASSERT(bResult);
// 第二層:右側窗格再上下分割(4行1列)
m_wndSplitterH.CreateStatic(&m_wndSplitterV, 4, 1,
WS_CHILD | WS_VISIBLE, m_wndSplitterV.IdFromRowCol(0, 1));
// 建立各視圖
m_wndSplitterV.CreateView(0, 0, RUNTIME_CLASS(CSceneView), CSize(600, 600), pContext);
m_wndSplitterH.CreateView(0, 0, RUNTIME_CLASS(CPitchView), CSize(100, 100), pContext);
m_wndSplitterH.CreateView(1, 0, RUNTIME_CLASS(CYawView), CSize(100, 100), pContext);
m_wndSplitterH.CreateView(2, 0, RUNTIME_CLASS(CRollView), CSize(100, 100), pContext);
m_wndSplitterH.CreateView(3, 0, RUNTIME_CLASS(CControlView), CSize(100, 100), pContext);
// 設定初始行高比例
m_wndSplitterV.SetRowInfo(0, IDEAL_RAWHEIGHT, 0);
m_bCreateSplitter = TRUE;
// 啟用主場景視圖接收命令訊息
m_wndSplitterV.SetActivePane(0, 0, NULL);
return bResult;
}
覆寫 OnSize 回應視窗縮放,按比例分配寬高:
void CMainFrame::OnSize(UINT nType, int cx, int cy) {
CMDIFrameWnd::OnSize(nType, cx, cy);
CRect rect; GetClientRect(rect);
if (m_bCreateSplitter) {
// 左側佔 3/4,右側佔 1/4
m_wndSplitterV.SetColumnInfo(0, rect.Width() * 3 / 4, 10);
m_wndSplitterV.SetColumnInfo(1, rect.Width() / 4, 10);
// 右側四行平均分配,最後一行佔 1/2
m_wndSplitterH.SetRowInfo(0, rect.Height() / 6, 10);
m_wndSplitterH.SetRowInfo(1, rect.Height() / 6, 10);
m_wndSplitterH.SetRowInfo(2, rect.Height() / 6, 10);
m_wndSplitterH.SetRowInfo(3, rect.Height() / 2, 10);
}
m_wndSplitterV.RecalcLayout();
m_wndSplitterH.RecalcLayout();
}
分割視圖下的命令路由遵循:View → Document → Frame → App。多視圖切換會改變焦點,影響選單命令啟用狀態。例如「開始」命令僅在 CSceneView 擁有焦點時啟用,實作方式:
void CMainFrame::OnUpdateStartCmd(CCmdUI* pCmdUI) {
CWnd* pActive = m_wndSplitterV.GetActivePane(0, 0);
pCmdUI->Enable(pActive && pActive->IsKindOf(RUNTIME_CLASS(CSceneView)));
}
本框架通過 CFixSplitterWnd 封裝固定分割邏輯,結合巢狀 CreateStatic/CreateView 實現複雜佈局,並示範動態佈局與命令路由控制。開發者可據此快速構建專業級多視圖應用,並輕鬆擴展自定義分割行為(如鎖定比例、最小尺寸限制等)。