在vc 中怎样实现双倍缓冲?

cetcscada 2004-12-20 11:00:19
谢谢,最好有个例子。
...全文
82 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
zhangqu_980371 2004-12-21
  • 打赏
  • 举报
回复
转载的, 对你或许有用:
关键字 双缓冲
原作者姓名 戚高

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

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

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

ming6424 2004-12-20
  • 打赏
  • 举报
回复
int DrawAtBackGround(HDC hdc)
{

// Temporary DC.Background DC.
HDC hdcTemp;

// Temporary Bitmap.Used to fill hdcTemp.
// 用于填充临时DC
HBITMAP hBitmapTemp;

// Create a temporary DC for drawing bitmaps on it.
hdcTemp = CreateCompatibleDC(NULL);

// Create a Bitmap that will be selected to hdcTemp.
hBitmapTemp = CreateCompatibleBitmap(hdc,WIDTH,HEIGHT);
//填充临时DC
SelectObject(hdcTemp,hBitmapTemp);

......
在临时DC上画图

// 将临时DC的内容拷贝到窗口DC
BitBlt(hdc,0,0,WIDTH,HEIGHT,hdcTemp,0,0,SRCCOPY);



// Destroy all DC objects.
DeleteObject(hBitmapTemp);


DeleteCompatibleDC(hdcTemp);

return TRUE;
}
秋叶君 2004-12-20
  • 打赏
  • 举报
回复
将要绘制的图形绘制到一个内存图片上,刷新时拷到视图上。

19,469

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 图形处理/算法
社区管理员
  • 图形处理/算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧