在 MDI 應用程式中,如何程式化控制多組工具列的初始停靠佈局 (如並排停靠於頂部、或一左一右)?MFC 提供 DockControlBar,但參數較抽象。本文提供一個實用的輔助函數 DockControlBarLeftOf,讓你能像拖曳操作一樣,精確指定「工具列 B 停靠在工具列 A 的左側/右側」。
DockControlBarLeftOf 實現加入 CMainFrame 為 protected 成員函數:
void CMainFrame::DockControlBarLeftOf(CToolBar* pBar, CToolBar* pLeftOf)
{
CRect rect;
DWORD dwStyle;
UINT nDockBarID = 0;
// 1. 強制重新計算佈局,確保 GetWindowRect 取得準確座標
RecalcLayout(TRUE);
pLeftOf->GetWindowRect(&rect);
rect.OffsetRect(1, 0); // 稍微偏移 1 像素,模擬拖曳間距
// 2. 根據參考工具列當前停靠邊緣,決定目標停靠邊緣 ID
dwStyle = pLeftOf->GetBarStyle();
if (dwStyle & CBRS_ALIGN_TOP) nDockBarID = AFX_IDW_DOCKBAR_TOP;
else if (dwStyle & CBRS_ALIGN_BOTTOM) nDockBarID = AFX_IDW_DOCKBAR_BOTTOM;
else if (dwStyle & CBRS_ALIGN_LEFT) nDockBarID = AFX_IDW_DOCKBAR_LEFT;
else if (dwStyle & CBRS_ALIGN_RIGHT) nDockBarID = AFX_IDW_DOCKBAR_RIGHT;
// 3. 核心:呼叫 DockControlBar,傳入計算好的矩形,模擬「拖曳到指定位置」效果
// 此時 MFC 會將 pBar 作為浮動工具列停靠在 pLeftOf 旁邊
DockControlBar(pBar, nDockBarID, &rect);
}
CMainFrame::OnCreate)// 1. 建立兩組工具列 (需對應兩個工具列位圖資源 IDR_MAINFRAME, IDR_WINDOW)
if (!m_wndToolBar1.CreateEx(this, TBSTYLE_FLAT | TBSTYLE_LIST,
WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_wndToolBar1.LoadToolBar(IDR_MAINFRAME)) return -1;
if (!m_wndToolBar2.CreateEx(this, TBSTYLE_FLAT | TBSTYLE_LIST,
WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_wndToolBar2.LoadToolBar(IDR_WINDOW)) return -1;
// 2. 啟用停靠功能
m_wndToolBar1.EnableDocking(CBRS_ALIGN_ANY);
m_wndToolBar2.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
// 3. 佈局:第一組標準停靠頂部,第二組停靠在第一組左側
DockControlBar(&m_wndToolBar1); // 標準停靠
DockControlBarLeftOf(&m_wndToolBar2, &m_wndToolBar1); // 精確並排
務必在 `.rc` 資源檔中包含兩個工具列位圖資源:ToolBar1.bmp (ID: IDR_MAINFRAME) 與 ToolBar2.bmp (ID: IDR_WINDOW),按鈕數量、尺寸需與代碼邏輯一致。
DockControlBar 若傳入 lpRect 參數,MFC 內部會判斷該矩形相對於目標停靠邊緣的位置,模擬使用者拖曳工具列到該矩形區域並釋放滑鼠的行為。我們利用此特性,透過取得參考工具列螢幕座標並微調,實現「並排停靠」的精確控制。