WTL-双缓冲(double buffer)绘图
WTL中有两个Mix-in类: CDoubleBufferImpl和CDoubleBufferWindowImpl,用于创建双缓冲绘图窗口,用法非常简单。
下面创建了一个普通的WTL窗口类,在窗口的客户区中有大量的绘图工作,使用CDoubleBufferImpl类来消除绘图时的闪烁现象:
const COLORREF WHITE_COLOR = RGB(255,255,255);
const COLORREF BLUE_COLOR = RGB(0,0,255);
class CMainWindow :
public CWindowImpl<CMainWindow,CWindow,CSimpleWinTraits>,
public CDoubleBufferImpl<CMainWindow>
{public:
typedef CMainWindow _thisClass;
typedef CDoubleBufferImpl<_thisClass> _baseDblBufImpl;
BEGIN_MSG_MAP(CMainWindow)MSG_WM_CREATE(OnCreate)MSG_WM_DESTROY(OnDestroy)CHAIN_MSG_MAP(_baseDblBufImpl)END_MSG_MAP()int OnCreate(LPCREATESTRUCT lpCreateStruct)
{m_RectPen.CreatePen(PS_SOLID,1,BLUE_COLOR);return 0;
}void OnDestroy()
{PostQuitMessage(0);}void OnPaint(CDCHandle)
{CPaintDC dc(m_hWnd);DoPaint(dc.m_hDC);}void DoPaint(CDCHandle dc)
{CRect rc;GetClientRect(&rc);dc.FillRect(&rc,WHITE_COLOR);HPEN hOldPen = dc.SelectPen(m_RectPen);const int width = 5;int x = 0;
int count = rc.Width()/width;
int height = 0;
for (int i=0; i<count; i++){height = (int)((double)rand()*rc.Height())/RAND_MAX;dc.Rectangle(x,rc.Height(),x+width,rc.Height()-height);x += width;}dc.SelectPen(hOldPen);}/*
void DoPaint(CDCHandle dc){CRect rc;GetClientRect(&rc);int width = rc.Width(), height = rc.Height();//use GDI+ to draw in the client areaGraphics g(dc.m_hDC);SolidBrush whiteBrush(Color(255,255,255));g.FillRectangle(&whiteBrush,0,0,width,height);Pen bluePen(Color(0,0,255));const int dx = 5;int count = width/dx;int x = 0, y = 0, h = 0;for (int i=0;i<count;i++){h = ((double)rand()*height)/RAND_MAX;g.DrawRectangle(&bluePen,x,y,dx,h);x += dx;}}*/private:
CPen m_RectPen;};
值得一提的是,Windows Vista操作系统增加了对Double buffered paint的内建支持,这里有一篇文章介绍如何在Win32程序中使用这些API:
Using Windows Vista Built-In Double Buffering
在WTL中使用Vista提供的这一功能非常容易,最新的WTL库中提供了CBufferedPaintImpl和CBufferedPaintWindowImpl两个类,这两个类的用法和前面提到的两个WTL自带的双缓冲类几乎一样。区别仅仅是所重载的DoPaint()函数的参数稍有不同。
对于CBufferedPaintImpl类,所需重载的DoPaint()函数的样子如下所示:
void DoPaint(CDCHandle dc, RECT& rect)
{CRect rc(rect);dc.FillSolidRect(&rc,WHITE_COLOR);HPEN hOldPen = dc.SelectPen(m_RectPen);const int width = 5;int x = 0;
int count = rc.Width()/width;
int height = 0;
for (int i=0; i<count; i++){height = (int)((double)rand()*rc.Height())/RAND_MAX;dc.Rectangle(x,rc.Height(),x+width,rc.Height()-height);x += width;}dc.SelectPen(hOldPen);}