首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC 教學

VC6.0 CSplitterWnd 動態與靜態分割視窗完整實戰:從巢狀分割到 CuteFTP 風格

     編輯:VC 教學

CSplitterWnd 核心認知

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

實戰一:單一文件介面 (SDI) 靜態分割上下兩窗格

// 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;
}

實戰二:巢狀分割實現 CuteFTP 風格四窗格佈局

目標佈局:

+---------------------+
|       CTopView      |  <-- 上方單一窗格 (檔案隊列)
+----------+----------+
| CLeftView| CRightView|  <-- 下方左右分割 (本地/遠端目錄樹)
+----------+----------+

步驟 1:MainFrm.h 宣告兩個分割器

class CMainFrame : public CFrameWnd {
    CSplitterWnd m_wndSplitterMain; // 主分割:上下
    CSplitterWnd m_wndSplitterSub;  // 子分割:左右 (放在主分割第 1 列)
    // ...
};

步驟 2:OnCreateClient 逐層建立

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

動態分割簡易範例 (2×2 最大)

// 僅支援同一 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 這條主線,即可任意組合多窗格佈局。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved