VC++ CMemDC类的扩展

在VC++6.0的那个年代,MFC是不自带CMemDC操作类的,此类是为了解决双缓存绘图问题,当初因为项目需要自写了一个CMemDC类;现在MFC虽然自带了CMemDC类,但是不支持alpha通道,仍然很是鸡肋, 于是解决当初自写的CMemDC和MFC自带的CMemDC类重新编写了这个类(为了防止名字冲突,重命名CMemoryDC),代码如下:

class CMemoryDC : public CDC
{
public:
	CMemoryDC(CDC& dc, CWnd* pWnd):
		m_dc(dc), m_bMemDC(FALSE), m_hBufferedPaint(NULL), m_hOldBmp(NULL), m_hBmp(NULL), m_pWnd(pWnd)
	{
		ASSERT_VALID(pWnd);

		pWnd->GetClientRect(m_rect);

		m_rect.right += pWnd->GetScrollPos(SB_HORZ);
		m_rect.bottom += pWnd->GetScrollPos(SB_VERT);

		HDC hdcPaint = NULL;
		m_hBufferedPaint = BeginBufferedPaint(dc.GetSafeHdc(), m_rect, BPBF_TOPDOWNDIB, NULL, &hdcPaint);

		if (m_hBufferedPaint != NULL && hdcPaint != NULL)
		{
			m_bMemDC = TRUE;
			this->Attach(hdcPaint);
		}
		else
		{
			if (this->CreateCompatibleDC(&m_dc))
			{
				BITMAPINFO bi;
				bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
				bi.bmiHeader.biBitCount = 32;
				bi.bmiHeader.biHeight = m_rect.Height();
				bi.bmiHeader.biWidth = m_rect.Width();
				bi.bmiHeader.biPlanes = 1;
				bi.bmiHeader.biCompression = BI_RGB;
				bi.bmiHeader.biXPelsPerMeter = 0;
				bi.bmiHeader.biYPelsPerMeter = 0;
				bi.bmiHeader.biClrUsed = 0;
				bi.bmiHeader.biSizeImage = ((m_rect.Width() * 32 + 31) & (~31)) >> 3 * m_rect.Height();
				PVOID pvBits = NULL;
				m_hBmp = ::CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, &pvBits, 0, 0);//创建32位位图  
				m_hOldBmp = (HBITMAP)this->SelectObject((HBITMAP)m_hBmp);
			}
		}
	}

	CMemoryDC(CDC& dc, const CRect& rect):
		m_dc(dc), m_bMemDC(FALSE), m_hBufferedPaint(NULL), m_hOldBmp(NULL), m_rect(rect), m_hBmp(NULL), m_pWnd(NULL)
	{
		ASSERT(!m_rect.IsRectEmpty());

		m_pWnd = dc.GetWindow();
		HDC hdcPaint = NULL;
		m_hBufferedPaint = BeginBufferedPaint(dc.GetSafeHdc(), m_rect, BPBF_TOPDOWNDIB, NULL, &hdcPaint);

		if (m_hBufferedPaint != NULL && hdcPaint != NULL)
		{
			m_bMemDC = TRUE;
			this->Attach(hdcPaint);
		}
		else
		{
			if (this->CreateCompatibleDC(&m_dc))
			{
				BITMAPINFO bi;
				bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
				bi.bmiHeader.biBitCount = 32;
				bi.bmiHeader.biHeight = m_rect.Height();
				bi.bmiHeader.biWidth = m_rect.Width();
				bi.bmiHeader.biPlanes = 1;
				bi.bmiHeader.biCompression = BI_RGB;
				bi.bmiHeader.biXPelsPerMeter = 0;
				bi.bmiHeader.biYPelsPerMeter = 0;
				bi.bmiHeader.biClrUsed = 0;
				bi.bmiHeader.biSizeImage = ((m_rect.Width() * 32 + 31) & (~31)) >> 3 * m_rect.Height();
				PVOID pvBits = NULL;
				m_hBmp = ::CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, &pvBits, 0, 0);//创建32位位图  
				m_hOldBmp = (HBITMAP)this->SelectObject((HBITMAP)m_hBmp);
			}
		}
	}

	virtual ~CMemoryDC()
	{
		if (m_hBufferedPaint != NULL)
		{
			this->Detach();
			EndBufferedPaint(m_hBufferedPaint, TRUE);
		}
		else if (m_bMemDC)
		{
			CRect rectClip;
			int nClipType = m_dc.GetClipBox(rectClip);

			if (nClipType != NULLREGION)
			{
				if (nClipType != SIMPLEREGION)
				{
					rectClip = m_rect;
				}

				// 这种方式绘制会丢失alpha色彩信息
				// m_dc.BitBlt(rectClip.left, rectClip.top, rectClip.Width(), rectClip.Height(), this, rectClip.left, rectClip.top, SRCCOPY);

				BLENDFUNCTION blendFunc32bpp;
				blendFunc32bpp.AlphaFormat = AC_SRC_ALPHA;
				blendFunc32bpp.BlendFlags = 0;
				blendFunc32bpp.BlendOp = AC_SRC_OVER;
				blendFunc32bpp.SourceConstantAlpha = 255;
				::AlphaBlend(m_dc.GetSafeHdc(), rectClip.left, rectClip.top, rectClip.Width(), rectClip.Height(),
					m_hDC, rectClip.left, rectClip.top, rectClip.Width(), rectClip.Height(), blendFunc32bpp);
				//::UpdateLayeredWindow(m_pWnd->GetSafeHwnd(), m_dc.GetSafeHdc(), NULL, &CSize(rectClip.Width(), rectClip.Height()), GetSafeHdc(), &CPoint(rectClip.left, rectClip.top), 0, &blendFunc32bpp, ULW_COLORKEY | ULW_ALPHA);
			}

			this->SelectObject((HBITMAP)m_hOldBmp);
		}
	}

	CDC& GetDC() { return m_bMemDC ? *this : m_dc; }
	BOOL IsMemDC() const { return m_bMemDC; }
	BOOL IsVistaDC() const { return m_hBufferedPaint != NULL; }

protected:
	CDC&     m_dc;
	BOOL     m_bMemDC;
	HANDLE   m_hBufferedPaint;
	HBITMAP  m_hBmp;
	HBITMAP m_hOldBmp;
	CRect    m_rect;
	CWnd*	 m_pWnd;
};

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值