双缓冲绘图

原文:http://www.ccrun.com/article.asp?i=434&d=17iz10

突显图形咋样制止闪烁,如何加强展现效用是问得相比多的题材。而且多数人认为MFC的绘图函数功效很低,总是想寻求另外的解决方案。
MFC的绘图效用真的不高但也不差,而且它的绘图函数使用相当简单,只要利用办法得当,再加上有的技巧,用MFC能够拿到功用很高的绘图程序。
自家想就自我长期(呵呵当然也只有2年多)使用MFC绘图的经验谈谈自己的部分见解。

1、展现的图片为何会闪烁?
   我们的绘图过程大多位于OnDraw或者OnPaint函数中,OnDraw在进展屏幕显示时是由OnPaint举办调用的。当窗口由于任何原因需要重绘时,总是先用背景观将展现区清除,然后才调用OnPaint,而背景象往往与绘图内容反差很大,那样在长期内背景观与映现图形的轮番现身,使得展现窗口看起来在闪。尽管将背景刷设置成NULL,这样无论咋样重绘图形都不会闪了。当然,这样做会使得窗口的显示乱成一团,因为重绘时从没背景象对原本绘制的图片举行破除,而又叠加上了新的图纸。有的人会说,闪烁是因为绘图的进度太慢或者显示的图样太复杂造成的,其实这样说并不对,绘图的展示速度对闪烁的震慑不是根本性的。例如在OnDraw(CDC
*pDC)中如此写:
pDC->MoveTo(0,0);
pDC->LineTo(100,100);
以此绘图过程应该是非凡简单、十分快了啊,不过带来窗口变化时依旧会看见闪烁。其实从道理上讲,画图的进程越复杂越慢闪烁应该越少,因为绘图用的年华与用背景清除屏幕所花的流年的比例越大人对闪烁的感觉到会越不精通。比如:清楚屏幕时间为1s制图时间也是为1s,这样在10s内的连接重画中就要闪烁5次;假设知道屏幕时间为1s不变,而绘图时间为9s,这样10s内的连日重画只会闪烁一回。这一个也足以测验,在OnDraw(CDC
*pDC)中这样写:
for(int i=0;i<100000;i++)
{
pDC->MoveTo(0,i);
pDC->LineTo(1000,i);
}
呵呵,程序有点变态,可是能证实问题。
   说到那里或许又有人要说了,为啥一个简单图形看起来没有复杂图形那么闪呢?这是因为复杂图形占的面积大,重画时造成的异样相比较大,所以倍感上要闪得厉害一些,不过闪烁频率要低。这为啥动画的重画频率高,而看起来却不闪?这里,我就要重新强调了,闪烁是什么样?闪烁就是异样,反差越大,闪烁越厉害。因为动画的接连多少个帧之间的出入很小所以看起来不闪。如若不信,可以在动画的每一帧中间加一张纯白的帧,不闪才怪呢。

2、如何防止闪烁
   在领略图形展现闪烁的原委之后,对症下药就好办了。首先当然是去掉MFC提供的背景绘制过程了。实现的法门很多,
* 可以在窗口形成时给窗口的注册类的背景刷付NULL
* 也可以在形成之后修改背景
   static CBrush brush(RGB(255,0,0));
   SetClassLong(this->m_hWnd,GCL_HBRBACKGROUND,(LONG)(HBRUSH)brush);
* 要简明也足以重载OnEraseBkgnd(CDC* pDC)直接回到TRUE
   这样背景没有了,结果图形展现的确不闪了,可是来得也象前边所说的一致,变得一团乱。肿么办?这就要用到双缓存的点子了。双缓冲就是除了在屏幕上有图形举办映现以外,在内存中也有图片在绘制。我们可以把要呈现的图样先在内存中绘制好,然后再一遍性的将内存中的图片按照一个点一个点地覆盖到屏幕上去(这么些过程至极快,因为是老大规整的内存拷贝)。那样在内存中绘制时,随便用哪些差别大的背景象举办割除都不会闪,因为看不见。当贴到屏幕上时,因为内存中最终的图形与屏幕显示图形差异很小(假设没有运动,当然就没有差距),那样看起来就不会闪。
// 本文转自 C++Builder探讨 –
http://www.ccrun.com/article.asp?i=434&d=17iz10

3、怎么着贯彻双缓冲
   首先付诸实现的次第,然后再解释,同样是在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();

地点的诠释应该很详细了,废话就不多说了。

4、怎么样增强绘图的频率
   我最首要做的是电力系统的网络图片的CAD软件,在一个窗口中多次要显得成千上万个电力元件,而各种元件又是由点、线、圆等基本图形组成。要是真要在两回重绘过程重画这么多元件,不问可知这一个进程是万分久远的。即使加上了图片的浏览效用,鼠标拖动图形滚动时需要开展大气的重绘,速度会慢得让用户将无法忍受。怎么做?唯有再研讨琢磨MFC的绘图过程了。
   实际上,在OnDraw(CDC
*pDC)中绘制的图并不是负有都显得了的,例如:你在OnDraw中画了两个矩形,在一回重绘中即便多少个矩形的绘图函数都有进行,可是很有可能只有一个显得了,这是因为MFC本身为了加强重绘的功能设置了裁剪区。裁剪区的功用就是:只有在这一个区内的绘图过程才会真正实用,在区外的是没用的,就算在区外执行了绘图函数也是不会来得的。因为大部分意况下窗口重绘的爆发大多是因为窗口部分被挡住或者窗口有滚动暴发,改变的区域并不是所有图形而唯有一小部分,这一局部需要转移的就是pDC中的裁剪区了。因为呈现(往内存依旧显存都叫呈现)比绘图过程的测算要劳碌得多,有了裁剪区后出示的就只是应该呈现的部分,大大提升了展现效能。不过这多少个裁剪区是MFC设置的,它早已为我们提升了显示功用,在进行复杂图形的绘图时怎么着进一步提高效用呢?这就唯有去掉在裁剪区外的绘图过程了。可以先用pDC->GetClipBox()得到裁剪区,然后在绘图时判断你的图片是否在这么些区内,倘若在就画,不在就不画。
借使你的绘图过程不复杂,这样做可能对您的绘图效用不会有提高。