当前位置: 首页 > article >正文

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


http://www.kler.cn/news/327375.html

相关文章:

  • 从入门到精通:单片机 100个关键技术关键词
  • (最新已验证)stm32 + 新版 onenet +dht11+esp8266/01s + mqtt物联网(含微信小程序)上报温湿度和控制单片机(保姆级教程)
  • 信号量SEM
  • 淘宝商品详情API接口多线程调用:解锁数据分析行业的效率新篇章
  • Linux防火墙配置绿色端口,解决无法访问java服务的问题
  • LINUX下的驱动开发三
  • window系统下nginx管理脚本
  • 【数据库】深入解析 MongoDB 数据库语法
  • 《OpenCV 计算机视觉》—— 视频背景建模
  • 【React】react hooks的使用规则
  • 基于深度学习的持续的知识积累与转移
  • golang学习笔记19-面向对象(一):面向对象的引入
  • 9.30学习
  • 南沙C++信奥赛陈老师解一本通题: 1963:【13NOIP普及组】小朋友的数字
  • Redis 性能优化的高频面试题及答案
  • HAProxy 安全配置
  • 正则表达式中的贪婪模式和非贪婪模式
  • [大语言模型-论文精读] 大语言模型是单样本URL分类器和解释器
  • 相互作用的检索增强 3D 分子生成扩散模型 - IRDiff 评测
  • 滚雪球学MySQL[5.1讲]:事务与并发控制
  • 如何使用ssm实现钢铁集团公司安全管理系统的构建与实现
  • 基于小步大步法(BSGS)的同态加密多项式求值
  • 滚雪球学Oracle[2.1讲]:Oracle数据库安装与配置
  • 新品上市!智能无线接入型路由器ZX7981EP,WIFI6技术双频频段
  • 解锁微信小程序新技能:ECharts动态折线图搭配WebSocket,数据刷新快人一步!
  • 数据库 - Mongo数据库
  • 第166天:应急响应-拒绝服务钓鱼指南DDOS压力测试邮件反制分析应用日志
  • ubuntu server 常用配置
  • Spring面试内容大纲
  • ios内购支付-支付宝APP支付提现