解决屏幕刷新闪烁的问题——双缓冲方法

Home / Hackintosh MrLee 2014-11-23 3586

下载本文所附源代码 图形为什么会闪烁的原因是:我们的绘图过程大多放在OnDraw或者OnPaint函数中,OnDraw在进行屏幕显示时是由OnPaint进行调用的。当窗口由于任何原因需要重绘时,总是先用背景色将显示区清除,然后才调用OnPaint,而背景色往往与绘图内容反差很大,这样在短时间内背景色与显示图形的交替出现,使得显示窗口看起来在闪。如果将背景刷设置成NULL,这样无论怎样重绘图形都不会闪了。当然,这样做会使得窗口的显示乱成一团,因为重绘时没有背景色对原来绘制的图形进行清除,而又叠加上了新的图形。有的人会说,闪烁是因为绘图的速度太慢或者显示的图形太复杂造成的,其实这样说并不对,绘图的显示速度对闪烁的影响不是根本性的。 如何实现双缓冲:在OnDraw(CDC *pDC)中:
CDC MemDC; //首先定义一个显示设备对象
       CBitmap MemBitmap;//定义一个位图对象
       //随后建立与屏幕显示兼容的内存显示设备
      MemDC.CreateCompatibleDC(NULL);
       //这时还不能绘图,因为没有地方画 ^_^
       //下面建立一个与屏幕显示兼容的位图,至于位图的大小嘛,可以用窗口的大小
      MemBitmap.CreateCompatibleBitmap(pDC,nWidth,nHeight);
       //将位图选入到内存显示设备中
       //只有选入了位图的内存显示设备才有地方绘图,画到指定的位图上
      CBitmap *pOldBit=MemDC.SelectObject(&MemBitmap);
       //先用背景色将位图清除干净,这里我用的是白色作为背景
       //你也可以用自己应该用的颜色
      MemDC.FillSolidRect(0,0,nWidth,nHeight,RGB(255,255,255));
       //绘图
      MemDC.MoveTo(……);
       MemDC.LineTo(……);
       //将内存中的图拷贝到屏幕上进行显示
      pDC->BitBlt(0,0,nWidth,nHeight,&MemDC,0,0,SRCCOPY);
       //绘图完成后的清理
      MemBitmap.DeleteObject();
       MemDC.DeleteDC();

以论坛的一个帖子例子为例来说明一些具体如何解决问题. 帖子那容是: 我想让一个区域动起来, 如何解决窗口刷新时区域的闪烁。
void CJhkljklView::OnDraw(CDC* pDC)
{
     CJhkljklDoc* pDoc = GetDocument();
     ASSERT_VALID(pDoc);
     // TODO: add draw code for native data here
             int i;
     int x[20],y[20];
     CPen hPen;
     POINT w[5];
    
             x[0]=a/100+10;
             x[1]=a/100+30;
                 x[2]=a/100+80;
                 x[3]=a/100+30;
                 x[4]=a/100+10;
                     y[0]=10;
                   y[1]=10;
                   y[2]=25;
                     y[3]=40;
                     y[4]=40;    
       for (i=0;i<5;i++)
       {         w[i].x=x[i];
       w[i].y=y[i];
       }
       //CClientDC dc(this);
             //hPen=CreatePen(PS_SOLID,1,RGB(255,0,0));
       CRgn argn,Brgn;
         CBrush abrush(RGB(40,30,20));
         argn.CreatePolygonRgn(w, 5, 1);// point为CPoint数组,
         pDC->FillRgn(&argn, &abrush);
         abrush.DeleteObject();
}
void CJhkljklView::OnTimer(UINT nIDEvent) 
{
     // TODO: Add your message handler code here and/or call default
         InvalidateRect(NULL,true);
         UpdateWindow();
         a+=100;
     CView::OnTimer(nIDEvent);
}
int CJhkljklView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
     if (CView::OnCreate(lpCreateStruct) == -1)
         return -1;
    
     // TODO: Add your specialized creation code here
     SetTimer(1,10,NULL);
     return 0;
}

利用定时器直接进行10毫秒的屏幕刷新,这样效果会出现不停的闪烁的情况.
解决方法利用双缓冲,首先触发WM_ERASEBKGND,然后修改返回TRUE; 定义变量:
CBitmap *m_PBitmapOldBackground ;
CBitmap m_bitmapBackground ;
CDC m_dcBackground;
//绘制背景
if(m_dcBackground.GetSafeHdc()== NULL|| (m_bitmapBackground.m_hObject == NULL))
     {
         m_dcBackground.CreateCompatibleDC(&dc);
         m_bitmapBackground.CreateCompatibleBitmap(&dc,rect.Width(),rect.Height()) ;
         m_pBitmapOldBackground = m_dcBackground.SelectObject(&m_bitmapBackground) ;
         //DrawMeterBackground(&m_dcBackground, rect);
         CBrush brushFill, *pBrushOld;        
         // 背景色黑色
         brushFill.DeleteObject();
         brushFill.CreateSolidBrush(RGB(255, 255, 255));
         pBrushOld = m_dcBackground.SelectObject(&brushFill);
         m_dcBackground.Rectangle(rect);
         m_dcBackground.SelectObject(pBrushOld);
     }
     memDC.BitBlt(0, 0, rect.Width(), rect.Height(), 
                       &m_dcBackground, 0, 0, SRCCOPY) ;
     //绘制图形
     int i;
     int x[20],y[20];
     CPen hPen;
     POINT w[5];
    
     x[0]=a/100+10;
     x[1]=a/100+30;
     x[2]=a/100+80;
     x[3]=a/100+30;
     x[4]=a/100+10;
    
     y[0]=10;
     y[1]=10;
     y[2]=25;
     y[3]=40;
     y[4]=40;
    
    
    
     for (i=0;i<5;i++)
     {         w[i].x=x[i];
     w[i].y=y[i];
     }
     //CClientDC dc(this);
     //hPen=CreatePen(PS_SOLID,1,RGB(255,0,0));
     CRgn argn,Brgn;
     CBrush abrush(RGB(40,30,20));
     argn.CreatePolygonRgn(w, 5, 1);// point为CPoint数组,
     memDC.FillRgn(&argn, &abrush);
     abrush.DeleteObject();
}

这样编译运行程序就会出现屏幕不闪烁的情况了.

本文链接:https://www.it72.com/292.htm

推荐阅读
最新回复 (0)
返回