MFC中的窗口绘图问题

 

1.闪屏

如果按照常规的绘图过程,即每做完一个绘图操作,就马上进行窗口刷新,当绘图过程比较密集的时候,由于没绘制一次就刷新一次窗口,而刷新窗口是需要一定延时的,这就导致了在上一次的刷新还没有完成的时候,这一次的绘图又到来了,这就是常见的闪屏现象(screen flicker

 

2.双缓冲

         要避免闪屏的问题,只需要对每次绘图都进行窗口刷新,而是对所有的绘图完成之后再进行一次刷新,这既提高了效率,有避免了闪屏的问题。

         绘图的实质是将绘制的图形数据写入到一个内存块,然后计算机将这个内存块送到图像显示设备进行显示。默认的绘图过程也是如此,只不过它是每将一次的绘图数据写入到内存,就直接将这块内存发送到显示设备。而现在我们要做的是,将一个周期的内的绘图数据全部写入到同一个内存块中,这个周期完成之后,再将其送到显示设备。

代码的大致流程如下:

CBitmap memBmp;

CDC memDC;

memDC.CreateCompatibleDC(NULL);

   CDC *pDC=this->GetDC(); 

   CRect rect;

   m_chartBoard.GetWindowRect(rect);

   this->ScreenToClient(rect);

   memBmp.CreateCompatibleBitmap(pDC,rect.Width(),rect.Height());

   CBitmap *pOldBmp=memDC.SelectObject(&memBmp);

   COLORREF testColor=RGB(236,233,216);

   memDC.FillSolidRect(rect,testColor);

   //TODO:在这里使用memDC完成绘图操作

   pDC->BitBlt(0,0,rect.Width(),rect.Height(),&memDC,0,0,SRCCOPY);

  

   memBmp.DeleteObject();

   memDC.DeleteDC();

同时要重写窗口类的afx_msg BOOL OnEraseBkgnd(CDC* pDC)函数

BOOL CPlayBackDlg::OnEraseBkgnd(CDC* pDC)

{

//return CDialog::OnEraseBkgnd(pDC);

      return TRUE;       

}

        

从上面的代码可以看出,双缓冲使用一个位图对象CBitmap memBmp 作为绘图数据的存储对象,CBitmap *pOldBmp=memDC.SelectObject(&memBmp);将绘图操作的对象memDC和绘图数据的存储对象memBmp关联起来,在后续过程中使用memDC进行的绘图操作的绘图数据都会存储到memBmp中,它实质上是一个位图图像,最后用

pDC->BitBlt(0,0,rect.Width(),rect.Height(),&memDC,0,0,SRCCOPY);

将这个位图图像应用到设备环境中

 

 

3.局部重绘

         假如一个窗口上既有需要进行重复绘图的区域,又有一些不需要进行重复绘图的区域,如果再每个绘图周期都没有区别的对整个窗口进行重绘,这是很没有必要的,这里可以只对需要进行重复绘图的局部区域进行重绘。

         进行局部重绘可以通过CDC类函数

BOOL BitBlt(

   int x,

   int y,

   int nWidth,

   int nHeight,

   CDC* pSrcDC,

   int xSrc,

   int ySrc,

   DWORD dwRop

);

里的第14个参数进行指定,这四个参数指定了一个矩形,程序会将内存中的数据应用到这个设备所在环境的这个矩形上,实质上就是将绘图后生成的图像拷贝到窗口的指定区域进行显示。

       指定了这4个参数后,确实是可以实现局部重绘的功能了,但是对于那些在这个区域之外的界面在整个窗口丢失焦点(如,被其他程序窗口覆盖后又获得焦点)的情况,它们不会被重新绘制。这个问题的原因是我们在OnEraseBkgnd函数中没有区别的只返回一个TRUE,把它自带的这句代码

return CDialog::OnEraseBkgnd(pDC);

给注释掉了,函数

afx_msg BOOL OnEraseBkgnd(

   CDC* pDC

);

的功能是准备一个失效的区域进行重绘,重绘的过程是使用窗口类的背景画刷进行,它的功能是通知程序进行整个窗口的重绘。所以在这种情况下,我们需要调用CDialog::OnEraseBkgnd(pDC)进行整个窗口重绘。

 

大致的操作流程是:

<1>将所有的绘图操作全部放到OnPaint函数当中

void CPlayBackDlg::OnPaint()

{ 

   if(m_bChartDataInit)DrawChart(); 

   CDialog::OnPaint();

}

 

 

<2>OnEraseBkgnd里对绘图操作的情况进行区分

BOOL CPlayBackDlg::OnEraseBkgnd(CDC* pDC)

{

   if(m_bDrawChart)

      return TRUE;

   else

      return CDialog::OnEraseBkgnd(pDC);

}

 

作者:kfqcome 发表于2011-6-16 16:37:00 原文链接
阅读:16 评论:0 查看评论
posted on 2011-06-16 08:37  柯大侠  阅读(1496)  评论(0编辑  收藏  举报