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 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 要在Win10上使用VC6.进行调试,您需要按照以下步骤操作: 1. 打开VC6.,打开您要调试的项目。 2. 在“生成”菜单中选择“配置管理器”。 3. 在“配置管理器”对话框中,选择“Active(Debug)”配置。 4. 点击“确定”按钮,关闭“配置管理器”对话框。 5. 在“调试”菜单中选择“开始调试”或按下F5键。 6. 在弹出的“选择调试器”对话框中,选择“本地Windows调试器”。 7. 点击“确定”按钮,开始调试您的程序。 请注意,VC6.已经过时,可能无法在最新的Windows版本上正常工作。建议您使用更现代的开发工具,如Visual Studio 2019。 ### 回答2: 在Win10的VC6.0中使用Debug模式需要进行一些设置和操作,以下步骤可以帮助您进行Debug: 1. 在VC6.0中选择“菜单栏- Tools(工具)”- “Options(选项)”。 2. 在弹出的窗口中,选择“Debug(调试)”选项卡。 3. 在左边列表中选择“General(常规)”选项。 4. 在右边列表中选择“Enable Debugging(启用调试)”。 5. 单击“OK”按钮,关闭窗口。 6. 打开项目,在菜单栏中选择“Project(项目)”- “Settings(设置)”。 7. 在弹出的窗口中,选择“Debug(调试)”选项卡。 8. 在左边列表中选择“Debug(调试)”目录。 9. 在右边列表中选择“Generate Debug Info(生成调试信息)”。 10. 单击“OK”按钮,关闭窗口。 11. 在需要Debug的地方插入断点,可通过点击代码行左侧的空白区域或使用快捷键F9实现。 12. 编译整个项目,选择“Debug”配置并启动程序。 13. 程序运行到断点处,按F11进入函数内部,F10跳过函数调用。 14. 在断点调试窗口中可以查看变量的值,步进和断点的控制。 15. Debug结束后,可通过选择“Project”- “Clean”清除编译后的文件和清除其他资源。 以上是Win10的VC6.0 Debug使用方法,需要注意的是,可能会遇到兼容性问题,建议使用更现代的IDE进行编程和Debug。 ### 回答3: VC6.0是一款十分实用的开发工具,用于Windows操作系统的编程与开发。想要在Win10上使用VC6.0的debug功能,需要先了解如何设置相关环境。 首先,需要在VC6.0中设置编译选项。打开“Project”菜单,选择“Settings”,在“Link”选项卡中勾选“Generate Debug Info”选项;在“C/C++”选项卡中勾选“Debug Information Format”并设置为“Program Database”;在“Optimization”选项卡中关闭所有优化选项。 其次,需要在Win10中设置符号文件路径。打开“系统属性”窗口,在“高级”选项卡中选择“环境变量”,在系统变量中设置“_NT_SYMBOL_PATH”变量为“srv*c:\symbols*https://msdl.microsoft.com/download/symbols”。 接着,在启动程序时需要选中“调试”配置。打开“菜单栏”中的“Debug”按钮,在“选择Debug”菜单中选择“应用程序”,即可启动程序进行debug调试。 在程序运行过程中,可以使用Visual Studio的调试功能。比如,在代码中设置好断点,程序运行到该处时就会暂停,可以查看变量值、运行顺序等,来排除程序中的bug。 总之,Win10的VC6.0 debug调试需要在编译选项、符号文件路径和程序启动时进行设置,同时结合Visual Studio的调试功能,从而更加方便地进行程序调试和debug。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值