GDI双缓冲绘图
Posted luo1873626242
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GDI双缓冲绘图相关的知识,希望对你有一定的参考价值。
一、简介
在进行复杂图形绘制时,若直接在屏幕DC上进行绘制,则会出现明显的闪烁。闪烁产生的原因是当绘制的图形较为 复杂时,图形绘制过程中就被刷新到屏幕上,导致结果断断续续地显示出来。双缓冲绘图的原理是在另开辟一块内存用于绘制,当所有绘制工作完成后将内存数据一 次性拷贝到屏幕上。
双缓冲绘图步骤:
创建兼容DC(CreateCompatibleDC)
创建兼容位图(CreateCompatibleBitmap)
将兼容位图选入兼容DC(SelectObject)
在兼容DC中进行绘制工作
将兼容DC中的像素拷贝至屏幕DC(BitBlt)
从兼容DC中换出兼容位图(SelectObject)
删除兼容位图(DeleteObject)
删除兼容DC(DeleteObject)
二、实现:
演示程序绘制了从窗口中心发射的300条射线,为了凸显双缓冲的效果,特意在绘制每条线段时添加延时操作(sleep)。可以发现,若直接在屏幕DC上绘制,能够明显感觉到每条线段的绘制过程,而采用双缓冲则无此现象。
直接绘制代码:
void CtestBFDlg::OnBnClickedDirectDraw() { // TODO: 在此添加控件通知处理程序代码 CPen newPen; CPen *pOldPen; CBrush newBrush; CBrush *pOldBrush; CRect zcRect; CDC *pDc; CPoint cenpoint; CPoint point; pDc = Picture.GetDC(); Picture.GetClientRect(&zcRect); newPen.CreatePen(PS_SOLID,1,RGB(0,255,0));//画笔 pOldPen = pDc->SelectObject(&newPen); newBrush.CreateSolidBrush(RGB(255,255,255));//画刷 pOldBrush=pDc->SelectObject(&newBrush); //绘制工作(直接在屏幕DC上作图) pDc->FillRect(zcRect,&newBrush); float radius=200; float degree=0; float x,y; float cenx,ceny; cenx=zcRect.Width()/2.0; ceny=zcRect.Height()/2.0; cenpoint.x=cenx; cenpoint.y=ceny; for(int i=0;i<300;i++) { pDc->MoveTo(cenpoint); degree=2*PI/300*i; point.x=radius*cos(degree)+cenx; point.y=radius*sin(degree)+ceny; Sleep(1); //刻意延时以凸显效果 pDc->LineTo(point); } pDc->SelectObject(pOldPen); pDc->SelectObject(pOldBrush); newBrush.DeleteObject(); newPen.DeleteObject(); ReleaseDC(pDc); }
双缓冲绘制代码:
void CtestBFDlg::OnBnClickedDFDraw() { // TODO: 在此添加控件通知处理程序代码 CPen newPen; CPen *pOldPen; CBrush newBrush; CBrush *pOldBrush; CRect zcRect; CDC *pDc; CPoint cenpoint; CPoint point; pDc = Picture.GetDC(); Picture.GetClientRect(&zcRect); CDC dc; dc.CreateCompatibleDC(pDc);//创建兼容DC CBitmap memBmp; memBmp.CreateCompatibleBitmap(pDc, zcRect.Width(), zcRect.Height());//创建兼容位图 CBitmap* OldBmp = dc.SelectObject(&memBmp);//将位图选入DC newPen.CreatePen(PS_SOLID,1,RGB(255,0,0)); pOldPen = dc.SelectObject(&newPen); newBrush.CreateSolidBrush(RGB(255,255,255)); pOldBrush=dc.SelectObject(&newBrush); //绘制工作(在兼容DC中作图) //**************************************************************** dc.FillRect(zcRect,&newBrush); float radius=200; float degree=0; float x,y; float cenx,ceny; cenx=zcRect.Width()/2.0; ceny=zcRect.Height()/2.0; cenpoint.x=cenx; cenpoint.y=ceny; for(int i=0;i<300;i++) { dc.MoveTo(cenpoint); degree=2*PI/300*i; point.x=radius*cos(degree)+cenx; point.y=radius*sin(degree)+ceny; Sleep(1); //此处刻意延时以凸显效果 dc.LineTo(point); } //**************************************************************** pDc->BitBlt(0,0,zcRect.Width(),zcRect.Height(),&dc,0,0,SRCCOPY);//将兼容DC中位图拷贝至屏幕DC dc.SelectObject(pOldPen); dc.SelectObject(pOldBrush); dc.SelectObject(OldBmp); newBrush.DeleteObject(); newPen.DeleteObject(); memBmp.DeleteObject(); dc.DeleteDC(); ReleaseDC(pDc); }
界面:
以上是关于GDI双缓冲绘图的主要内容,如果未能解决你的问题,请参考以下文章
在具有 DWM 合成的窗口上使用 GDI 绘图时是不是可以防止撕裂伪影?