您的位置:首页 > 其它

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

2011-10-31 13:21 381 查看
双缓冲方法解决屏幕刷新闪烁的问题
2009年02月24日 星期二 16:12

http://dev.21tx.com/2005/05/06/11850.html

下载本文所附源代码

关键字 双缓冲

原作者姓名 戚高

介绍

在论坛中经常见到关于刷新时界面闪烁的帖子,如何控制在进行高效绘图时不出现界面闪烁的感觉呢,下文就双缓冲方法进行讲解.
正文

图形为什么会闪烁的原因是:我们的绘图过程大多放在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();

}

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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: