zoukankan      html  css  js  c++  java
  • MFC 透明内存DC

    在MFC中绘制比较复杂图形,通常采用双缓冲技术来绘图,的确可以大大加快绘制速度和减少闪烁,但是有些情况也不尽然。

    我最近遇到了一个问题,采用的也是双缓冲来加快绘图,但是绘制效果还是不尽人意。A对象里大约有几百个可以绘画的对象,每个对象都没有填充背景,他们的背景是另一对象B。A和B在一个窗口中可能有N个,绘画时,先绘制B然后在绘制A,只有2、3个A对象的时候,绘画已经比较慢了,DEBUG下可以明显感觉到延迟,原因是我可能只改变了对象B或一个A对象,但是需要把所有的对象重新绘画一边,效率非常低,即使是用上双缓冲也不行,PS大家都用过,它里面有一个叫做透明层的概念,在透明层上画任何东西不影响下面的层,那么我们能不能将A对象绘画在一个"透明层"1上,将B对象绘画在另一"透明层"2上。改变A对象时只需要重新在"透明层"1重新绘制A对象,而"透明层"2不需要重新绘制,最后先画透明层1然后再画透明层2,这样效率就可以大大提高了。

    问题的关键之处是创建一个透明位图,然后在这个透明的位图上绘制图形。

    注意:演示代码使用了GDI+,因为GDI没有使用ARGB,不会改写Alpha的值,即使画了也显示不出来。

     1、首先写一个CPngMem类。

    class CPngMemDC
    {
    public:
    	CPngMemDC() : m_hBmp(NULL)
    	{
    	}
    	~CPngMemDC()
    	{
    		if (m_hBmp)
    			::DeleteObject(m_hBmp);
    	}
    
    	//创建内存DC
    	void CreateMemDC(CDC *pDC)
    	{
    		ASSERT(pDC);
    
    		if (m_MemDC.GetSafeHdc())
    			m_MemDC.DeleteDC();
    		m_MemDC.CreateCompatibleDC(pDC);
    	}
    
    	//创建位图,并将位图选进内存DC
    	void CreateBitmap(int nWidth, int nHeight)
    	{
    		BITMAPINFO bi;
    		bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    		bi.bmiHeader.biBitCount = 32;
    		bi.bmiHeader.biHeight = nHeight;
    		bi.bmiHeader.biWidth  = nWidth;
    		bi.bmiHeader.biPlanes = 1;
    		bi.bmiHeader.biCompression = BI_RGB;
    		bi.bmiHeader.biXPelsPerMeter = 0;
    		bi.bmiHeader.biYPelsPerMeter = 0;
    		bi.bmiHeader.biClrUsed = 0;
    		bi.bmiHeader.biSizeImage = 0;
    		bi.bmiHeader.biSizeImage = nWidth * nHeight * bi.bmiHeader.biBitCount / 8;
    
    		if (m_hBmp)
    			::DeleteObject(m_hBmp);
    		m_hBmp = ::CreateDIBSection(m_MemDC, &bi, 0, NULL, 0, 0);//创建32位位图
    
    		m_MemDC.SelectObject(m_hBmp);
    
    		m_nWidth = nWidth;
    		m_nHeight = nHeight;
    	}
    
    	void Draw(CDC *pDC)
    	{
    		BLENDFUNCTION bf;
    		bf.AlphaFormat = AC_SRC_ALPHA;
    		bf.BlendFlags = 0;
    		bf.BlendOp = AC_SRC_OVER;
    		bf.SourceConstantAlpha = 255;
    		
    		BOOL bRet = pDC->AlphaBlend(0, 0, m_nWidth, m_nHeight,
    &m_MemDC, 0, 0, m_nWidth, m_nHeight, bf);
    		VERIFY(bRet);
    	}
    
    	operator HDC()//重载HDC类型转换
    	{
    		return m_MemDC.GetSafeHdc();
    	}
    
    private:
    	CDC m_MemDC;
    	HBITMAP m_hBmp;
    
    	int m_nWidth;
    	int m_nHeight;
    };

    1、在对话框类中添加两个成员变量:

    private:
    	CPngMemDC m_pngMem1;
    	CPngMemDC m_pngMen2;

    2、在OnInitDialog()函数中创建内存DC和位图:

    	CClientDC dc(this);
    	CRect rcClient;
    	GetClientRect(rcClient);
    
    	m_pngMem1.CreateMemDC(&dc);
    	m_pngMem1.CreateBitmap(rcClient.Width(), rcClient.Height());
    
    	m_pngMen2.CreateMemDC(&dc);
    	m_pngMen2.CreateBitmap(rcClient.Width(), rcClient.Height());

    3、添加OnBnClickedOk()按钮响应函数:

    void CDlg::OnBnClickedOk()
    {
    	Graphics g1(m_pngMem1);
    	Pen pen1(Color(255, 255, 0, 0), 5);//红色
    	g1.DrawLine(&pen1, Point(100, 0), Point(100, 300));
    
    	Graphics g2(m_pngMen2);
    	Pen pen2(Color(0, 255, 0), 5);//绿色
    	g2.DrawLine(&pen2, Point(0, 150), Point(300, 150));
    
    	CClientDC dc(this);
    	
    	m_pngMem1.Draw(&dc);
    	m_pngMen2.Draw(&dc);
    }

    最后显示结果如下:

  • 相关阅读:
    016 vue的组件通信
    015 vue组件中的数据
    014 vue的组件化开发
    013 vue的js中的高阶函数
    012 vue的v-model的使用
    011 vue的购书案例
    010 vue的过滤器的使用
    CF1519F
    CF1519E
    CF1517F
  • 原文地址:https://www.cnblogs.com/dongc/p/5225133.html
Copyright © 2011-2022 走看看