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

VC++ SDK 實作分割條控制項完整教學

     編輯:VC++

前言

分割條 是 Explorer 風格應用程式常用控制項,但鮮有完整實作教學。本文從視窗類別註冊、建立、訊息處理完整示範如何用純 SDK 打造分割條。

核心觀念:分割條就是普通視窗

擁有自己的視窗類別、視窗程序,需經過 RegisterClass 與 CreateWindow。

1. 註冊分割條視窗類別

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

2. 版面配置範例

示範介面包含:樹狀檢視、分割條、列表檢視、狀態列。所有子視窗控制代碼宣告為全域變數:hTree, hSplitter, hList, hStatus。

3. 主視窗 WM_SIZE 處理:重新配置子視窗

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);
    // 分割條:緊鄰樹狀檢視右側,寬度 2 像素
    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;

使用 DeferWindowPos 批次更新,避免多次重繪閃爍。

4. 分割條視窗程序:滑鼠拖曳調整

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 dx = (short)LOWORD(lParam); // 滑鼠水平位移
            
            // 樹狀檢視寬度改變
            DeferWindowPos(hdwp, hTree, NULL, 0, 0, 
                (rcTree.right - rcTree.left) + dx, rc.bottom - rcStatus.bottom,
                SWP_NOMOVE | SWP_NOZORDER);
            // 分割條位置跟隨
            DeferWindowPos(hdwp, hSplitter, NULL, 
                (rcTree.right - rcTree.left) + dx, 0, 0, 0,
                SWP_NOSIZE | SWP_NOZORDER);
            // 列表檢視寬度相對調整
            DeferWindowPos(hdwp, hList, NULL, 
                (rcTree.right - rcTree.left) + dx + 2, 0,
                rc.right - (rcTree.right - rcTree.left) - dx - 2,
                rc.bottom - rcStatus.bottom, SWP_NOZORDER);
            
            EndDeferWindowPos(hdwp);
        }
        break;
    default:
        return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}

關鍵技巧總結

  • SetCapture/ReleaseCapture 確保拖曳期間滑鼠訊息專屬分割條
  • 使用 DeferWindowPos 批次移動,避免中間狀態閃爍
  • 矩形運算是核心:精確計算各子視窗新位置與大小
  • 不使用 MoveWindow 等單獨移動函式,因會觸發多次重繪

分割條示範介面

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