使用Qt实现实时数据动态绘制的折线图示例

基于Qt的 QChartView 和定时器来动态绘制折线图。它通过动画的方式逐步将数据点添加到图表上,并动态更新坐标轴的范围,提供了一个可以实时更新数据的折线图应用。以下是对代码的详细介绍及其功能解析:
在这里插入图片描述

代码概述

该程序使用Qt的 QChartView 作为图表绘制的基础,结合 QLineSeriesQSplineSeries 来绘制折线或样条曲线。程序通过定时器 (QTimer) 控制数据点的动态绘制,并在绘图过程中实时更新坐标轴的显示范围。

主要功能
  • 动态创建系列:可以动态创建多个曲线系列(QLineSeriesQSplineSeries),每个系列对应一条折线或样条曲线。
  • 动态添加数据点:通过 addPointAnimated() 函数,可以为每个系列动态添加数据点,并通过动画效果逐步连接新数据点。
  • 定时更新:使用 QTimer 每隔一段时间调用 animateDrawing() 函数,逐步将新点连接到已有的曲线上。
  • 自动调整坐标轴范围:在绘制过程中,如果新点超出了当前坐标轴范围,坐标轴会自动调整以适应新的数据点。

代码结构

1. DynamicChart 类构造函数
DynamicChart::DynamicChart(QWidget *parent)
    : QChartView(new QChart(), parent), m_chart(this->chart())
{
    m_chart->setTitle("Dynamic Data Plot");
    m_chart->legend()->hide();
    setRenderHint(QPainter::Antialiasing);

    // 设置图表主题和隐藏图例
    m_chart->setTheme(QChart::ChartTheme::ChartThemeDark);

    // 创建共用的坐标轴
    axisX = new QValueAxis();
    axisX->setRange(0, 100);
    m_chart->addAxis(axisX, Qt::AlignBottom);

    axisY = new QValueAxis();
    axisY->setRange(0, 100);
    m_chart->addAxis(axisY, Qt::AlignLeft);

    // 设置定时器
    connect(&timer, &QTimer::timeout, this, &DynamicChart::animateDrawing);
    timer.setInterval(30); // 动画更新间隔为30毫秒
    resize(500,500);
}

该构造函数中设置了图表的主题、坐标轴、以及定时器,定时器的作用是每隔30毫秒触发 animateDrawing() 函数,用于动态绘制数据。

2. createSeries() 函数
void DynamicChart::createSeries(int seriesId, const QString &name)
{
#ifdef LINE
    QLineSeries *series = new QLineSeries();
#else
    QSplineSeries *series = new QSplineSeries();
#endif
    series->setName(name);
    m_chart->addSeries(series);

    // 使用共用的坐标轴
    series->attachAxis(axisX);
    series->attachAxis(axisY);

    seriesMap.insert(seriesId, series);
}

该函数负责创建新的系列(折线或样条曲线),并将其添加到图表中。 seriesId 用于标识不同的曲线,name 则用于显示系列的名称。系列将共享同一套坐标轴。

3. addPointAnimated() 函数
void DynamicChart::addPointAnimated(int seriesId, const QPointF &point)
{
    if (!seriesMap.contains(seriesId)) return;
#ifdef LINE
    QLineSeries *series = seriesMap[seriesId];
#else
    QSplineSeries *series =seriesMap[seriesId];
#endif

    if (!series->points().isEmpty()) {
        lastPoint = series->points().last();
    } else {
        lastPoint = point; // 第一个点直接添加
        series->append(point);
    }
    newPoint = point;
    currentSeriesId = seriesId;
    currentStep = 0;
    stepsCount = 10; // 分10步完成连线
    timer.start();
}

该函数用于为指定的系列添加新点,并通过动画效果使新点逐步出现在图表上。它会计算新点与最后一个点之间的插值,并逐步绘制曲线。

4. animateDrawing() 函数
void DynamicChart::animateDrawing()
{
#ifdef LINE
    QLineSeries *series = seriesMap[currentSeriesId];
#else
    QSplineSeries *series =seriesMap[currentSeriesId];
#endif
    if (currentStep >= stepsCount) {
        timer.stop();
        series->append(newPoint);
        return;
    }

    qreal x = lastPoint.x() + (newPoint.x() - lastPoint.x()) * currentStep / stepsCount;
    qreal y = lastPoint.y() + (newPoint.y() - lastPoint.y()) * currentStep / stepsCount;
    series->append(x, y);

    // 动态更新坐标轴
    if (x > axisX->max()) {
        axisX->setMax(x + 10);
    }
    if (y > axisY->max() || y < axisY->min()) {
        axisY->setMax(qMax(y + 10, axisY->max()));
        axisY->setMin(qMin(y - 10, axisY->min()));
    }

    currentStep++;
}

该函数实现了通过定时器触发的动态绘制。它逐步将新点与前一个点连接,并动态调整坐标轴的范围以适应新增数据。

主窗口逻辑

最后的代码片段展示了如何使用 DynamicChart 类创建一个包含多个曲线的图表,并通过按钮控制定时器的启动与停止:

setMinimumSize(QSize(800,500));
chartView = new DynamicChart(this);
chartView->createSeries(1, "Test Series 1");
chartView->createSeries(2, "Test Series 2");
chartView->createSeries(3, "Test Series 3");
chartView->createSeries(4, "Test Series 4");

QTimer *timer = new QTimer;
connect(timer, &QTimer::timeout, this, [=]()
{
    int m_id = QRandomGenerator::global()->bounded(1, 5);
    chartView->addPointAnimated(m_id, QPointF(m_index++, QRandomGenerator::global()->bounded(100)));
});

startButton = new QRadioButton("StartDrawing", this);
connect(startButton, &QRadioButton::clicked, [=](bool arg)
{
    if (arg)
        timer->start(100);
    else
        timer->stop();
});

通过 QRadioButton 控制定时器的启停,点击按钮后,程序将开始在图表上随机添加点,并动态绘制折线或样条曲线。

结论

此程序通过Qt的 QChartView 和定时器,实现了一个能够动态绘制多条曲线的折线图表。通过定时器控制数据点的逐步绘制,并结合坐标轴的动态更新,使得该图表在绘图过程中能够自动适应数据的变化。这种方式适用于需要实时显示数据变化的场景,如传感器数据的实时监控或动态性能分析等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/885501.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Vxe UI vue 使用 vxe-form 表单实现简历模板

Vxe UI 使用 vxe-form 表单实现简历模板 查看 github <template><div><p>边框&#xff1a;<vxe-switch v-model"border"></vxe-switch>标题背景&#xff1a;<vxe-switch v-model"titleBackground"></vxe-switch&…

鸿蒙开发(NEXT/API 12)【请求用户授权】手机侧应用开发

为保护用户隐私&#xff0c;Wear Engine的API需要用户授权才可以正常访问。建议开发者在用户首次调用Wear Engine开放能力的时候执行本章节操作。 申请用户穿戴设备权限 应用拉起华为账号登录和授权界面&#xff0c;由用户授权相应的数据访问权限。用户可以自主选择授权的数据…

计算机毕业设计 二手图书交易系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

如何利用ChatGPT开发一个盈利的AI写作助手网站

3-1 整体介绍写作助手及原型展示说明 在当今数字化时代&#xff0c;人工智能&#xff08;AI&#xff09;技术正逐步改变我们的生活方式&#xff0c;特别是在内容创作领域。本文将详细介绍如何利用ChatGPT技术&#xff0c;开发一个能够生成高质量内容的AI写作助手网站&#xff…

黑马头条day10 热点文章定时文章

day8-9是项目实战没有新东西 暂时跳过 进度到这里 但是后边的东西一直跑不通 调度一直失败 我也不知道哪里出了问题 整tm一天了也没搞出来 心态炸了 主要是xxl调度算是新内容 但是一直跑不出来就很烦 所谓的热点也就是计算权值然后存储到redis就行了 未解决&#xff1a; we…

解决Pymysql has no attribute ‘escape_string‘ 并且无法引入该模块

打印出的pymysql版本是1.4.6 需要import这个module&#xff0c;并且根据pymysql的版本import的方式还不同 import pymysqlif pymysql.__version__ >1.0.0:from pymysql.converters import escape_string else:escape_string lambda x: pymysql.escape_string(x)然而&am…

基于ESP8266—AT指令连接阿里云+MQTT透传数据(3)

MQTT_RX设备为接收(订阅)数据的Topic,使用ESP8266通过AT指令实现。 首先需要串口通信软件,如 SSCOM、PuTTY、SecureCRT 等串口调试工具,功能丰富,支持常见的串口调试功能,用于发送AT指令。 以下是ESP8266通过AT指令连接阿里云MQTT服务的步骤: 1、初始化WiFi 发送下面…

BOM对象

BOM对象 ECMAScript BOM DOM BOM&#xff08;Browser Object Model&#xff09;浏览器对象模型 BOM 使 JavaScript 有能力与浏览器“对话” BOM尚无正式标准,但是浏览器已经&#xff08;几乎&#xff09;实现了 JavaScript 交互性方面的相同方法和属性&#xff08;window&a…

详解TCP协议(三次握手四次挥手)

1. TCP通信时序 下图是一次TCP通讯的时序图。TCP连接建立断开。包含大家熟知的三次握手和四次握手。 在这个例子中&#xff0c;首先客户端主动发起连接、发送请求&#xff0c;然后服务器端响应请求&#xff0c;然后客户端主动关闭连接。两条竖线表示通讯的两端&#xff0c;从上…

车视界系统小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;汽车品牌管理&#xff0c;汽车颜色管理&#xff0c;用户管理&#xff0c;汽车信息管理&#xff0c;汽车订单管理系统管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;汽车信息&#xff0c;我…

算法打卡:第十一章 图论part11

今日收获&#xff1a;Floyd 算法&#xff0c;A * 算法&#xff0c;最短路算法总结 1. Floyd 算法 题目链接&#xff1a;97. 小明逛公园 思路&#xff1a;Floyd用于解决多源最短路问题&#xff0c;对边的正负权值没有要求。核心是动态规划 &#xff08;1&#xff09;dp数组的…

Springboot-多数据源

文章目录 一、架构二、实现过程2.1 第一步&#xff1a;引入依赖pom2.2 第二步&#xff1a;创建application.yml配置2.3 第三步&#xff1a;创建架构的文件夹MybatisPlusConfigFirstDataSourceConfigSecondDataSourceConfig 实现功能&#xff0c;在不同的文件夹使用不同的库 一、…

基于Hive和Hadoop的电商消费分析系统

本项目是一个基于大数据技术的电商消费分析系统&#xff0c;旨在为用户提供全面的电商消费信息和深入的消费行为分析。系统采用 Hadoop 平台进行大规模数据存储和处理&#xff0c;利用 MapReduce 进行数据分析和处理&#xff0c;通过 Sqoop 实现数据的导入导出&#xff0c;以 S…

Updates were rejected because the tip of your current branch is behind 的解决方法

1. 问题描述 当我们使用 git push 推送代码出现以下问题时&#xff1a; 2. 原因分析 这个错误提示表明当前本地分支落后于远程分支&#xff0c;因此需要先拉取远程的更改。 3. 解决方法 1、拉取远程更改 在终端中执行以下命令&#xff0c;拉取远程分支的更新并合并到本地…

基于Arduino的L298N电机驱动模块使用

一.简介&#xff1a; L298N作为电机驱动芯片&#xff0c;具有驱动能力强&#xff0c;发热量低&#xff0c;抗干扰能力强的特点,一个模块可同时驱动两个直流电机工作&#xff0c;能够控制电机进行正转、反转、PWM调速。 说明&#xff1a; 1&#xff09;12V输入端口接入供电电压…

cpp,git,unity学习

c#中的? 1. 空值类型&#xff08;Nullable Types&#xff09; ? 可以用于值类型&#xff08;例如 int、bool 等&#xff09;&#xff0c;使它们可以接受 null。通常&#xff0c;值类型不能为 null&#xff0c;但是通过 ? 可以表示它们是可空的。 int? number null; // …

数据分析-28-交互式数据分析EDA工具和低代码数据科学工具

文章目录 1 数据分析的七步指南1.1 第一步:问题定义和数据采集1.2 第二步:数据清洗和预处理1.3 第三步:数据探索和分析1.4 第四步:模型建立和分析1.5 第五步:数据可视化1.6 第六步:结果解释和报告1.7 第七步:部署和维护1.8 基础的数据分析库1.9 低代码数据科学工具2 EDA…

Linux网络操作命令与函数全面总结

1. 引言 Linux作为服务器和开发平台&#xff0c;网络操作是其核心功能之一。本文旨在全面总结Linux系统中的网络操作方法&#xff0c;包括命令行工具和编程接口&#xff0c;帮助读者深入理解Linux网络管理的机制。 2. 命令行工具 2.1 ping 命令 ping 命令用于测试网络连接和…

css的背景background属性

CSS的background属性是一个简写属性&#xff0c;它允许你同时设置元素的多个背景相关的子属性。使用这个属性可以简化代码&#xff0c;使其更加清晰和易于维护。background属性可以设置不同的子属性。 background子属性 定义背景颜色 使用background-color属性 格式&#x…

了解Webpack并处理样式文件

目录 引入定义安装和使用配置文件命令配置单独文件指定文件 处理样式css-loader使用 style-loaderless-loaderPostCSSpostcss-loaderpostcss-preset-env 引入 随着前端的快速发展&#xff0c;目前前端的开发已经变的越来越复杂了&#xff1a; 比如开发过程中我们需要通过模块化…