这里提供一个SDK版的,支持窗口滚动条控制的类,MFC版本和使用方法都请参考这里。// H 文件 #pragma once class CScrollWnd { public: CScrollWnd(); virtual ~CScrollWnd(); public: void Attach(HWND hWnd); void Detach(); void SetSize(int nWidth, int nHeight); const SIZE& GetSize() const; const SIZE& GetScrollPos() const; const SIZE& GetPageSize() const; void ScrollToOrigin(BOOL bLeft, BOOL bTop); void OnHScroll(WPARAM wParam, LPARAM lParam); void OnVScroll(WPARAM wParam, LPARAM lParam); BOOL OnMouseWheel(WPARAM wParam, LPARAM lParam); void OnSize(WPARAM wParam, LPARAM lParam); private: void SetScrollClientRect(HWND hWnd, RECT& rect); int Get32BitScrollPos(int bar, BOOL bTrackPos, HWND hWndScrollBar); void UpdateScrollInfo(); void UpdateScrollBar(int bar, int windowSize, int displaySize, LONG& pageSize, LONG& scrollPos, LONG& deltaPos); HWND m_hWndAttach; SIZE m_pageSize; SIZE m_size; SIZE m_scrollPos; }; // CPP 文件 #include "StdAfx.h" #include "ScrollWnd.h" CScrollWnd::CScrollWnd() : m_hWndAttach(NULL) { m_pageSize.cx = 0; m_pageSize.cy = 0; m_size.cx = 0; m_size.cy = 0; m_scrollPos.cx = 0; m_scrollPos.cy = 0; } CScrollWnd::~CScrollWnd() { Detach(); } void CScrollWnd::Attach(HWND hWnd) { m_hWndAttach = hWnd; } void CScrollWnd::Detach() { m_hWndAttach = NULL; } void CScrollWnd::SetSize(int nWidth, int nHeight) { m_size.cx = nWidth; m_size.cy = nHeight; if(NULL != m_hWndAttach && ::IsWindow(m_hWndAttach)) { UpdateScrollInfo(); } } const SIZE& CScrollWnd::GetSize() const { return m_size; } const SIZE& CScrollWnd::GetScrollPos() const { return m_scrollPos; } const SIZE& CScrollWnd::GetPageSize() const { return m_pageSize; } void CScrollWnd::ScrollToOrigin(BOOL bLeft, BOOL bTop) { if(NULL == m_hWndAttach) { return ; } if(bLeft) { if(m_size.cx > 0 && m_pageSize.cx > 0 && m_scrollPos.cx > 0) { int deltaPos = -m_scrollPos.cx; m_scrollPos.cx += deltaPos; ::SetScrollPos(m_hWndAttach, SB_HORZ, m_scrollPos.cx, TRUE); ::ScrollWindowEx(m_hWndAttach, -deltaPos, 0, NULL, NULL, NULL, NULL, SW_ERASE | SW_INVALIDATE | SW_SCROLLCHILDREN); ::UpdateWindow(m_hWndAttach); } } if(bTop) { if(m_size.cy > 0 && m_pageSize.cy > 0 && m_scrollPos.cy > 0) { int deltaPos = -m_scrollPos.cy; m_scrollPos.cy += deltaPos; ::SetScrollPos(m_hWndAttach, SB_VERT, m_scrollPos.cy, TRUE); ::ScrollWindowEx(m_hWndAttach, 0, -deltaPos, NULL, NULL, NULL, NULL, SW_ERASE | SW_INVALIDATE | SW_SCROLLCHILDREN); } } } void CScrollWnd::OnHScroll(WPARAM wParam, LPARAM lParam) { if(NULL == m_hWndAttach) { return ; } const int lineOffset = 60; int deltaPos = 0; UINT nSBCode = LOWORD(wParam); UINT nPos = HIWORD(wParam); switch( nSBCode ) { case SB_LINELEFT: deltaPos = -lineOffset; break; case SB_LINERIGHT: deltaPos = lineOffset; break; case SB_PAGELEFT: deltaPos = -m_pageSize.cx; break; case SB_PAGERIGHT: deltaPos = m_pageSize.cx; break; case SB_THUMBTRACK: deltaPos = Get32BitScrollPos(SB_HORZ, TRUE, (HWND)lParam) - m_scrollPos.cx; break; case SB_THUMBPOSITION: deltaPos = Get32BitScrollPos(SB_HORZ, FALSE, (HWND)lParam) - m_scrollPos.cx; break; default: return; } int newScrollPos = m_scrollPos.cx + deltaPos; if(newScrollPos < 0) { deltaPos = -m_scrollPos.cx; } int maxScrollPos = m_size.cx - m_pageSize.cx; if(newScrollPos > maxScrollPos) { deltaPos = maxScrollPos - m_scrollPos.cx; } if(deltaPos != 0) { m_scrollPos.cx += deltaPos; ::SetScrollPos(m_hWndAttach, SB_HORZ, m_scrollPos.cx, TRUE); ::ScrollWindowEx(m_hWndAttach, -deltaPos, 0, NULL, NULL, NULL, NULL, SW_ERASE | SW_INVALIDATE | SW_SCROLLCHILDREN); ::UpdateWindow(m_hWndAttach); } } void CScrollWnd::OnVScroll(WPARAM wParam, LPARAM lParam) { if(NULL == m_hWndAttach) { return ; } const int lineOffset = 60; UINT nSBCode = LOWORD(wParam); UINT nPos = HIWORD(wParam); int deltaPos = 0; SCROLLINFO si = {sizeof(si), SIF_ALL}; GetScrollInfo(m_hWndAttach, SB_VERT, &si); switch( nSBCode ) { case SB_LINEUP: deltaPos = -lineOffset; break; case SB_LINEDOWN: deltaPos = lineOffset; break; case SB_PAGEUP: deltaPos = -m_pageSize.cy; break; case SB_PAGEDOWN: deltaPos = m_pageSize.cy; break; case SB_THUMBTRACK: deltaPos = Get32BitScrollPos(SB_VERT, TRUE, (HWND)lParam) - m_scrollPos.cy; break; case SB_THUMBPOSITION: deltaPos = Get32BitScrollPos(SB_VERT, FALSE, (HWND)lParam) - m_scrollPos.cy; break; default: return; } int newScrollPos = m_scrollPos.cy + deltaPos; if(newScrollPos < 0) { deltaPos = -m_scrollPos.cy; } int maxScrollPos = m_size.cy - m_pageSize.cy; if(newScrollPos > maxScrollPos) { deltaPos = maxScrollPos - m_scrollPos.cy; } if(deltaPos != 0) { m_scrollPos.cy += deltaPos; ::SetScrollPos(m_hWndAttach, SB_VERT, m_scrollPos.cy, TRUE); ::ScrollWindowEx(m_hWndAttach, 0, -deltaPos, NULL, NULL, NULL, NULL, SW_ERASE | SW_INVALIDATE | SW_SCROLLCHILDREN); ::UpdateWindow(m_hWndAttach); } } BOOL CScrollWnd::OnMouseWheel(WPARAM wParam, LPARAM lParam) { if(NULL == m_hWndAttach) { return FALSE; } int scrollMin = 0; int scrollMax = 0; SCROLLINFO si = {sizeof(si), SIF_ALL}; GetScrollInfo(m_hWndAttach, SB_VERT, &si); scrollMin = si.nMin; scrollMax = si.nMax; if(scrollMin == scrollMax) { return FALSE; } UINT nFlags = LOWORD(wParam); short zDelta = HIWORD(wParam); POINT pt = {LOWORD(lParam), HIWORD(lParam)}; int numScrollIncrements = abs(zDelta) / WHEEL_DELTA; int numScrollLinesPerIncrement = 0; ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &numScrollLinesPerIncrement, 0); if(numScrollLinesPerIncrement == WHEEL_PAGESCROLL) { OnVScroll(MAKEWPARAM(zDelta > 0 ? SB_PAGEUP : SB_PAGEDOWN, 0), NULL); return TRUE; } int numScrollLines = numScrollIncrements * numScrollLinesPerIncrement; numScrollLines = max(numScrollLines/3, 1); for(int i = 0; i < numScrollLines; ++i) { OnVScroll(MAKEWPARAM(zDelta > 0 ? SB_LINEUP : SB_LINEDOWN, 0), NULL); } return TRUE; } void CScrollWnd::OnSize(WPARAM wParam, LPARAM lParam) { UpdateScrollInfo(); } void CScrollWnd::SetScrollClientRect(HWND hWnd, RECT& rect) { ASSERT(NULL != hWnd); RECT rc; ::GetWindowRect(hWnd, &rc); POINT ptLeftTop = {rc.left, rc.top}; POINT ptRightBottom = {rc.right, rc.bottom}; ::ScreenToClient(hWnd, &ptLeftTop); ::ScreenToClient(hWnd, &ptRightBottom); rc.left = ptLeftTop.x; rc.top = ptLeftTop.y; rc.right = ptRightBottom.x; rc.bottom = ptRightBottom.y; ::GetClientRect(hWnd, &rect); int cx = ::GetSystemMetrics(SM_CXVSCROLL); int cy = ::GetSystemMetrics(SM_CYHSCROLL); if(rc.right >= (rect.right + cx)) { rect.right += cx; } if(rc.bottom >= (rect.bottom + cy)) { rect.bottom += cy; } } int CScrollWnd::Get32BitScrollPos(int bar, BOOL bTrackPos, HWND hWndScrollBar) { if(NULL == m_hWndAttach) { return 0; } HWND hWndScroll; if (NULL == hWndScrollBar) { hWndScroll = m_hWndAttach; } else { hWndScroll = hWndScrollBar; } SCROLLINFO si = {0}; si.cbSize = sizeof(SCROLLINFO); si.fMask = bTrackPos ? SIF_TRACKPOS : SIF_POS; ::GetScrollInfo(hWndScroll, bar, &si); return bTrackPos ? si.nTrackPos : si.nPos; } void CScrollWnd::UpdateScrollInfo() { if(NULL == m_hWndAttach) { return ; } RECT rect; SetScrollClientRect(m_hWndAttach, rect); SIZE windowSize = {rect.right - rect.left, rect.bottom - rect.top}; SIZE deltaPos = {0, 0}; UpdateScrollBar(SB_HORZ, windowSize.cx, m_size.cx, m_pageSize.cx, m_scrollPos.cx, deltaPos.cx); UpdateScrollBar(SB_VERT, windowSize.cy, m_size.cy, m_pageSize.cy, m_scrollPos.cy, deltaPos.cy); if(deltaPos.cx != 0 || deltaPos.cy != 0) { ::ScrollWindowEx(m_hWndAttach, deltaPos.cx, deltaPos.cy, NULL, NULL, NULL, NULL, SW_ERASE | SW_INVALIDATE | SW_SCROLLCHILDREN); ::UpdateWindow(m_hWndAttach); } } void CScrollWnd::UpdateScrollBar(int bar, int windowSize, int displaySize, LONG& pageSize, LONG& scrollPos, LONG& deltaPos) { int scrollMax = 0; deltaPos = 0; SCROLLINFO si = {sizeof(si), SIF_ALL}; ::GetScrollInfo(m_hWndAttach, bar, &si); int nPos = si.nPos; if(windowSize < displaySize ) { scrollMax = displaySize - 1; if(pageSize > 0 && scrollPos > 0) { scrollPos = (LONG)(1.0 * scrollPos * windowSize / pageSize); } pageSize = windowSize; scrollPos = min(scrollPos, displaySize - pageSize - 1); deltaPos = nPos - scrollPos; } else { pageSize = 0; scrollPos = 0; deltaPos = nPos; } memset(&si, 0, sizeof(SCROLLINFO)); si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_ALL; si.nMin = 0; si.nMax = scrollMax; si.nPage = pageSize; si.nPos = scrollPos; ::SetScrollInfo(m_hWndAttach, bar, &si, TRUE); }