关于VC画图闪屏的问题 - VC/MFC / 基础类

显示图形如何避免闪烁,如何提高显示效率是问得比较多的问题。

而且多数人认为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

这样背景没有了,结果图形显示的确不闪了,但是显示也象前面所说的一样,

变得一团乱。怎么办?这就要用到双缓存的方法了。双缓冲就是除了在屏幕上有

图形进行显示以外,在内存中也有图形在绘制。我们可以把要显示的图形先在内存中

绘制好,然后再一次性的将内存中的图形按照一个点一个点地覆盖到屏幕上去(这个

过程非常快,因为是非常规整的内存拷贝)。这样在内存中绘图时,随便用什么反差

大的背景色进行清除都不会闪,因为看不见。当贴到屏幕上时,因为内存中最终的图形

与屏幕显示图形差别很小(如果没有运动,当然就没有差别),这样看起来就不会闪。

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()得到裁剪区,然后在绘图时判断你的图形是否在这个区内,如果在就画,不在就不画。

如果你的绘图过程不复杂,这样做可能对你的绘图效率不会有提高。

关于VC画图闪屏的问题 - VC/MFC / 基础类,布布扣,bubuko.com

时间: 2024-08-25 13:55:56

关于VC画图闪屏的问题 - VC/MFC / 基础类的相关文章

VC++ 轻松实现“闪屏” SplashWnd

我们平时使用的好多软件在运行启动时都会有一个"闪屏"画面显示,一般用于标识软件的一些信息,如软件版本名称.公司等,通过查找资料发现,其实实现起来很简单,一个类就能搞定! SplashWnd.h C++ Code 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647   #if !defined(AFX_SPLASHWND_H__18C1CB0F_1CFF_483B_87

VC调试闪退解决办法

在VC2010调试或执行EXE文件时,程序运行结束后自动退出了,想看到打印 可以采用几种方法: 1.按ctrl+F5只执行不调试 2.在cmd中手动调用 而不是直接点 3.加入getchar  #include <iostream> using namespace std; int main(void) { cout<<"welcome!"; getchar(); return 0; } 这样输入任意值可以退出 4.调用系统函数 #include<stdi

win32 窗口缩放时出现闪屏

今天无意发现之前写的一个小工具在缩放窗口的时候,出现闪屏,主要有两个位置: 工具栏出一闪屏 右侧的控制面板出现闪屏 (这个控制面板与多层元件组合而成) 之前真没注意到这个问题,平时都是最大化/恢复窗口,没缩放窗口,所以没发现这样的问题. 网上搜索了一下,找到一些解决方案: [百度文库] VC窗口闪烁问题的解决 - http://wenku.baidu.com/view/3c7e747931b765ce0508146a.html 我遇到的问题属于第2种情况: 原因二:  复杂的界面有多层窗口组成,

vue cavnas绘制矩形,并解决由clearRec带来的闪屏问题

起因:在cavnas绘制矩形时 鼠标移动一直在监测中,所以鼠标移动的轨迹会留下一个个的矩形框, 要想清除矩形框官方给出了ctx.clearRect() 但是这样是把整个画布给清空了,因此需要不断 向画布展示新的图片,这样就出现了不断闪屏的问题. 那么怎么解决呢? microsoft提供了双缓冲图形技术,可以点击看看这边文章. 具体就是画图的时候做两个 cavnas层,一个临时层 一个显示层,鼠标的监听事件放在显示层处理, 每次清空的时候只清空临时层,这样就可以解决闪屏问题了. 部分代码如下: <

WinForm Flicker闪屏解决方案

开发WinForm 程序时经常会遇到闪屏的问题,这会给用户造成很差的使用体验,所以必须妥善解决好这个问题. 首先,我们先要找出闪屏的原因,就我目前遇到的问题而言,其原因真是五花八门. 主要的原因有:使用了很多的组件导致加载缓慢,使用了性能差的组件(PictureBox.Button等). 所以,不论开发者的水平如何,微软给我们也挖了坑的. 对于控件太多造成的闪屏,其原因有两个: 1. 绘制控件时,Windows 会给控件发送两个消息.第一个是WM_ERASEBKGND消息,它会触发OnPaint

【apicloud问题解决记录】键盘弹出监听处理以及头部底部的黑色闪屏现象

http://blog.csdn.net/kongjiea/article/details/46545351 移动端解决fixed和input获取焦点软键盘弹出影响定位的问题 使用apicloud开发中并不存在这个问题,input进行焦点获取,页面会自动压缩 apicloud,使用api.openWin()打开win框架后,如果bounces:true会出现向下拉和向上拉黑屏和闪屏现象. 打开openWin({bounces:false}),再在win里面打开frame框架 以下面新浪新闻页为例

直播疑难杂症排查(7)— 黑屏、花屏、闪屏问题

本文是 <直播疑难杂症排查>系列的第七篇文章,我们来重点看看直播中常见的各种黑屏.花屏.闪屏问题. 首先我们要明白,黑屏.花屏.闪屏等问题,可能是推流端的问题,也可能是播放器的问题,遇到这些现象,我们要第一时间用别的播放器(如 VLC,ffplay)试试,如果都出现同样的问题,那么多半是流本身的问题了,反之,则很可能是播放器的问题. 1.  播放黑屏 现象:画面是黑的,没有图像,但是有声音. 1.1 主播端摄像头权限问题 无论 Android 还是 iOS,App 使用摄像头都是需要申请授权的

另类解决Win10游戏会闪屏的方法

在Win10系统中遇到游戏时闪屏另很多朋友很苦恼,可是又找不到解决方法,下面小编分享一个另类的解决方法,或许可以帮助你解决Win10下游戏时闪屏的问题,. 解决步骤: 1.打开游戏后先将游戏界面调整成"窗口化",或者"无边窗口化(全屏无边框)"; 2.任意打开一个另外的程序窗口,按组合键Win+Tab(不是Alt+Tab)切换,然后点击+添加桌面,添加一个"桌面2"; 3.接着将游戏窗口拖入"桌面2"里去; 4.然后点击&qu

关于android应用闪屏的几种情况

1.主菜单进入某应用闪屏: 常见是一个空的activity作为launcher属性,实际上它什么事业没干,真正干事情的是从它通过intent启动的activity. 例子: public class BootActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); /* if (SDCardUtils.