使用两个简单类实现无闪烁重绘和背景缓冲绘图






4.88/5 (8投票s)
2000年3月28日

147291

2035
使双缓冲变得简单的两个类
引言
我在这里介绍两个类,它们可以用于
- 无闪烁绘图
- 缓冲绘图,例如,背景
这两个类的优点是
- 可以有多个缓冲区用于多种目的。与其他网站上的一些
CMemDC
类的代码不同,缓冲区和用于访问这些缓冲区的代码之间存在区别。 - 当我们对所有绘图操作使用
GetSafeCDC()
时,我们在打印或预览期间永远不会遇到问题,因为在这种情况下,我们只是绕过了指向OnDraw
提供的CDC
的指针。这种简单的方法永远不会失败。 - 兼容 16 位和 32 位
- 缓冲区可以分配一次。如果我们有一个大屏幕,我们不会为每个
OnDraw
事件分配一个新的大位图。如果只需要重绘屏幕的一部分,仍然可以声明和使用一个临时缓冲区。 - 如果由于系统资源有限而导致缓冲区分配失败,则所有绘图都将无缓冲地进行
- 如果我们的绘图操作持续很长时间,则可以定期(例如,每秒)向用户显示中间结果。这的实现很简单:在这些操作期间只需调用
CopyToScreen(1000)
。这将每秒将后台缓冲区的当前内容复制到屏幕上。
注意:在预览期间,提供给 OnDraw
的 CDC
内部是一个 CPreviewDC
。这是一个内部 MFC 类。这个类确实有一些函数被重载了,而不是虚函数。因此,当我使用其他 CMemDCs
实现时,我在打印和预览期间遇到了错误,因为这些 CMemDC
没有调用 CPreviewDC
的函数,而是调用了 CDC
的相应函数。
使用类
有很多方法可以使用这些类。请看 MemDc.h 中的声明。
使用示例,逐步解释
- 在您的
CView
派生类的头文件中定义一个或多个CBufferMemDC
。在我的例子中,我定义了两个缓冲区。一个用于静态的通用背景,另一个用于我必须更频繁地在背景上重绘的信息。也可以为绘图的最终结果分配一个额外的缓冲区,以缓冲整个窗口客户区,例如在用户使用 Alt-Tab 在应用程序之间切换的情况下。示例
CBufferMemDC m_BufferBackground; // a buffer for the part of drawing which does not change CBufferMemDC m_BufferFlickerFreeDrawing; // a buffer which is used for flicker free redrawing on top of // the background
- 将以下函数添加到您的
CView
派生类static void CalcSizeTotalAreaWnd( CDC* pDC, const YourView* pView, CRect& totalAreaWnd ) { if ( pDC->IsPrinting() ){ // if we are printing we get the total area from the clip box. // Perhaps there is a better way to get this information pDC->GetClipBox(&totalAreaWnd); } else { // if we don't print we just take the client area of the window pView->GetClientRect( totalAreaWnd ); } }
- 将您的
OnDraw
函数的实现放在另一个函数中。例如OnRedraw( CDC* pDC).
- 修改您的
OnDraw
函数void MyView::OnDraw( CDC* pDC ) { CRect totalAreaWnd; CalcSizeTotalAreaWnd( pDC, this, totalAreaWnd ); CMemDC memDC( pDC, totalAreaWnd, totalAreaWnd, &m_BufferBackground ); if ( pDC->IsPrinting() || m_BufferBackground.IsDirty()){ // draw what you want to draw, for example a line. We simply call here // our routine, which we have defined above. It is important not to // use memDC, but GetSafeCDC. See the descriptions of this function // in the header file. Note: OnRedraw is only called when the // background buffer is dirty or when we are printing. Printing // processes are not buffered because this can // create very big bitmaps if we use for example A0-printers OnRedraw( memDC.GetSafeCDC() ); // when we have drawn all, we have all information in the bitmap but // not on the screen. So we copy the contents of the buffer to the // screen, to show the user what has happened. The user will see only // the result and so we have realized the flicker free redrawing memDC.CopyToScreen(0); } }
我自己的实现更复杂,因为我不仅要缓冲背景,还要缓冲绘图期间的几个中间状态。但这对于这两个类来说不是问题,因为这两个类确实解决了这类问题的两个主要部分:如何处理缓冲区以及如何进行缓冲。
最后,我不得不说我对最终代码是多么小感到惊讶。
许可证
本文未附加明确的许可证,但可能在文章文本或下载文件本身中包含使用条款。如有疑问,请通过下面的讨论区联系作者。
作者可能使用的许可证列表可以在此处找到。