闪烁的原因与双缓冲

  做客户端的时候经常碰到闪烁的问题。以前直接就用双缓冲技术给解决了,压根就没有去思考里面的原理。前几天看了个资料,里面讲的蛮透彻,整理下吧。

  闪烁产生的原因是在极短的时间内,显示设备上的内容反差太大照成的。当绘图过程是 按 填充背景色->绘制图像 这种流程,并且绘制是直接作用在显示设备上时,就会产生闪烁现象。因为绘图过程是直接作用在显示设备上的,所以人眼会直接观察到 填充背景色 与 绘制图像 这2步。往往背景色与绘制图像的内容反差是很大的,从而闪烁就产生了。

  双缓冲技术的原理就是将 填充背景色->绘制图像 这个过程作用在后台缓存中,人眼所能观察到的是绘制完地图像。绘制完地图像的反差一般是很小的,故而就不会感觉的闪烁了。

  • bcb delph中一个 doublebuff的函数就能直接双缓冲了。
  • vc mfc 中需要自己用 HBitmap 去建立内存dc,这个dc就后台缓存
  • ddraw 中交换链的设置 就是为了建立后台缓存
  • d3d 中创建d3d设备时就能指定后台缓存的数目(默认 1个后台缓存)。

附上 mfc的后台缓存类

 

class CMemDC : public CDC
{
private:
CBitmap m_bitmap;
// Offscreen bitmap
CBitmap *m_oldBitmap; // bitmap originally found in CMemDC
CDC *m_pDC; // Saves CDC passed in constructor
CRect m_rect; // Rectangle of drawing area.
BOOL m_bMemDC; // TRUE if CDC really is a Memory DC.

public:
CMemDC(CDC
*pDC, const CRect *pRect=NULL) : CDC()
{
ASSERT(pDC
!= NULL);

// Some initialization
m_pDC = pDC;
m_oldBitmap
= NULL;
m_bMemDC
=!pDC->IsPrinting();

// Get the rectangle to draw
if(pRect == NULL)
{
pDC
->GetClipBox(&m_rect);
}
else
{
m_rect
=*pRect;
}

if(m_bMemDC)
{
// Create a Memory DC
CreateCompatibleDC(pDC);
pDC
->LPtoDP(&m_rect);

m_bitmap.CreateCompatibleBitmap(pDC, m_rect.Width(), m_rect.Height());
m_oldBitmap
= SelectObject(&m_bitmap);

SetMapMode(pDC
->GetMapMode());

SetWindowExt(pDC
->GetWindowExt());
SetViewportExt(pDC
->GetViewportExt());

pDC
->DPtoLP(&m_rect);
SetWindowOrg(m_rect.left, m_rect.top);
}
else
{
// Make a copy of the relevent parts of the current DC for printing
m_bPrinting = pDC->m_bPrinting;
m_hDC
= pDC->m_hDC;
m_hAttribDC
= pDC->m_hAttribDC;
}

// Fill background
FillSolidRect(m_rect, pDC->GetBkColor());
}

~CMemDC()
{
if(m_bMemDC)
{
// Copy the offscreen bitmap onto the screen.
m_pDC->BitBlt(m_rect.left,
m_rect.top,
m_rect.Width(),
m_rect.Height(),
this,
m_rect.left,
m_rect.top,
SRCCOPY);

//Swap back the original bitmap.
SelectObject(m_oldBitmap);
}
else
{
// All we need to do is replace the DC with an illegal value,
// this keeps us from accidently deleting the handles associated with
// the CDC that was passed to the constructor.
m_hDC = m_hAttribDC = NULL;
}
}

// Allow usage as a pointer
CMemDC*operator->()
{
returnthis;
}
// Allow usage as a pointer
operator CMemDC*()
{
returnthis;
}
};

 

 ============================================================

最近在做一个flash项目,发现闪烁的另外一个可能。

如果在控件的呈现过程中,是异步的,也会造成闪烁。

例子:

listbox的item 在normal 与 mousein状态时 如果item背景图是用同一个image控件,在不同的状态指定不同的图路径,则由于载图是个异步过程,载图时listbox的底色便显示出来,造成闪烁。

解决办法:呈现的切换不要使用异步。就上例来说

item背景图用2个image 在不同的状态指定某个image不可见(这个设置是个同步过程,所以不闪烁)。

<?xml version="1.0" encoding="utf-8"?>
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s
="library://ns.adobe.com/flex/spark"
xmlns:mx
="library://ns.adobe.com/flex/mx"
width
="100%" height="39" autoDrawBackground="true" currentState="normal">

<fx:Script>
<![CDATA[
import resource.SourceImages;
]]>
</fx:Script>

<s:states>
<s:State name="normal"/>
<s:State name="selected"/>
<s:State name="hovered"/>
</s:states>

<s:Image width="100%" height="100%"
source
="{SourceImages.listItemScheduleNormal}"
scaleMode
="stretch" includeIn="normal"/>

<s:Image width="100%" height="100%"
source
="{SourceImages.listItemScheduleDown}"
scaleMode
="stretch" includeIn="selected"/>

<s:Image width="100%" height="100%"
source
="{SourceImages.listItemScheduleLight}"
scaleMode
="stretch" includeIn="hovered"/>

<s:Label left="20" color="0xff4040" fontFamily="宋体" fontSize="12"
text
="{data.time}" verticalCenter="0"
color.hovered
="#404040"
color.normal
="#404040"
color.selected
="#CCD0D6"/>
<s:Label color="0xffff0000" fontFamily="宋体" fontSize="12" horizontalCenter="0" text="vs"
verticalCenter
="0"
color.hovered
="#404040"
color.normal
="#404040"
color.selected
="#CCD0D6"/>
<s:Label right="10" color="0x404040" fontFamily="宋体" fontSize="18" text="{data.bout}"
textAlign
="right" verticalCenter="0"
fontSize.hovered
="12"
color.normal
="#404040" fontSize.normal="12"
color.selected
="#CCD0D6" fontSize.selected="12"/>

</s:ItemRenderer>



 

posted @ 2010-07-05 18:07  迷花倚石忽已暝  阅读(701)  评论(0编辑  收藏  举报