WTL双缓冲类CDoubleBufferImpl的缺陷

WTL的双缓存类非常好用,但是要注意一点。这个DoPaint的重载函数中,只有传递给WM_PAINT中CPaintDC中的m_ps.rcPaint区域才能更新,其他区域将无法得到更新。这点需要了解下。

如果你在缓存DoPaint( CDCHandle dc) 获取的DC中,在rcPaint之外的绘图将无法在屏幕上显示。因为这个内存缓存只把rcPaint中的部分作为一个bitmap映射,其他部分没有映射。因此会越界的。

解决的方法就是不要使用InvalidateRect,直接使用InvalidateWindow。或者修改程序,把那个rcPaint传过来,自己DoPaint的时候小心。

修改的方法,可以参照atltheme.h中的CBufferedPaintImpl,把那个rect也一起传进来

///////////////////////////////////////////////////////////////////////////////
// CBufferedPaintImpl - provides buffered paint for any window

template <class T>
class ATL_NO_VTABLE CBufferedPaintImpl : public CBufferedPaintBase
{
public:
	CBufferedPaint m_BufferedPaint;
	BP_BUFFERFORMAT m_dwFormat;
	BP_PAINTPARAMS m_PaintParams;


// Overrideables
	void DoBufferedPaint(CDCHandle dc, RECT& rect)
	{
		HDC hDCPaint = NULL;
		if(IsBufferedPaintSupported())
			m_BufferedPaint.Begin(dc, &rect, m_dwFormat, &m_PaintParams, &hDCPaint);

		T* pT = static_cast<T*>(this);
                if(hDCPaint != NULL)
			pT->DoPaint(hDCPaint, rect);  //修改成类似这样
		else
			pT->DoPaint(dc.m_hDC, rect);  //修改成类似这样

		if(IsBufferedPaintSupported())
			m_BufferedPaint.End();
	}

	void DoPaint(CDCHandle /*dc*/, RECT& /*rect*/)
	{
		// must be implemented in a derived class
		ATLASSERT(FALSE);
	}
};


 

我修改成这样

///////////////////////////////////////////////////////////////////////////////
// CDoubleBufferImpl - Provides double-buffer painting support to any window

template <class T>
class CDoubleBufferImpl
{
public:
// Overrideables
	void DoPaint(CDCHandle /*dc*/,RECT& /*rect*/)
	                               //这里修改
	{
		// must be implemented in a derived class
		ATLASSERT(FALSE);
	}

// Message map and handlers
	BEGIN_MSG_MAP(CDoubleBufferImpl)
		MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
		MESSAGE_HANDLER(WM_PAINT, OnPaint)
#ifndef _WIN32_WCE
		MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
#endif // !_WIN32_WCE
	END_MSG_MAP()

	LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
	{
		return 1;   // no background painting needed
	}

	LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
	{
		T* pT = static_cast<T*>(this);
		ATLASSERT(::IsWindow(pT->m_hWnd));

		if(wParam != NULL)
		{
			RECT rect = { 0 };
			pT->GetClientRect(&rect);
			CMemoryDC dcMem((HDC)wParam, rect);//修改
			pT->DoPaint(dcMem.m_hDC,rect);
		}
		else
		{
			CPaintDC dc(pT->m_hWnd);
			CMemoryDC dcMem(dc.m_hDC, dc.m_ps.rcPaint);
			pT->DoPaint(dcMem.m_hDC, dc.m_ps.rcPaint);//修改
		}

		return 0;
	}
};


 

参考:

http://www.cnblogs.com/wdhust/archive/2011/01/12/1934042.html

http://bbs.csdn.net/topics/390488347

猜你喜欢

转载自blog.csdn.net/stevenkoh/article/details/9084145
WTL