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 area
		Graphics 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);
}
posted @ 2015-11-06 10:14  爱好奇  阅读(390)  评论(0编辑  收藏  举报