双缓冲 不错的转一下算是!!

来源:互联网 发布:linux系统安全软件 编辑:程序博客网 时间:2024/05/18 20:49

双缓冲是一种常用的消除屏闪的方法,这段文字,是我本科毕业论中的一小段,用来说明显示原理的,现共享出来,共同交流一下

 

MFC程序中,经常会遇到这样的问题:在客户区内动态绘图,或者客户区被其它窗口遮挡而产生无效区域时,会产生闪烁现象,下面我们来分析一下这个问题。

CView类是由CWnd类继承而来,也就是说,CView类是窗口类,客户区就是一个窗口。在Windows程序中,窗口的的更新是通过处理WM_PAINT消息实现的,在更新之前,MFC程序会先处理WM_ERASEBKGND消息,该消息默认处理函数会使用预定义的画刷刷新窗口,作为背景色,然后WM_PAINT消息处理函数重绘窗口。而MFC程序预定义的用来刷新窗口的画刷是白色(24位色RGB255,255,255)),所以当动态绘图或重绘窗口时,客户区内是白色和图像交替出现,短时间内出现颜色的反差,由于人眼的视觉暂留作用,速度很快的情况不会看出反差,但是会有闪烁的感觉,这是用户所不能接受的,所以,在这里我们来解决这个问题。

首先,要把系统预定义画刷重绘部分去掉。

ClassWizard中为CConcaveView类(本系统所用的视图类,由CView类继承而来)添加WM_ERASEBKGND消息处理函数,编辑代码,发现其返回值调用了父类(CView类)的消息处理函数,很显然,用预义定画刷重新刷新窗口的工作是在父类中完成的,故应把函数调用删掉,另外,由于其返回的是BOOL类型,所以返回语句改为return TRUE

建立另一个缓冲区,并在其中作图。在绘图函数中,定义两个局部变量,其类型为CDC(设备上下文类)和CBitmap(位图类),在MFC程序中,存储器中的图像,一般是存储于位图中,而图像与设备的通信,是在设备上下文对象中完成的,所以,把CBitmap对象调入CDC对象中,就可以在设备上下文中作图了,其实质是在主存储器中作图,还没有写入到显存中。

把主存中的图像拷贝到显存,以显示图像。这步很简单,只要把自定义的设备上下文对像,送给系统预定义的设备上下文对像中即可。

总结其原理,出现闪烁的原因关键问题就是颜色的反差,消除了反差,闪烁自然就消除。但是双缓冲是有缺点的:

1.        由于两次绘图,运行速度比较慢,在某些追速度的应用中,效果不是很理想。

2.        使用了两倍的缓冲区空间,空间占用比较大,在某些大规模计算的应用中,不是理想首选。

 

以上就是在Windows程序设计中,双缓冲算法的思想,其实双缓冲只是一种方法,这个概念不只应用在绘图方面,还有数据的传输、数据库等很多地方,下面是代码样例(ADL语言和C++语言)

在文档/视图结构的MFC工程中,视图类有一个成员函数void OnDraw(CDC* pDC),它由Windows客户区刷新消息WM_PAINT消息的处理函数OnPaint所调用,用于处理当前视图的刷新工作。我们的绘图,就是在它中完成的。

前面已经讨论过客户区刷新时的闪烁问题,即双缓冲显示的算法,由上段所述,双缓冲处理消除闪烁的最佳位置,即OnDraw函数。下面将给出OnDraw函数的实现:

BOOL CConcaveView::OnEraseBkgnd(CDC* pDC)

{

      // 此函数为CView类中用默认画刷(白刷)刷新客户区函数的重写

      //return CView::OnEraseBkgnd(pDC);  //注释掉对父类刷新函数的调用,即摒掉了客户区的刷新

      return TRUE;

}

void CConcaveView::OnDraw(CDC* pDC)

{

      CConcaveDoc* pDoc = GetDocument();

      ASSERT_VALID(pDoc);

      CRect rect;  //定义矩形类对象,用于计算客户区大小

      CDC dc;  //定义新的设置上下文对象,下一步绘图就在这里

      CBitmap bitmap;  //定义新的位置,实际是一块缓冲区

      GetClientRect(&rect);  //计算客户区大小

      dc.CreateCompatibleDC(NULL);  创建新的DC

      bitmap.CreateCompatibleBitmap(pDC,rect.Width(),rect.Height());  //创建与当前设备匹配的位图,分配缓冲区空间

      dc.SelectObject(&bitmap);  //将缓冲区交与新的DC

      dc.FillSolidRect(0,0,rect.Width(),rect.Height(),RGB(255,255,255));  //用白色初始化缓冲区颜色

      //从此开始,就可以用新定义的dc画图了

      int i;

      gShowAnnotation(rect,&dc);  //显示注解

      gShowBitmap(g_currtopo,rect,&dc);  //显示范例位图

      if(m_nSelect!=ST_REASON||m_listbox.GetCount())

      {

             for(i=0;i<3;++i)

             {

                    pDoc->m_pCave[i]->Show(&dc);  //从文档类中取出所有图形对象,并调用Show方法显示。

             }

      }

 

      pDC->BitBlt(0,0,rect.Width(),rect.Height(),&dc,0,0,SRCCOPY);  //调用原系统DCBitBlt方法,将新缓冲区的内容以SRCCOPY(原拷贝)模式复制给原系统DC,此时,图形将出现在屏幕上

      bitmap.DeleteObject();  //删除位图,释放空间

      dc.DeleteDC();  //删除dc,释放空间

}