CFrameWnd::OnCreateClient 是建立客戶區視圖的關鍵。SDI 應用程式中,覆寫此函數並建立 CSplitterWnd 即可實現分割。
// MainFrm.cpp
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) {
// 1. 建立 2 行 1 列靜態分割器
if (!m_wndSplitter.CreateStatic(this, 2, 1))
return FALSE;
// 2. 取得客戶區尺寸計算分割比例
CRect rect;
GetClientRect(&rect);
CSize size = rect.Size();
int cyTop = size.cy / 2 - 10; // 上方窗格高度
// 3. 建立上方視圖 (第 0 列)
if (!m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CTopView), CSize(0, cyTop), pContext))
return FALSE;
// 4. 建立下方視圖 (第 1 列),高度 0 表示填滿剩餘
if (!m_wndSplitter.CreateView(1, 0, RUNTIME_CLASS(CBottomView), CSize(0, 0), pContext))
return FALSE;
return TRUE;
}
class CMainFrame : public CFrameWnd {
protected:
CSplitterWnd m_wndSplitter; // 分割器成員變數
// ...
virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext);
DECLARE_MESSAGE_MAP()
};
CTopView、CBottomView 衍生自 CViewRUNTIME_CLASS 宏可解析 (需 #include "TopView.h" 等)// 依據具體需求調整
int cyTop = 200; // 固定 200 像素
// 或
int cyTop = size.cy * 2 / 3; // 佔 2/3
// 或載入上次使用者調整的位置 (從註冊表/INI 讀取)
// 在 CreateStatic 後、CreateView 前
m_wndSplitter.SetRowInfo(0, cyTop, 50); // 第 0 列理想高度、最小高度
m_wndSplitter.SetRowInfo(1, 100, 50); // 第 1 列理想、最小
| 錯誤 | 原因 | 解決 |
|---|---|---|
| 編譯錯誤:m_wndSplitter 未宣告 | MainFrm.h 缺少成員變數 | 加入 CSplitterWnd m_wndSplitter; |
| 執行時 Assert 失敗 / 視圖空白 | RUNTIME_CLASS 對應類別未正確宣告/實作 | 檢查 View 類別 DECLARE_DYNCREATE/IMPLEMENT_DYNCREATE |
| 分割條無法拖動 | 視窗樣式缺少 WS_THICKFRAME 或分割器樣式問題 | 確認 Frame 樣式、分割器建立參數 |
| 雙視圖文檔同步問題 | 同一文檔雙視圖需處理 OnUpdate | 覆寫 OnUpdate 同步捲軸/選取狀態 |
if (!m_wndSplitter.CreateStatic(this, 1, 2)) // 1 行 2 列
return FALSE;
int cxLeft = size.cx / 2 - 10;
if (!m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CLeftView), CSize(cxLeft, 0), pContext))
return FALSE;
if (!m_wndSplitter.CreateView(0, 1, RUNTIME_CLASS(CRightView), CSize(0, 0), pContext))
return FALSE;
掌握 OnCreateClient → CreateStatic(2,1) → CreateView(0,0) → CreateView(1,0) 這四步,SDI 視窗分割即刻上手,靈活構建專業多窗格介面。