我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Qt中怎么使用PaintEvent绘制实时波形图

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Qt中怎么使用PaintEvent绘制实时波形图

本文小编为大家详细介绍“Qt中怎么使用PaintEvent绘制实时波形图”,内容详细,步骤清晰,细节处理妥当,希望这篇“Qt中怎么使用PaintEvent绘制实时波形图”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。

数据来源依旧是硬件传入的实时数据,如下:

[0, 3, 5, 8, 10, 13, 15, 18, 20, 23, 25, 28, 26, 23, 20, 16, 13, 11, 9, 6, 4, 3, 0]

其实有些人看到这里会说,数据都有了直接画出来不就可以了吗?

在我们实际应用过程中,这些硬件上传的数据不是一次性传出的,而是取决于你操作硬件的频率以及事件决定的。所以说,想要一次性拿出一整条数据来绘制,这个时机已经晚了。

绘制思路

1:接收硬件传入的数据

这里使用了SetRealTimeDepthData(stDepthData stData);意思是:设置实时深度数据值。

参数穿入的是一个结构体,在使用这个函数之前我已经将数据做了简单的处理,包括了深度方向设置。

比如:当深度逐渐变大时,深度方向div是正数,当深度逐渐减小时,深度方向div是负数。

下面,我展示下我实际处理后的数据值

Qt中怎么使用PaintEvent绘制实时波形图

对于这些真实数据我设定了一个结构体,用于存储数据时间、深度方向以及具体深度值

struct DrawingEffectivePress{    int nDiv; //深度方向    int nDepth; //深度值    DWORD dwTime; //记录当前真实数据的时间    DrawingEffectivePress():nDiv(0),nDepth(0),dwTime(0){}}

SetRealTimeDepthData具体实现,如下:

void QDrawingWaveform::SetRealTimeDepthData(stDepthData stData){    std::lock_guard<std::mutex> lck(m_dataMutex); //加锁进行数据操作    DrawingEffectivePress stDepth;    stDepth.nDiv = stData.nDiv>=0?1:-1;    stDepth.nDepth = stData.nDepth;    stDepth.dwTime = GetTickCont();    m_vetDepth.push_back(stDepth);}

代码讲解:

有上述图片的真实数据来看,深度的方位是逐渐递增的,那么在程序中我们采用了1和-1的方式表示,正方向时都是用1来表示,负方向时都是用-1来表示。

每有一条真实数据时,都需要记录当前真实数据的具体时间,用于绘制实时的动态走向。

2:定时器动态刷新页面

设定定时器每40毫秒刷新一次页面:

#define TimeInterval 40 //定时器时间间隔

定时器启动 m_nTimerId = startTimer(TimeInterval);

3:真实数据处理

这是我们绘制的一个重点,也是比较麻烦的一部分了。

与硬件打过交道的友友们都知道,硬件数据的不稳定性,有些时候看着数据的走向是朝下的,因为手动操作缘故,偶尔会有一些浮动的数据,这些数据需要筛除,在传入数据之前我已经做了处理,这个问题在这篇文章中是不存在的。

使用m_vetDepth存储了实际的深度数据值。

std::vector<DrawingEffectivePress> m_vetDepth;
第一步:每进行一次数据更新,都需要剔除超时显示数据。

什么叫做超时显示数据?

根据文章一开篇的动画可以看出,波形图一边进行绘制操作,一边向左移动。

在移动过程中,肯定会移出左边界,那么也就代表了当前的图形不需要展示。对此,我们就需要在每次更新数据时,判断有哪些数据是已经超过显示范围的,需要进行剔除了。

那么,到这里也就遇到了另外一个问题,我们剔除的数据是在m_vetDepth中存储的数据吗?

答案是的,但是为了逻辑简单操作,我们需要重新定义一个结构体,当前结构体主要用来做已经绘制成图形的点的记录。

std::vector<DrawingEffectivePress> m_vetEffectiveDepth;

在当前容器中存储的数据一定是具体特定标识的,也就是波形图的拐点数据,一个完整波形的最低点以及最高点。

当我们进行实际绘图时,也是取m_vetEffectiveDepth中的数据,保证了数据逻辑简单性。

现在,我们先来看一看剔除超时数据的实际代码,如下:

void QDrawingWaveform::DeletingTimeoutData(){    DWORD dwCurrentTime = GetTickCount(); //当前时间    std::vector<DrawingEffectivePress>::iterator itvet = m_vetEffectivePress.begin();    for (itvet; itvet != m_vetEffectivePress.end();)    {DrawingEffectivePress stPoint = *itvet;if ((dwCurrentTime - stPoint.dwPressTime) > m_nSingShowTime){            //超过界面展示范围,剔除数据            itvet = m_vetEffectivePress.erase(itvet++);}else            itvet++;    }}

代码解析:实时获取最新时间,每次都判断存储的硬件操作时间与设定的最大值(m_nSingShowTime)进行比较。

当超过设定的时间时,说明图形已经消失在界面上了,就需要剔除数据。

第二步:筛查有效数据,并记录

上一步骤是剔除超时数据,那么我们该如何存储这些有效数据到m_vetEffectivePress容器中呢?

思路:

默认容器中存储前两条数据。

当后续数据来时,需要与上一条数据进行判别。

如果方向一致,说明深度一直在递增或者是递减,直接替换最后一会有效数据的值即可。

如果方向不一致,说明深度值发生了变换,可能由向下变成了向上;也可能由向上变成了向下。不再做数据替换操作,而是插入一条新数据。

操作一条数据后,进行数据删除。

将上述思路转变成代码,如下:

std::vector<DrawingEffectivePress>::iterator itvet = m_vetPress.begin()for (itvet; itvet != m_vetPress.end(); ){DrawingEffectivePress stPoint = *itvet;DrawingEffectivePress stPress;stPress.dwTime = stPoint.dwTime;stPress.nDiv = stPoint.nDiv;stPress.nDepth = stPoint.nDepth;int nsize = m_vetEffectivePress.size();if (nsize < 2){m_vetEffectivePress.push_back(stPress);}else {            //如果当前数据stPoint与m_vetEffectivePress的最后一位的拐点一致,            //剔除掉m_vetEffectivePress的最后一位,存储成最新数据            if (m_vetEffectivePress[nsize - 1].nDiv == stPoint.nDiv)            {                    //更新m_vetEffectivePress的最后一位                    m_vetEffectivePress[nsize - 1] = stPress;            }            else            {                    //存储的最后一位的拐点与当前数值不一致时,直接存储                    m_vetEffectivePress.push_back(stPress);                                     }}itvet = m_vetPress.erase(itvet++);}

4:图形绘制

经过上述数据处理后,我们可以直接在panitEvent中直接绘制出m_vetEffectivePress图形了。

实际代码效果如下:

QPainter painter(this);painter.setRenderHint(QPainter::Antialiasing); //抗锯齿QPolygon polygon;for (int i = 0; i < m_vetEffectivePress.size(); i++){DrawingEffectivePress stPoint = m_vetEffectivePress[i];int nX = this->CalcRealPointX(stPoint.dwPressTime);int nY = this->CalcRealPointY(stPoint.nDepth);polygon << QPoint(nX, nY);}painter.drawPolyline(polygon);

代码解析:根据实际数据的操作时间以及具体的深度值,可以确定波形图的x轴与y轴了。

根据时间的变化,就可以让图形看起来是一种动起来的效果。

CalcRealPointX实际处理

//TODO:计算,实际的x轴坐标DWORD dwCurrent = GetTickCount();int nRectRight = rect().right();int nMoveOriginal = dwDepthTime - dwCurrent;double dMoveLen = nMoveOriginal / 8;int nX = nRectRight + dMoveLen;return nX;

代码解析:实时获取当前绘制时间,并减去结构体中存储的深度时间,设置移动长度(dwMoveOriginal)。

因为要向左偏移,所以,每次用窗口的右侧区域减去就可以了。

注意:我这里使用的是"+",因为我计算得出的偏移长度一定是一个负值。实时时间一定会比实际深度时间大,所以结果肯定是一个负值。

到这里,我们的实时图形绘制算是完成了80%了,想要绘制出连续的实时深度值图形就可以实现了。

为什么说是80%呢?

因为还有一个我们需要考虑的问题,当不是连续数据获取时,使用QPolygon绘制图形时,就会出现以下效果:

Qt中怎么使用PaintEvent绘制实时波形图

当我们不是连续绘制深度值时,间隔一定时间后,再进行绘图时,就会出现上述红色区域框出来的诡异现象。

按照实际应用的绘制效果就应该如同文章刚开始的效果一样,间隔一定时间后,再次绘制,应该还是一条完整的波形数据。

QPolygon这个绘制类显然使用上述代码是不支持的,即使我们换成了DrawLine的方式,这个问题还是需要被解决的。

此时,我们就需要做一个特殊处理,当我们没有实际深度值数据时,需要实时知道当前的绘制点在哪个位置,也就是说,在没有真实数据来临之前,我们需要每间隔一个绘图数据刷新时间,需要绘制一条直线,而不是直接从上一个绘制点直接绘制波形图。

读到这里,这篇“Qt中怎么使用PaintEvent绘制实时波形图”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注编程网行业资讯频道。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Qt中怎么使用PaintEvent绘制实时波形图

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Qt中怎么使用PaintEvent绘制实时波形图

本文小编为大家详细介绍“Qt中怎么使用PaintEvent绘制实时波形图”,内容详细,步骤清晰,细节处理妥当,希望这篇“Qt中怎么使用PaintEvent绘制实时波形图”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧
2023-06-30

怎么在python中使用opencv绘制图形

这篇文章给大家介绍怎么在python中使用opencv绘制图形,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。实现方法1)画线段 cv.line在图片中绘制一段直线# 绘制线段# 参数1:图片# 参数2:起点# 参数3:
2023-06-14

Python中怎么使用Matplotlib库绘制图形

这篇文章主要介绍“Python中怎么使用Matplotlib库绘制图形”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Python中怎么使用Matplotlib库绘制图形”文章能帮助大家解决问题。一、
2023-07-02

Python怎么使用pyecharts绘制箱形图

这篇文章主要介绍“Python怎么使用pyecharts绘制箱形图”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Python怎么使用pyecharts绘制箱形图”文章能帮助大家解决问题。箱形图概念后
2023-07-02

怎么使用Python Matplotlib绘制条形图

今天小编给大家分享一下怎么使用Python Matplotlib绘制条形图的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。前言
2023-07-02

怎么使用Python+turtle绘制对称图形

这篇文章主要介绍“怎么使用Python+turtle绘制对称图形”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“怎么使用Python+turtle绘制对称图形”文章能帮助大家解决问题。1.图1第一个图
2023-07-02

使用Python怎么绘制柱状图和条形图

今天就跟大家聊聊有关使用Python怎么绘制柱状图和条形图,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。一、实验目的:1.掌握Python中柱状图、条形图绘图函数的使用2.利用上述绘
2023-06-15

怎么在Android中实现绘制各种图形

怎么在Android中实现绘制各种图形?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。首先自定义一个View类,这个view类里面需要一个Paint对象来控制图形的属性,需要
2023-05-30

python怎么使用Matplotlib绘制多种常见图形

今天小编给大家分享一下python怎么使用Matplotlib绘制多种常见图形的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。
2023-06-30

微信小程序中怎么用Canvas绘制图形

在微信小程序中使用Canvas绘制图形需要以下步骤:在wxml文件中添加Canvas组件:在js文件中获取Canvas的上下文对象,并设置绘制参数:// 获取Can
微信小程序中怎么用Canvas绘制图形
2024-04-03

怎么使用vue+echarts绘制折线图、柱状图和扇形图

这篇“怎么使用vue+echarts绘制折线图、柱状图和扇形图”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“怎么使用vue+
2023-07-05

使用canvas怎么绘制一个树形结构的可视图形

这篇文章给大家介绍使用canvas怎么绘制一个树形结构的可视图形,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。树形分支是后端接口返回数据渲染,可展示多条;代码可拓展,可封装;点击节点可查看备注;2023-06-09

怎么使用pyecharts绘制时间轮播图

本篇内容介绍了“怎么使用pyecharts绘制时间轮播图”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1、pyecharts绘制时间轮播柱形
2023-07-02

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录