界面刷新的时候,CScrollView会先调用OnEraseBkgnd,将背景色刷新一次后才绘制视图,会造成闪烁问题。
解决方式:在CScrollView继承类中,接收ON_WM_ERASEBKGND()消息,然后函数屏蔽背景刷新函数。
ON_WM_ERASEBKGND() // 消息 BOOL CAView::OnEraseBkgnd(CDC* pDC){ //return CScrollView::OnEraseBkgnd(pDC) // 屏蔽 return true; }当移动滚动条时,CScrollView默认会先移动逻辑视图,如果你不是基于逻辑视图绘制的视图,而是基于物理视图绘制的话,快速移动滚动条时就会有重影问题。
解决方式:屏蔽掉移动滚动条时调用的移动逻辑视图函数;移动逻辑视图函数是ScrollWindow(),在CScrollView虚函数OnScrollBy中被调用到,所以重载该虚函数,将CScrollView::OnScrollBy的内容复制到重载的虚函数中,只屏蔽ScrollWindow()。
BOOL CScrollView::OnScrollBy(CSize sizeScroll, BOOL bDoScroll) { int xOrig, x; int yOrig, y; // don't scroll if there is no valid scroll range (ie. no scroll bar) CScrollBar* pBar; DWORD dwStyle = GetStyle(); pBar = GetScrollBarCtrl(SB_VERT); if ((pBar != NULL && !pBar->IsWindowEnabled()) || (pBar == NULL && !(dwStyle & WS_VSCROLL))){ // vertical scroll bar not enabled sizeScroll.cy = 0; } pBar = GetScrollBarCtrl(SB_HORZ); if ((pBar != NULL && !pBar->IsWindowEnabled()) || (pBar == NULL && !(dwStyle & WS_HSCROLL))){ // horizontal scroll bar not enabled sizeScroll.cx = 0; } // adjust current x position xOrig = x = GetScrollPos(SB_HORZ); int xMax = GetScrollLimit(SB_HORZ); x += sizeScroll.cx; if (x < 0) x = 0; else if (x > xMax) x = xMax; // adjust current y position yOrig = y = GetScrollPos(SB_VERT); int yMax = GetScrollLimit(SB_VERT); y += sizeScroll.cy; if (y < 0) y = 0; else if (y > yMax) y = yMax; // did anything change? if (x == xOrig && y == yOrig) return FALSE; if (bDoScroll){ // do scroll and update scroll positions // ScrollWindow(-(x-xOrig), -(y-yOrig));// 屏蔽移动逻辑视图函数 if (x != xOrig) SetScrollPos(SB_HORZ, x); if (y != yOrig) SetScrollPos(SB_VERT, y); } return TRUE; }使用的父窗口是CSplitterWnd时鼠标拖拽滚动条最终会调用OnScrollBy,但使用鼠标滚动轮的话是不会调用该函数的,所以需要通过接受鼠标滚动轮消息,直接使用SetScrollPos(SB_VERT, y);(SB_VERT:垂直方向)移动滚动条位置。
BOOL CScrollView::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) { // TODO: 在此添加消息处理程序代码和/或调用默认值 SetScrollPos(SB_VERT, GetScrollPosition().y-zDelta); Invalidate(); UpdateWindow(); // 触发视图重绘 return CScrollView::OnMouseWheel(nFlags, zDelta, pt); }