zoukankan      html  css  js  c++  java
  • VC使用双缓冲避免绘图闪烁的正确使用方法【转】

    使用内存DC绘图,然后实现双缓冲,避免绘图闪烁,这个小技术简单但很有效。但是仍然有很多人说使用了双缓冲,图片却仍然有闪烁,分析了几个这样的例子,发现

    其实不是双缓冲的技术问题,而是使用者没有正确理解和使用双缓冲的方法。使用双缓冲要点如下:

    1. 保证绘图过程中的所有CDC及其继承类指向内存DC。

    在窗口或者视图中绘图,一般都是在OnDraw或者OnPaint事件中,但是有时根据需要绘图是通过调用其他类及函数完成比较复杂的绘制,在这些函数中,有时编写者会获取诸如CClientDC,然后绘图,此时的任何动作都会绕过缓冲区直接绘制到屏幕,从而造成闪烁。正确的做法是检查并修改所有绘图过程函数,避免直接获取CClientDC、CWindowDC、CPaintDC之类。而是采用传递CDC指针的方式写绘图类或者函数。

    2. 修改OnEraseBkgnd(CDC* /*pDC*/)  事件 

    将代码屏蔽,改为一句    return TRUE;   这样做是避免使用原来父类代码中的擦除屏幕语句。

    3. 另一个容易忽略的关键点-〉擦除背景。

    第2条是必要的,避免了擦除背景的工作,但是这不代表背景不需要擦除了,只不过这个擦除过程要放到内存缓冲区中去做。

    例如下面代码:

    void CGraphView::EraseBkgnd(CDC* pDC)
    {
     // TODO: Add your message handler code here and/or call default
       CRect rect;
       GetClientRect( &rect );
       CBrush brush;
       brush.CreateSolidBrush(GetColor(CColorClass::clrGraphBK) );
       pDC->FillRect( &rect, &brush );
     
    }
     
    void CGraphView::OnDraw(CDC* pDC)
    {
      
     CRect rectClient;
     GetClientRect( &rectClient );
     CMemDC memDC(pDC, rectClient);
     EraseBkgnd(&memDC);            // OnEraseBkgnd 失效了,但是仍然需要在内存缓冲区中擦除背景
     m_graph.Redraw( &memDC, rectClient );
     
    }

    如果要求更高的绘图效率,重画时可以采用局部擦除的办法,即擦除一定区域内的代码。

    使用双缓冲的整个步骤如下:

    定义内存设备CMemDC,将所有绘图DC指向该设备  ---〉去掉擦除背景语句 ---〉在内存DC中擦除背景

    -〉在内存DC中绘图 -〉结果切换到显示DC。

    实际应用于复杂图形绘制,没有任何闪烁变化。

    *文中提到的双缓冲代码CMemDC是个开源类,其内容如下:

    #ifndef _MEMDC_H_
    #define _MEMDC_H_
     
    //////////////////////////////////////////////////
    // CMemDC - memory DC
    //
    // Author: Keith Rule
    // Email:  keithr@europa.com
    // Copyright 1996-1999, Keith Rule
    //
    // You may freely use or modify this code provided this
    // Copyright is included in all derived versions.
    //
    // History - 10/3/97 Fixed scrolling bug.
    //                   Added print support. - KR
    //
    //           11/3/99 Fixed most common complaint. Added
    //                   background color fill. - KR
    //
    //           11/3/99 Added support for mapping modes other than
    //                   MM_TEXT as suggested by Lee Sang Hun. - KR
    //
    // This class implements a memory Device Context which allows
    // flicker free drawing.
     
    class CMemDC : public CDC {
    protected:
       CBitmap  m_bitmap;       // Offscreen bitmap
       CBitmap* m_oldBitmap;    // bitmap originally found in CMemDC
       CDC*     m_pDC;          // Saves CDC passed in constructor
       CRect    m_rect;         // Rectangle of drawing area.
       BOOL     m_bMemDC;       // TRUE if CDC really is a Memory DC.
         
       void Construct(CDC* pDC)
       {
            ASSERT(pDC != NULL);
     
            // Some initialization
            m_pDC = pDC;
            m_oldBitmap = NULL;
            m_bMemDC = !pDC->IsPrinting();
     
            if (m_bMemDC) {
                // Create a Memory DC
                CreateCompatibleDC(pDC);
                pDC->LPtoDP(&m_rect);
     
                m_bitmap.CreateCompatibleBitmap(pDC, m_rect.Width(), m_rect.Height());
                m_oldBitmap = SelectObject(&m_bitmap);
                 
                SetMapMode(pDC->GetMapMode());
                pDC->DPtoLP(&m_rect);
                SetWindowOrg(m_rect.left, m_rect.top);
            } else {
                // Make a copy of the relevent parts of the current DC for printing
                m_bPrinting = pDC->m_bPrinting;
                m_hDC       = pDC->m_hDC;
                m_hAttribDC = pDC->m_hAttribDC;
            }
     
            // Fill background
            FillSolidRect(m_rect, pDC->GetBkColor());
        }
     
    // TRK begin
    public:
       CMemDC(CDC* pDC                  ) : CDC() { pDC->GetClipBox(&m_rect); Construct(pDC); }
       CMemDC(CDC* pDC, const RECT& rect) : CDC() { m_rect = rect           ; Construct(pDC); }
    // TRK end
         
       virtual ~CMemDC()
       {       
            if (m_bMemDC) {
                // Copy the offscreen bitmap onto the screen.
                m_pDC->BitBlt(m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(),
                    this, m_rect.left, m_rect.top, SRCCOPY);           
                 
                //Swap back the original bitmap.
                SelectObject(m_oldBitmap);       
            } else {
                // All we need to do is replace the DC with an illegal value,
                // this keeps us from accidently deleting the handles associated with
                // the CDC that was passed to the constructor.           
                m_hDC = m_hAttribDC = NULL;
            }   
        }
         
        // Allow usage as a pointer   
        CMemDC* operator->()
        {
            return this;
        }   
     
        // Allow usage as a pointer   
        operator CMemDC*()
        {
            return this;
        }
    };
     
     
    #endif

    原文链接:http://blog.csdn.net/r3000/article/details/5454262 

  • 相关阅读:
    ajax实现异步请求的过程
    GET和POST的区别,何时使用POST?
    函数有几种调用方式?
    substring、slice、substr的区别
    Spring 调用 Stored Procedure 并获取返回值
    Oracle 中, 使用 Instr 函数 替换 OR
    Oracle Materialized View refresh
    Oracle中Union 和 Union All
    toString() 和 强制类型转换 (String)
    2013年这一年
  • 原文地址:https://www.cnblogs.com/lidabo/p/3406222.html
Copyright © 2011-2022 走看看