CSplitterWnd 本質是特殊框架視窗,內部建立多個 MDI 子視窗佈局。支援兩種模式:
Create(),執行時由使用者拖曳分割,最大 2×2,所有窗格共用同一 View 類別CreateStatic(),設計時固定行列,最大 16×16,每窗格可指定不同 View 類別| 函數 | 用途 | 關鍵參數 |
|---|---|---|
| Create | 動態分割 | pParentWnd, maxRows, maxCols, sizeMin, pContext |
| CreateStatic | 靜態分割 | pParentWnd, rows, cols, dwStyle, nID |
| CreateView | 填充靜態窗格 | row, col, pViewClass, sizeInit, pContext |
// MainFrm.cpp
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) {
// 建立 2 行 1 列靜態分割
if (!m_wndSplitter.CreateStatic(this, 2, 1))
return FALSE;
CRect rect;
GetClientRect(&rect);
int cyHalf = rect.Height() / 2 - 10;
// 第 0 行:CTopView
if (!m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CTopView), CSize(0, cyHalf), pContext))
return FALSE;
// 第 1 行:CBottomView
if (!m_wndSplitter.CreateView(1, 0, RUNTIME_CLASS(CBottomView), CSize(0, 0), pContext))
return FALSE;
return TRUE;
}
目標佈局:
+---------------------+
| CTopView | <-- 上方單一窗格 (檔案隊列)
+----------+----------+
| CLeftView| CRightView| <-- 下方左右分割 (本地/遠端目錄樹)
+----------+----------+
class CMainFrame : public CFrameWnd {
CSplitterWnd m_wndSplitterMain; // 主分割:上下
CSplitterWnd m_wndSplitterSub; // 子分割:左右 (放在主分割第 1 列)
// ...
};
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) {
// 1. 主分割:2 行 1 列
if (!m_wndSplitterMain.CreateStatic(this, 2, 1))
return FALSE;
CRect rect;
GetClientRect(&rect);
int cyTop = rect.Height() / 3; // 上方佔 1/3
// 1.1 上方窗格:CTopView (檔案隊列)
if (!m_wndSplitterMain.CreateView(0, 0, RUNTIME_CLASS(CTopView), CSize(0, cyTop), pContext))
return FALSE;
// 2. 子分割器建立在主分割第 1 列 (索引 1,0)
// 必須指定父視窗為主分割器,ID 需唯一
if (!m_wndSplitterSub.CreateStatic(&m_wndSplitterMain, 1, 2, WS_CHILD | WS_VISIBLE,
m_wndSplitterMain.IdFromRowCol(1, 0)))
return FALSE;
// 2.1 左下:CLeftView (本地目錄)
if (!m_wndSplitterSub.CreateView(0, 0, RUNTIME_CLASS(CLeftView), CSize(0, 0), pContext))
return FALSE;
// 2.2 右下:CRightView (遠端目錄)
if (!m_wndSplitterSub.CreateView(0, 1, RUNTIME_CLASS(CRightView), CSize(0, 0), pContext))
return FALSE;
// 3. 設定分割條樣式 (可選)
m_wndSplitterMain.SetRowInfo(0, cyTop, 50); // 最小高度 50
m_wndSplitterSub.SetColumnInfo(0, 200, 50); // 左欄預設 200,最小 50
return TRUE;
}
| 問題 | 解決方案 |
|---|---|
| 子分割器父視窗是誰? | 父視窗 = 父分割器 (&m_wndSplitterMain),而非 Frame |
| 子分割器 ID 如何指定? | 使用父分割器 IdFromRowCol(row, col) 取得該窗格預留 ID |
| 視圖類別必須預先宣告 | 在 MainFrm.h 前向宣告或包含對應 View 標頭檔 |
| 動態調整比例 | SetRowInfo/SetColumnInfo 設定理想/最小尺寸 |
| 存取子窗格 View 指標 | m_wndSplitterSub.GetPane(0,0) 回傳 CWnd*,需 dynamic_cast |
// 僅支援同一 View 類別
BOOL CChildFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) {
return m_wndSplitter.Create(this, 2, 2, CSize(100, 100), pContext);
}
OnDrawSplitter 自訂分割條外觀 (顏色、漸層、圖示)OnInvertTracker 控制拖曳反饋樣式WM_SETCURSOR 變更分割條游標靜態分割 + 巢狀分割器是構建複雜專業介面 (CuteFTP、VS IDE、Outlook) 的標準做法。掌握 CreateStatic → CreateView → 巢狀父視窗指定 → IdFromRowCol 這條主線,即可任意組合多窗格佈局。