滾動條雖少單獨使用(常被滾動視圖、SpinCtrl 替代),但在自定義視圖、大數據可視化、自繪控件中仍不可或缺。MFC CScrollBar 封裝創建、範圍管理、位置同步、箭頭啟用狀態及 WM_HSCROLL/WM_VSCROLL 消息處理。本文系統講解完整用法。
BOOL Create(LPCTSTR lpszText, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID = 0xffff);
| 風格 | 方向 | 對應消息 |
|---|---|---|
SBS_VERT | 垂直 | WM_VSCROLL |
SBS_HORZ | 水平 | WM_HSCROLL |
// 垂直滾動條
m_vScroll.Create(WS_CHILD | WS_VISIBLE | SBS_VERT, rect, this, IDC_VSCROLL);
// 水平滾動條
m_hScroll.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ, rect, this, IDC_HSCROLL);
| 操作 | 函數 | 說明 |
|---|---|---|
| 設置滾動範圍 | SetScrollRange(int nMin, int nMax, BOOL bRedraw=TRUE) | 包含邊界,如 0~100 共101個位置 |
| 獲取滾動範圍 | GetScrollRange(LPINT lpMin, LPINT lpMax) | 輸出最小/最大值 |
| 獲取當前位置 | GetScrollPos() | 返回 nMin~nMax 間值 |
| 設置當前位置 | SetScrollPos(int nPos, BOOL bRedraw=TRUE) | 自動鉤住在範圍內 |
| 顯示/隱藏 | ShowScrollBar(BOOL bShow=TRUE) | 不改變位置狀態 |
| 啟用/禁用箭頭 | EnableScrollBar(UINT nArrowFlags) | 見下表 |
| 標誌 | 效果 |
|---|---|
ESB_ENABLE_BOTH | 兩個箭頭均啟用 (默認) |
ESB_DISABLE_LTUP | 禁用左/上箭頭 |
ESB_DISABLE_RTDN | 禁用右/下箭頭 |
ESB_DISABLE_BOTH | 禁用兩個箭頭 (滾動條變灰) |
滾動條不發送命令消息,而是向父窗口發送 WM_VSCROLL/WM_HSCROLL。父窗口類中重載:
ON_WM_VSCROLL()
ON_WM_HSCROLL()
afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
nSBCode:滾動動作代碼(見下表)nPos:當前拖動位置(僅 SB_THUMBTRACK/SB_THUMBPOSITION 有效)pScrollBar:發送消息的滾動條指針(多滾動條共用處理函數時識別用)| 代碼 | 含義 | nPos 有效性 |
|---|---|---|
SB_TOP | 滾動到頂部/最左 | 無效 |
SB_BOTTOM | 滾動到底部/最右 | 無效 |
SB_LINEUP | 向上/左滾動一行 | 無效 |
SB_LINEDOWN | 向下/右滾動一行 | 無效 |
SB_PAGEUP | 向上/左滾動一頁 | 無效 |
SB_PAGEDOWN | 向下/右滾動一頁 | 無效 |
SB_THUMBTRACK | 拖動滑塊中(實時) | 有效:當前位置 |
SB_THUMBPOSITION | 拖動結束釋放鼠標 | 有效:最終位置 |
SB_ENDSCROLL | 拖動完成(用戶鬆開鼠標) | 無效 |
void CMyView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) {
// 1. 識別滾動條 (多滾動條時)
if (pScrollBar->GetDlgCtrlID() != IDC_MY_VSCROLL) {
CView::OnVScroll(nSBCode, nPos, pScrollBar);
return;
}
// 2. 獲取當前位置
int curPos = pScrollBar->GetScrollPos();
int minPos, maxPos;
pScrollBar->GetScrollRange(&minPos, &maxPos);
int newPos = curPos;
// 3. 根據動作計算新位置
switch (nSBCode) {
case SB_TOP: newPos = minPos; break;
case SB_BOTTOM: newPos = maxPos; break;
case SB_LINEUP: newPos = max(minPos, curPos - 1); break;
case SB_LINEDOWN: newPos = min(maxPos, curPos + 1); break;
case SB_PAGEUP: newPos = max(minPos, curPos - GetPageSize()); break;
case SB_PAGEDOWN: newPos = min(maxPos, curPos + GetPageSize()); break;
case SB_THUMBTRACK: // 實時拖動
case SB_THUMBPOSITION: newPos = nPos; break; // nPos 已在範圍內
case SB_ENDSCROLL: break; // 可用於觸發延遲渲染
}
// 4. 位置實際改變時更新
if (newPos != curPos) {
pScrollBar->SetScrollPos(newPos);
OnScrollPositionChanged(newPos); // 自定義響應邏輯
}
CView::OnVScroll(nSBCode, nPos, pScrollBar);
}
圖片 5000x3000,視口 800x600,需雙向滾動查看。
nMax = max(0, picHeight - viewHeight),nMin = 0viewHeight * 0.9 (留 10% 重疊)SB_THUMBTRACK 觸發 Invalidate() 重繪OnDraw 中 dc.SetViewportOrg(0, -scrollPos) 平移繪圖原點void CImageView::OnInitialUpdate() {
CScrollView::OnInitialUpdate();
CSize sz(5000, 3000); // 圖片邏輯尺寸
SetScrollSizes(MM_TEXT, sz); // CScrollView 自動管理滾動條
}
void CImageView::OnDraw(CDC* pDC) {
// CScrollView 已自動設置視口原點,直接繪製邏輯座標即可
pDC->DrawImage(m_image, 0, 0, 5000, 3000);
}
提示:繼承
CScrollView可自動獲得滾動條管理、範圍計算、視口原點同步,手動操作CScrollBar僅在非視圖類、特殊佈局時需要。
SetScrollRange(0, 100) 表示 0~100 共 101 個離散位置,非像素數min/max 校驗pScrollBar->GetDlgCtrlID() 識別ShowScrollBar(FALSE) 後位置保持,再顯示恢復原位本文整理自 MFC 經典技術文檔,適用於 VC6~VS2022 所有版本。