MFC中绘制动态曲线

2023-05-16

在工控监测领域,经常需要动态绘制曲线,观察曲线的变化趋势,绘制波形图,绘制频谱等。在前面4讲中介绍了MFC经常用的 TeeChart 控件和 Hight-Speed Chart  Ctrl,这两个都是MFC绘图控件的经典(另外,在Qt中还有 QwtPlot QCustomPlot 两大神器)。许多人问如何绘制动态变化的曲线,为此专门写下这篇文章。


C++ GUI 绘图控件目录

MFC(VC)

  • VS2010 使用TeeChart绘图控件 - 之一 - 控件和类的导入
  • VS2010 使用TeeChart绘图控件 - 之二 - 绘制图形(折线图,柱状图)
  • TeeChart绘图控件 - 之三 - 提高绘图的效率
  • MFC下好用的高速绘图控件-(Hight-Speed Charting)
  • 绘制动态曲线

Qt

  • qt超强精美绘图控件 - QCustomPlot一览
  • qt超强绘图控件qwt - 安装及配置


















对于任何绘图控件,都可以实现动态绘图,其原则是:控件只负责绘图,若想曲线动,就让数据动,就像看电影一样,电影是由一帧一帧的静态图片组合起来的,在一定速度上刷新,静态图片就能动起来;和电影的原理一样,绘图控件能显示静态的曲线,想要它动起来,就让它频在一定时间刷新就可以了

这就是动态绘图的实现原理。

实现动态曲线需要以下两个准备:

  1. 计时器Timer
  2. 数组左移

基于Timer的绘图

任何界面库都会有Timer这个实现,在MFC中时OnTimer消息,在Qt中是QTimer类,那种原理基本都一样,下面将以MFC(VC)为例进行说明。

Timer是消息级别最低的消息,它会保证其它级别高的消息优先执行,因此,就算数据大量刷新,也不会影响主线程的其它消息。

MFC生成OnTimer消息,消息响应函数如下:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void CTeeChartDlg::OnTimer(UINT_PTR nIDEvent)  
  2. {  
  3.     // TODO: 在此添加消息处理程序代码或调用默认值  
  4.     CDialogEx::OnTimer(nIDEvent);  
  5. }  

绘图的实现就在这个消息响应函数里

如果让定时器设定为1秒触发,每一秒把旧数据去除,绘制新数据,就能看到不停变换的波形;对于趋势图,假如每秒有一个新数据,那么就在定长数组中,把数组所有数据整体左移,同时数组末端加入新数据。代码如下:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. ///   
  2. /// \brief 左移数组  
  3. /// \param ptr 数组指针  
  4. /// \param data 新数值  
  5. ///  
  6. void LeftMoveArray(double* ptr,size_t length,double data)  
  7. {  
  8.     for (size_t i=1;i<length;++i)  
  9.     {  
  10.         ptr[i-1] = ptr[i];  
  11.     }  
  12.     ptr[length-1] = data;  
  13. }  
此函数把整个数组左移,然后新数据放置在数组最末端(右端)。

这样,数组就实现“向左运动”,把左移后的数组绘制,就能在绘图控件上发现其变化。

下面开始实现动态绘图(这里演示TeeChart的方法,附件里有HightSpeed-Chart CChartCtrl的方法):

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void CTeeChartDlg::OnBnClickedButtonRuning()  
  2. {  
  3.     KillTimer(0);  
  4.     ZeroMemory(&m_TeeChartArray,sizeof(double)*m_c_arrayLength);  
  5.     for (size_t i=0;i<m_c_arrayLength;++i)  
  6.     {  
  7.         m_X[i] = i;  
  8.     }  
  9.     m_count = m_c_arrayLength;  
  10.     CSeries chart_T = (CSeries)m_Chart.Series(0);  
  11.     chart_T.Clear();  
  12.     m_pLineSerie->ClearSerie();  
  13.     SetTimer(0,1000,NULL);    
  14. }  
函数中几个成员变量的定义是:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. double m_TeeChartArray[2096];  
  2. double m_X[2096];  
  3. unsigned int m_count;  
  4. const size_t m_c_arrayLength = 2096;  

m_TeeChartArray是需要绘制的数组的Y值,m_X是对应的x值,m_count是计数器,每绘制一次,个数加1,主要用于x轴

在timer中的实现如下:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void CTeeChartDlg::OnTimer(UINT_PTR nIDEvent)  
  2. {  
  3.     // TODO: 在此添加消息处理程序代码和/或调用默认值  
  4.     if(0 == nIDEvent)  
  5.     {  
  6.         ++m_count;  
  7.         drawMoving();  
  8.     }  
  9.     CDialogEx::OnTimer(nIDEvent);  
  10. }  

drawMoving函数用于绘图,timer设定为1秒触发一次,这时就能看到每秒的变化,如果数据是以1秒为刷新周期,每一秒有个新数据,只需要把旧的数据向左移,新数据放到数组最右端,再在绘图控件上把此图形画出来即可看的像动一样。

drawMoving函数的实现如下:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void CTeeChartDlg::drawMoving()  
  2. {  
  3.     CSeries chart_T = (CSeries)m_Chart.Series(0);  
  4.     chart_T.Clear();  
  5.     m_pLineSerie->ClearSerie();  
  6.     LeftMoveArray(m_TeeChartArray,m_c_arrayLength,randf(0,10));  
  7.     LeftMoveArray(m_X,m_c_arrayLength,m_count);  
  8.     DrawLine_TeeChart(m_X,m_TeeChartArray,m_c_arrayLength);  
  9. }  

前面说过timer是优先级最低的消息,如果想曲线动的流畅,可以把时钟设置为0ms,如

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. SetTimer(0,0,NULL);   
这时会在保证界面流畅的前提下,以最高频率刷新。这样看到的图形会非常流畅。

上面介绍的就是动态绘制曲线的思路和方法,附件中有用TeeChart实现和HightSpeedChart实现的例子,考虑到可能有些人没有安装TeeChart,专门把TeeChart分离出来了一个源码,只有HightSpeedChart,不需要安装任何控件。


demo1:

MFC下TeeChart和HightSpeedChart动态绘制曲线图-VS2010

demo2(不用安装任何控件):

MFC动态绘制曲线图-HightSpeedChart实现

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

MFC中绘制动态曲线 的相关文章

  • 支持 IAccesible 接口以在文本编辑器中移动插入符号的正确解决方案是什么?

    我想从头开始实现一个支持 IAccessible 接口的文本编辑器 我正在使用 MFC 和 Win32 API 当记事本等标准文本编辑器中的插入符号位置发生变化时 讲述人 JAWS 等客户端工具将发音与插入符号移动相对应的字母 单词或行 我
  • CCcomboBoxEx 图像和文本之间的间距

    有没有什么方法 一些系统指标值或其他任何东西可以给出 CComboBoxEx 控件上图标和图像之间的边距有多少像素 下图中红色标记表示的空间 None
  • 安装VS2008后,在winnt.h中出现编译错误

    我正在尝试将我们的项目从 VS2005 转移到 VS2008 并且在 MFC 项目上遇到此构建错误 C Program Files Microsoft SDKs Windows v6 0A include winnt h 236 error
  • 在 Visual Studio 2013 中显示带有偏移量的控件

    最近 我将源代码从 Visual Studio 2010 迁移到 Visual Studio 2013 在 Visual Studio 2013 中构建后 控件将显示有偏移 单击下面的链接查看图像 链接到图像 https i stack i
  • Mfc CComboBoxEx - 如何更改背景颜色

    我有一个派生自 CComboBoxEx 的类 我正在尝试更改背景颜色 我认为它会像 ComboBox 一样工作 使用 SetBkColor 函数 但它不会改变背景颜色 这是我尝试过的 BEGIN MESSAGE MAP CMyComboBo
  • 如果我没有为其相应的命令声明消息映射条目,如何阻止 MFC 禁用我的控件?

    我有以下问题 如果我没有相应消息的消息映射条目 假设 ID MYBUTTON1 MFC 将禁用我的工具栏 CToolbar 控件 有没有解决的办法 我对菜单也有同样的问题 但我发现您可以通过将 CFrameWnd m bAutoMenuEn
  • 有效的 MFC ID 范围

    这让我很困惑 我正在读这个技术说明 https learn microsoft com en gb cpp mfc tn020 id naming and numbering conventions它指出 Prefix Resource t
  • 菜单被裁剪

    我有一个MFC项目 它支持 40 多种语言 我的电脑上有两个显示器 它们都是不同尺寸的显示器和不同的分辨率 如果我将应用程序移至较小的显示器上 则不会显示完整的语言菜单 我知道它会显示滚动条 为什么不是呢 我的菜单是标准菜单 没有什么花哨
  • 在MFC项目中使用多个资源文件

    我在 VS2015 中使用 MFC C 11 并且有一组独立的 GUI 我想在多个项目中使用它们 我知道这可以通过创建一个 rc 文件来实现 该文件可以包含在每个项目的主 rc 文件中 使用多个资源文件 https msdn microso
  • 如何将 unicode 字符变成小写字母

    我在 VC MFC 中将 unicode 字符转换为小写字母时遇到问题 我在 CString 变量中有 unicode 字符 所以 使用英语 MakeLower 工作正常 我得到小写字母 但它无法将 unicode 字符转换为小写 我确实尝
  • MFC:如何减少OnInitialUpdate()滚动的时间成本?

    我需要打印多行数据 每行都可以进行文本换行 因此高度会有所不同 要进行滚动 我需要导出总高度 由于每条线可能有不同的高度 我只能遍历每条线来累加高度 如下所示 void CMyScrollView OnInitialUpdate for a
  • 使用 CSplitterWnd 在 CChildFrame 中创建多个视图

    我正在使用 MFC MDI 我需要创建如下视图 我的 ChildWnd 分为两部分 它们是LeftView CView 和RightView CScrollView LeftView 分为两部分 TreeView 和 FormView 我怎
  • 如何在 MFC 中创建 GUI

    我需要能够即时创建指南 MFC中有没有办法做到这一点 我了解了如何在 net 中做到这一点 但我们还没有做到这一点 如果没有 您是否有一些我可以使用的代码的指针 don t forget to add Rpcrt4 lib to your
  • 默认情况下启用或禁用菜单项。为什么?

    我有一些遗留代码 由于某种原因 菜单项在启动时被启用或禁用 我的问题是 如何 有没有办法在不调用 EnableMenuItem 函数的情况下执行此操作 MFC 有没有办法做与资源设置所说相反的事情 我也不明白为什么当最后一个子窗口关闭时 当
  • 与 UltraHD 兼容的 CHtmlView

    CHtmlView与 UltraHD 分辨率不兼容 实现 UltraHD 感知并不仅仅在于使用正确的 HTML CSS 打印预览机制失败并裁剪页面 许多个月前 微软承认这是一个问题 但没有解决它 我的应用程序大量使用CHtmlView用于显
  • 编辑默认工具栏时 Microsoft Visual Studio“未知位图格式”

    我已使用项目创建向导使用 Microsoft 基础类库 MFC 创建了一个应用程序 我创建了一个多文档界面 MDI 应用程序 该向导创建您可以使用的虚拟工具栏和菜单 我扩展了默认工具栏 没有任何问题 但是现在当我尝试通过资源视图编辑它时 我
  • 在Linux上运行MFC程序

    我有一个相当大的基于 MFC 的程序 我的任务是让它在 Linux 上运行 我已经解释过 这需要将程序重新编写为带有 STL 的直接 C 更多工作 或者重新编写为 Qt C 更少工作 现在我被告知 我需要编写包装器以使每个 MFC 类在 L
  • MFC CMenu 工具提示未显示

    我尝试使用类似的东西来设置 CMenu 项的工具提示 如所述here https stackoverflow com questions 2400180 mfc how to add tooltip in cmenu items 但它只是显
  • 如何使用 MFC 禁用顶级菜单项并使其变灰

    我有一个对话框应用程序 我希望在对话框顶部有可单击的菜单项 这些项目不显示下拉菜单 但实际上运行关联的命令 我通过在对话框属性中设置 Popup False 并分配消息 ID 来做到这一点 但我的问题是 当项目可点击没有意义时 无法正确禁用
  • 屏幕截图忽略了一些窗口

    我正在 MFC 中工作 我正在尝试捕获桌面的 bmp 我正在使用 GetDC NULL 来执行此操作 但它似乎忽略了特殊的皮肤窗口 它似乎忽略了用 UpdateLayeredWindow 绘制的窗口 此行为似乎仅发生在 Vista x64

随机推荐

  • C++回调机制的几种实现方式

    xfeff xfeff Callback Callback的本质是设置一个函数指针进去 xff0c 然后在需要触发某个事件时调用该方法 比如Windows的窗口消息处理函数就是这种类型 比如下面的示例代码 xff0c 我们在Download
  • C/C++函数调用的几种方式总结

    xfeff xfeff 本篇文章主要是对C C 43 43 函数调用的几种方式进行了详细的总结介绍 xff0c 需要的朋友可以过来参考下 xff0c 希望对大家有所帮助 调用函数时 xff0c 计算机常用栈来存储传递给函数的参数 栈是一种先
  • Aspose.Cells.dll操作exel

    xfeff xfeff 1 创建execl xff08 不需要服务器或者客户端安装office xff09 public void DCExexl DataTable dt Workbook wb 61 new Workbook Works
  • 使用Aspose.Cells组件生成Excel文件实例

    xfeff xfeff 这篇文章主要介绍了使用Aspose Cells组件生成Excel文件的方法 xff0c 大家参考使用吧 生成带表头的Excel文件 xff0c 格式如下显示 当然更复杂的一些也可以通过 合并单元格的方法 public
  • VS2010中添加lib库引用

    xfeff xfeff 一 VS2010中添加lib库引用 1 菜单 项目 gt 属性 gt 配置属性 gt 链接器 gt 输入 附加依赖项 加入库名 如 my API lib 或是在cpp源文件中用代码 pragma comment li
  • C++静态库与动态库

    xfeff xfeff 这次分享的 宗旨 是 让大家学会创建与使用静态库 动态库 xff0c 知道静态库与动态库的区别 xff0c 知道使用的时候如何选择 这里不深入介绍静态库 动态库的底层格式 xff0c 内存布局等 xff0c 有兴趣的
  • 在mysql设置root用户密码的方法

    在mysql设置root用户密码的方法
  • C++中的“error:LNK2005 已经在*.obj中定义”异常

    xfeff xfeff C 43 43 中的 error LNK2005 已经在 obj中定义 异常问题 异常现象如下 xff1a C 43 43 中的 error LNK2005 已经在 obj中定义 异常问题 图1 error LNK2
  • 指令和数据都用二进制代码存放在内存中,从时空观角度回答CPU如何区分读出的代码是指令还是数据

    xfeff xfeff 指令用来确定 做什么 和 怎样做 xff0c 数据是 做 的时候需要原始数 计算机可以从时间和空间两方面来区分指令和数据 xff0c 在时间上 xff0c 取指周期从内存中取出的是指令 xff0c 而执行周期从内存取
  • C++类的内存地址存放问题

    了解C 43 43 类地址的存放和分配等问题 xff0c 能帮助我们更深入 更清晰了解类的组成及其使用 自己目前不是很清楚 xff0c 先收集一些网上资料 xff0c 而后再慢慢补充增加的了解 网络收集之 关于结构体和C 43 43 类的内
  • 介绍了如何取成员函数的地址以及调用该地址

    xfeff xfeff 摘要 xff1a 介绍了如何取成员函数的地址以及调用该地址 关键字 xff1a C 43 43 成员函数 this指针 调用约定 一 成员函数指针的用法 在C 43 43 中 xff0c 成员函数的指针是个比较特殊的
  • 类中内容在内存中到底是如何分配的呢?

    xfeff xfeff 分类 xff1a 一个类 xff0c 有成员变量 xff1a 静态与非静态之分 xff1b 而成员函数有三种 xff1a 静态的 非静态的 虚的 那么这些个东西在内存中到底是如何分配的呢 xff1f 以一个例子来说明
  • 什么变量在堆内存里存放,什么变量在栈内存里存放

    堆和栈的区别 stack and heap 一般认为在c中分为这几个存储区 1栈 有编译器自动分配释放 2堆 一般由程序员分配释放 xff0c 若程序员不释放 xff0c 程序结束时可能由OS回收 3全局区 xff08 静态区 xff09
  • C# 泛型(Generic)

    xfeff xfeff 泛型 xff08 Generic xff09 允许您延迟编写类或方法中的编程元素的数据类型的规范 xff0c 直到实际在程序中使用它的时候 换句话说 xff0c 泛型允许您编写一个可以与任何数据类型一起工作的类或方法
  • 基础拾遗------泛型详解

    xfeff xfeff 基础拾遗 xff1a 前言 xff1a 1 泛型的约束2 泛型继承3 关键字default4 泛型方法5 泛型接口6 泛型数组7 泛型委托 基础拾遗 xff1a 基础拾遗 特性详解 基础拾遗 webservice详解
  • ORA-31600: invalid input value INDEX PARTITION for parameter

    运行备份数据库对象的存储过程报如下错误 SQL gt exec proc auto backup begin proc auto backup end ORA 31600 invalid input value INDEX PARTITIO
  • Windows静态库和动态库的调用方法汇总

    静态库的调用方法 第一种 xff1a 项目设置中引用 xff0c 在项目的属性中设置 第二种 xff1a 在代码中使用 pragma comment lib 34 lib文件名 34 第一种方法 步骤一 xff1a 右键单击项目 gt 属性
  • 包含目录、库目录、附加包含目录、附加库目录、附加依赖项之详解

    VS项目中的包含目录 库目录 附加包含目录 附加库目录 附加依赖项均在 34 项目 gt 属性 gt 配置属性 34 下进行配置 xff0c 具体说明如下 xff1a VC 43 43 目录 xff1a 包含目录 xff1a 寻找 incl
  • c++用WinForm做界面的实现

    以前是做C 的 xff0c 对Winform情有独钟 xff0c 最近想转C 43 43 想把以前的一些Delphi转成c 43 43 xff0c MFC我不熟而且用起来相当烦效果又丑 xff0c GTK图形库用起来太麻烦 xff0c 琢磨
  • MFC中绘制动态曲线

    在工控监测领域 xff0c 经常需要动态绘制曲线 xff0c 观察曲线的变化趋势 xff0c 绘制波形图 xff0c 绘制频谱等 在前面4讲中介绍了MFC经常用的 TeeChart 控件和 Hight Speed Chart Ctrl xf