首页 > 范文大全 > 正文

VC++基于MFC类库的高效曲线显示原理和实现

开篇:润墨网以专业的文秘视角,为您筛选了一篇VC++基于MFC类库的高效曲线显示原理和实现范文,如需获取更多写作素材,在线客服老师一对一协助。欢迎您的阅读与分享!

[摘 要] 曲线显示在很多类型的软件中都多有使用,基于mfc类库的曲线显示原理和实现是本文探讨的主要内容。大量的数据如何以曲线的形式显示出来,对显示算法效率有一定的要求,特别对要求刷新速度高的数据显示尤其重要,本文探讨的绘图方式采用GDI绘图,探讨了曲线绘图中需要解决的问题和解决方案,主要涉及到高精度多媒体定时器和GDI双缓冲绘图技术的原理和实现。

[关键词] MFC vc++ 曲线 多媒体定时器 双缓冲绘图

曲线显示在统计类、监控类等很多类型的软件中都有广泛的应用,最简单的例子,Windows系统任务管理器中的CPU负载曲线图示。各种监测数值的实时曲线显示,非常有利于对数据的直观表现。笔者完成过两个和曲线显示相关的项目,一个是数据实时监测软件,其中实时监测数据需要曲线显示,另一个是和地震相关的数据处理软件,也需要一个辅助的曲线显示窗口。所以曲线显示是有相当应用价值的。

本文使用的开发环境是微软的VC++6.0,Microsoft Visual C++是Microsoft公司推出的开发Win32环境程序,面向对象的可视化集成编程系统。VC++自带了MFC类库,微软基础类(Microsoft Foundation Classes),同VCL类似,是一种应用程序框架,它封装了Windows API,提供了相对比较成熟的应用程序框架,采用MFC开发程序可以软件开发者所需要编写的代码大为减少,提高开发效率,有力地保证了程序良好的稳定性和可调试性。

一、曲线显示中的两个技术问题

曲线显示有两个问题需要解决,一个是高速刷新情况下,如何保证精确的图像刷新速度。由此带来的另一个问题是如何在高速刷新的情况下防止闪烁,提高绘图效率,降低系统资源占用率。在多个曲线同时显示情况下,良好的算法可以保证曲线显示的流畅。下面先探讨第一个问题。

如何保持一定时间精度的刷新问题,以10ms的数据刷新率为例,要求曲线实时显示,处理这个问题有两个思路,一个是考虑到人类眼睛的特点,一般来说每秒24帧的速度,就足以让眼睛感觉到连续,所以数据刷新和图像刷新可以不同步,数据以10ms间隔刷新,而图像以25ms间隔(每秒40帧)刷新,也就是说数据和图像异步刷新。思路二,数据和图像的同步刷新,数据刷新的同时图像也同步刷新,均为10ms间隔,帧速100。

在程序显示中,考虑到更精确的曲线数据显示,在显示算法足够效率的基础上数据和显示同步刷新效果为最佳。如何精确的控制曲线图像的刷新速率,这牵扯到另一个问题,就是Windows系统中如何精确定时。一般来说,最常用简单的定时方式就是响应WM_TIMER消息,但是该定时方式存在定时精度低的缺点,一般来说WM_TIMER定时精度在Windows95系统中最高为55ms,在Windows2000和XP中能达到10ms,这看起来似乎不错,但是由于定时器消息WM_TIMER在多任务操作系统中优先级较低,这会导致WM_TIMER消息在系统资源紧张或者应用程序消息队列繁忙时不能得到及时响应,导致10ms根本无法精确保证。除此之外,定时方式还有很多,综合考虑优缺点以后,以多媒体定时器最合适此类曲线显示应用,使用相对简单,定时控制、定时精度等均相当理想。

微软提供了多媒体定时器,采用回调函数方式来完成高精度定时,多媒体定时器与普通定时器机理是不同的,多媒体定时器最高定时精度能达到1ms。完全满足曲线绘图中的使用要求。为了便于更好的使用和控制多媒体定时器,笔者封装了一个用于控制多媒体定时器的C++类,具体实现细节稍后呈现。

第二个问题是绘图效率问题,如何高效的绘图,以10ms的数据刷新率和同步图像刷新速度,这不仅仅要求绘图算法高效简洁,还需要从绘图方法上有根本的转变。高速刷新的情况下,还要保证绘图的平滑无闪烁,同时兼顾显示效果和绘图效率,双缓冲绘图是个非常不错的方案。

一般的Virtual C++视类程序的绘图是无需考虑闪烁的,在绘图不够复杂,计算量不是很大的情况下,无闪烁绘图是不太有必要的,但是在曲线绘制中,采用无闪烁绘图是非常有必要的,可以提高绘图的质量和程序的绘图效率,从而提高整个程序绘图模块的效率和显示效果。

绘图为什么会闪烁,不明白原因就无法解决这个问题。首先考虑下Windows绘图机制,当我们需要在客户区显示曲线或者图形时,调用绘图函数绘制我们需要显示的图形,绘制完的图形不会立即显示出来,还需要程序去刷新客户区才能显示,程序主动刷新客户区会导致Windows发送一条WM_PAINT消息,在文档视图结构的程序中,CView视图类的OnDraw函数会被调用来处理这个消息,而OnDraw函数一般的处理方法就是简单将所有需要绘制的图形重新绘制一遍。这样一个完整的绘图显示过程就完成了。而之所以绘图会闪烁,根本原因就是在WM_PAINT发出时,响应函数会调用BeginPaint(hWnd,&ps);而BeginPaint会产生WM_ERASEBKGND消息,而响应WM_ERASEBKGND消息的处理函数会根据默认的画刷绘制图形背景底色,之后再绘制客户区的图形,产生闪烁原因的正是背景底色重绘导致的反差。

下面谈谈重绘闪烁的解决方法,当曲线更新数据显示的时候,首先要把WM_ERASEBKGND的响应函数返回值设为TRUE,表示不再绘制背景。避免重绘反差导致闪烁。然后再采用双缓冲绘图来解决大量数据刷新时稳定高效的绘制方式。

首先创建一个与原设备环境句柄pDC相兼容的内存设备环境,也就是内存中的DC,之后在内存DC中进行曲线重绘,重绘完毕以后调用BitBlt函数把内存DC拷贝当前显示的pDC上,由于Bitblt函数效率非常高,所以基本不浪费计算时间。简单说就是一个用来显示的dc,一个在内存中创建与原dc兼容的dc用来在后台绘图,绘图完毕以后,拷贝并显示,这样数据显示就会非常平稳和高效,不会再有闪烁。双缓冲绘图是一个解决大量数据重绘时屏幕闪烁的有效方法。

笔者根据实际的需要,封装了一个CMemDC类,用来实现双缓冲绘图。

二、具体实现

先列出解决高精度定时的代码,主要是一个封装以后的多媒体定时器控制类。限于篇幅,只列出类声明部分主要接口函数和部分实现代码。

代码如下:

类: 其次是双缓冲绘图的一个封装类和在工程中部分显示核心代码。

类:CMemView

CDC *CreateMemDC(CDC *pDC);

CDC *GetMemDC();

void BitBltMemDC(CDC *pDC);

曲线绘制显示代码:

类CCurveView主显示函数

最后在工程中的效果,图片如下:

三、本文中的一些不足

笔者因为一直在使用VC,到目前为止最新的Visual studio 2010已经和本文使用的VC6.0有很大变化了,MFC的版本也已经更新了。众所周知,VC开发程序效率是比较低的,本文所采用GDI方式来开发曲线绘图显示从开发角度来说效率是比较低的,GDI+已经很长时间了,如果采用GDI+开发速度会更快,复杂度也会降低不少。另外曲线绘制整体设计还有待进步一完善,一些显示细节,比如曲线x、y方向坐标刻度显示不够完善,图像颜色显示单一,显示代码效率还有进一步优化的空间。整体代码封装,接口设计也需要进一步完善。

参考文献:

[1] [美]CharlesPetzold. Windows 程序设计:第5版 北京大学出版社.