分隔條擁有獨立視窗類別、視窗程序,需經 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 批次提交,單次重繪,體驗順滑。

IDC_SIZENS 游標)CSplitterWnd 風格)