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

VC++ SDK 實作分隔條:從視窗類別註冊到滑鼠拖曳調整佈局完整教學

     編輯:VC 教學

分隔條本質:只是一個普通視窗

分隔條擁有獨立視窗類別、視窗程序,需經 RegisterClass 註冊、CreateWindow 建立。無特殊魔法,核心在於 WM_MOUSEMOVE 處理中同步調整鄰近視窗幾何屬性。

視窗類別註冊


WNDCLASS wc = {0};
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)COLOR_BTNSHADOW; // 1. 背景色
wc.hCursor = LoadCursor(NULL, IDC_SIZEWE);   // 2. 雙向調整游標
wc.hInstance = hInstance;
wc.lpfnWndProc = (WNDPROC)SplitterProc;      // 3. 視窗程序
wc.lpszClassName = _T("MySplitter");         // 4. 類別名稱
wc.style = 0;
RegisterClass(&wc);

主視窗 WM_SIZE 佈局邏輯 (熱身)

使用 DeferWindowPos 批次移動/調整大小,避免多次重繪閃爍:


case WM_SIZE: {
    HDWP hdwp = BeginDeferWindowPos(4);
    RECT rc, rcStatus, rcTree;
    GetClientRect(hDlg, &rc);
    GetClientRect(hStatus, &rcStatus);
    GetWindowRect(hTree, &rcTree);
    
    // 狀態列置底
    DeferWindowPos(hdwp, hStatus, NULL, 0, rc.bottom - rcStatus.bottom, rc.right, rcStatus.bottom, SWP_NOZORDER);
    // 樹狀視圖:固定寬度、高度扣除狀態列
    DeferWindowPos(hdwp, hTree, NULL, 0, 0, rcTree.right - rcTree.left, rc.bottom - rcStatus.bottom, SWP_NOMOVE|SWP_NOZORDER);
    // 分隔條:緊貼樹狀視圖右側,寬度 2px
    DeferWindowPos(hdwp, hSplitter, NULL, rcTree.right - rcTree.left, 0, 2, rc.bottom - rcStatus.bottom, SWP_NOZORDER);
    // 列表視圖:佔滿剩餘區域
    DeferWindowPos(hdwp, hList, NULL, rcTree.right - rcTree.left + 2, 0, 
        rc.right - (rcTree.right - rcTree.left) - 2, rc.bottom - rcStatus.bottom, SWP_NOZORDER);
    EndDeferWindowPos(hdwp);
    break;
}

分隔條視窗程序:滑鼠捕捉與即時調整


LRESULT CALLBACK SplitterProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    switch (msg) {
    case WM_LBUTTONDOWN:
        SetCapture(hwnd); break;
    case WM_LBUTTONUP:
        ReleaseCapture(); break;
    case WM_MOUSEMOVE: {
        if ((wParam & MK_LBUTTON) && GetCapture() == hwnd) {
            HDWP hdwp = BeginDeferWindowPos(3);
            RECT rc, rcStatus, rcTree;
            GetClientRect(GetParent(hwnd), &rc);
            GetClientRect(hStatus, &rcStatus);
            GetWindowRect(hTree, &rcTree);
            
            int x = LOWORD(lParam); // 滑鼠客戶區 X 座標
            // 樹狀視圖寬度跟隨滑鼠
            DeferWindowPos(hdwp, hTree, NULL, 0, 0, rcTree.right - rcTree.left + x, rc.bottom - rcStatus.bottom, SWP_NOMOVE|SWP_NOZORDER);
            // 分隔條水平位置跟隨
            DeferWindowPos(hdwp, hSplitter, NULL, rcTree.right - rcTree.left + x, 0, 0, 0, SWP_NOSIZE|SWP_NOZORDER);
            // 列表視圖寬度自適應
            DeferWindowPos(hdwp, hList, NULL, rcTree.right - rcTree.left + x + 2, 0,
                rc.right - (rcTree.right - rcTree.left) - x - 2, rc.bottom - rcStatus.bottom, SWP_NOZORDER);
            EndDeferWindowPos(hdwp);
        }
        break;
    }
    default:
        return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}

為何不用 MoveWindow?

MoveWindow 會觸發每個視窗獨立重繪,導致整個介面閃爍。DeferWindowPos 批次提交,單次重繪,體驗順滑。

執行畫面

SDK 實作分隔條示例介面

延伸思考

  • 支援垂直分隔條 (IDC_SIZENS 游標)
  • 加入最小/最大寬度限制
  • 雙擊分隔條自動調整至最佳寬度
  • 封裝為 C++ 類別 (CSplitterWnd 風格)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved