65.9K
CodeProject is changing. Read more.
Home

Buffered CScrollView

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.89/5 (9 votes)

Dec 9, 2003

viewsIcon

55711

downloadIcon

1191

A reusable class inherited from CScrollView to implement buffered scrolling

Abstract

Article is on a reusable class inherited from CScrollView to implement buffered scrolling.

Objective

Although "double buffered drawing" is a common technique that every intermediate programmer knows, tt’s quite tricky to implement a smoothly no flicker scrolling view. What if an application already drawing directly on a CScrollView wants to use the technique? Does it need to change much code? No. All those tricky things can be concealed in one reusable class. All you need is to inherit your class from CCachedScrollView instead of CScrollView.

Implementation

  • First Step: Create a class CCachedScrollView inherited from CScrollView using the MFC class wizard.
  • Second Step: Add member fields CacheBitmap that is the memory bitmap, CacheValid and CacheRect for scroll buffer. At last, process the WM_PAINT message by OnPaint.

CachedScrollView.h

class CCachedScrollView : public CScrollView
{
 DECLARE_DYNCREATE(CCachedScrollView)
protected:
 CCachedScrollView(); 
 virtual ~CCachedScrollView();
 virtual void OnDraw(CDC* pDC) { }
private:
 CBitmap CacheBitmap;
public:
 BOOL CacheValid;
 CRect CacheRect;
 void SetCacheSize(SIZE sz) {
  if (CacheRect.IsRectNull()) 
   CacheRect=CRect(CPoint(0,0),sz);
 } DECLARE_MESSAGE_MAP()
 afx_msg void OnPaint();
};

CachedScrollView.cpp

 
void CCachedScrollView::OnPaint()
{
 CPaintDC dc(this); 
 OnPrepareDC(&dc);
 if (CacheRect.IsRectNull()) 
 {
  OnDraw(&dc);
  return;
 }
 if (CacheBitmap.m_hObject==NULL) 
  CacheBitmap.CreateCompatibleBitmap(&dc,CacheRect.Width(),
CacheRect.Height()); CRect ClientRect; GetClientRect(ClientRect); CPoint org=dc.GetViewportOrg(); ClientRect.OffsetRect(-org.x,-org.y); if (!CacheRect.PtInRect(ClientRect.TopLeft()) || !CacheRect.PtInRect(ClientRect.BottomRight())) { CacheRect.OffsetRect( ClientRect.CenterPoint()-CacheRect.CenterPoint()); CacheValid=FALSE; } CDC mdc; mdc.CreateCompatibleDC(&dc); mdc.SelectObject(&CacheBitmap); if (!CacheValid) { mdc.SelectStockObject(WHITE_BRUSH); mdc.SelectStockObject(NULL_PEN); mdc.Rectangle(0,0,CacheRect.Width(),CacheRect.Height()); mdc.SelectStockObject(BLACK_PEN); mdc.SetViewportOrg(-CacheRect.left,-CacheRect.top); OnDraw(&mdc); mdc.SetViewportOrg(0,0); CacheValid=TRUE; } dc.SelectClipRgn(NULL); dc.BitBlt(CacheRect.left,CacheRect.top, CacheRect.Width(),CacheRect.Height(),&mdc,0,0,SRCCOPY); }

Usage

You can write your own view inherited from CCachedScrollView, pay attention to call
the SetCacheSize() method in InitUpdate() for setting the buffer image size.