MFC 图像闪烁原理及规避方法

闪烁的原理:
在知道图形显示闪烁的原因之后,对症下药就好办了。首先当然是去掉MFC
提供的背景绘制过程了。实现的方法很多,
* 可以在窗口形成时给窗口的注册类的背景刷付NULL
* 也可以在形成以后修改背景
static CBrush brush(RGB(255,0,0));
SetClassLong(this->m_hWnd,GCL_HBRBACKGROUND,(LONG)(HBRUSH)brush);
* 要简单也可以重载OnEraseBkgnd(CDC* pDC)直接返回TRUE
这样背景没有了,结果图形显示的确不闪了,但是显示也象前面所说的一样,
变得一团乱。怎么办?这就要用到双缓存的方法了。双缓冲就是除了在屏幕上有
图形进行显示以外,在内存中也有图形在绘制。我们可以把要显示的图形先在内存中
绘制好,然后再一次性的将内存中的图形按照一个点一个点地覆盖到屏幕上去(这个
过程非常快,因为是非常规整的内存拷贝)。这样在内存中绘图时,随便用什么反差
大的背景色进行清除都不会闪,因为看不见。当贴到屏幕上时,因为内存中最终的图形
与屏幕显示图形差别很小(如果没有运动,当然就没有差别),这样看起来就不会闪。(转载自网上)

 

自己的总结:在使用invalidate()的时候,设置成true的时候,调用ondraw()这时内部会用背景颜色来重绘dc,这相当于再动态图像中插入了一白色空帧,所以会出项图像闪烁(白帧闪现),所以防止闪烁的方法就是防止白帧的出现,一种,是直接用invalidate(false),但对于动态图像,这样会造成dc里的内容越来,另外一种方法就是双缓存技术,用两个dc,在备用dc里画图,然后把备用dc拷贝到前台dc显示(实验证明,这样前台dc的内容会自动擦除,这种擦除无论用什么颜色的帧擦除都不影响,因为他是在内存中进行的,并不出现在显示界面,所以相当于前面说的白色帧擦除在后台内存中进行了),再调用invalidate(false),这样就不会出现闪烁,并且界面能实施更新!

 

下面的代码是使用双缓存技术实时显示方波,不闪烁!

void CtestdcView::OnStart()
{
 // TODO: Add your command handler code here
 m_bDraw=TRUE;
 
 SetTimer(0,200,NULL);//设置定时器
}

 

void CtestdcView::OnTimer(UINT_PTR nIDEvent)
{
 // TODO: Add your message handler code here and/or call default
   Invalidate(FALSE);//响应定时器
}

 

void CtestdcView::OnDraw(CDC* pDC)
{
 static int count=0;//记录数组下标向前推进的点
 static int count1=0;//滚屏完后点数组下标点,用于确定重绘的起点
 static int ncount=0;//记录滚屏了多少次
 CtestdcDoc* pDoc = GetDocument();
 ASSERT_VALID(pDoc);
 if (!pDoc)
  return;

 CRect rect;
 GetClientRect(&rect);
 int nClientWidth=rect.right;
 int nClientHeight=rect.bottom;
 CDC MemDc;
 MemDc.CreateCompatibleDC(pDC);
 CBitmap VirtualBMP;
 VirtualBMP.CreateCompatibleBitmap(pDC,nClientWidth,nClientHeight);
 
 CBitmap*poldbmp=MemDc.SelectObject(&VirtualBMP);//创建空位图
 MemDc.FillSolidRect(0,0,nClientWidth,nClientHeight,RGB(255,255,255));//用指定颜色清除位图
 
 CBrush br,*poldbr;
 br.CreateSolidBrush(RGB(0,0,0));
 poldbr=MemDc.SelectObject(&br);
 MemDc.Rectangle(rect);//把背景刷黑
 MemDc.SelectObject(poldbr);
 int xpoint=rect.right;
 int nWidth=100;
 CPen mypen,*poldpen;
 mypen.CreatePen(PS_SOLID,1,RGB(255,0,0));
 poldpen=MemDc.SelectObject(&mypen);
 if(m_bDraw==TRUE)
 {
   count++;//记录次数
   for(int i=count1;i<count;i++)
   {
     int startoffset=(count1+1)*nWidth-ncount*xpoint;//起始偏移点
  int xCor,x1Cor;
  if(i==count1)//客户区的开头,需要特殊处理
  {
   xCor=0;
   x1Cor=startoffset;
  }
  else
  {
   xCor=startoffset+(i-count1-1)*nWidth;
   x1Cor=xCor+nWidth;
  }
  if(x1Cor>xpoint)
  {
   x1Cor=xpoint;
   count1=i;//记录到好多次,超出屏幕范围,最后一次分成两段,两个屏幕都要绘
   ncount++;//记录屏幕超了好多次
  }
  
  MemDc.MoveTo(xCor,testarray[i]);
  MemDc.LineTo(x1Cor,testarray[i]);
  MemDc.MoveTo(x1Cor,testarray[i]);
  MemDc.LineTo(x1Cor,testarray[i+1]);
  
   }
  
  
 }
 pDC->BitBlt(0,0,nClientWidth,nClientHeight,&MemDc,0,0,SRCCOPY);
 MemDc.SelectObject(poldpen);
 mypen.DeleteObject();
 br.DeleteObject();
 VirtualBMP.DeleteObject();
 MemDc.DeleteDC();
 
}

你可能感兴趣的:(MFC 图像闪烁原理及规避方法)