QT使用Qchart实时显示多条曲线绘制

2,016 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第10天,点击查看活动详情

之前由于没有绘图需求,一直没有关注QChart这个类,最近有个朋友向我求助,如何将STM32的四个数据实时绘制到图中,于是将朋友的需求转换成代码并记录下来。

废话不多说,先看一下代码最终的效果,本代码以两条曲线为例,如果需要添加更多曲线,直接在源码中修改即可。

image.png

界面最上面的按钮中"clear window"作用是清除界面中已经绘制的曲线,并且停止曲线绘制,"data generate"作用是生成数据并开始实时绘制曲线。由于只包含两条曲线,因此曲线对象的名称也只有两个,分别是"V/T Curve"和"I/TCurve",这个名字随便取,只要符合自己数据表示的意义即可,此处作为demo,名字也是随意取的。

image.png

绘图过程中设置了计时器,从而实现周期性绘图,每隔1秒绘制一次数据,两个数据同时绘制。

下面直接上代码 首先UI文件设置如下

image.png

然后在项目文件中添加如下一行代码

QT       += charts
// widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QTimer>
#include <QChartView>
#include <QValueAxis>
#include <QLineSeries>
// 加入命名空间
QT_CHARTS_USE_NAMESPACE
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
    Q_OBJECT
public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();
private:
    Ui::Widget *ui;
private:
    QTimer* myTimer;
    //图表对象
    QChart* myChart;
    QChart* myChart1;
    // 横纵坐标轴对象
    QValueAxis *myAxisX, *myAxisY;
    // 曲线图对象
    QLineSeries* myLineSeries;
    QLineSeries* myLineSeries1;
    // 横纵坐标最大显示范围
    const int AXIS_MAX_X = 10, AXIS_MAX_Y = 10;
    // 用来记录数据点数
    int pointCount = 0;
private slots:
    void slotBtnClear();
    void slotBtnStartAndStop();
    void slotTimeout();

};

#endif // WIDGET_H

//widget.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    myTimer = new QTimer(this);
    myTimer->setSingleShot(false);
    QObject::connect(myTimer, SIGNAL(timeout()), this, SLOT(slotTimeout()));
    QObject::connect(ui->btnClear, SIGNAL(clicked(bool)), this, SLOT(slotBtnClear()));
    QObject::connect(ui->btnStartAndStop, SIGNAL(clicked(bool)), this, SLOT(slotBtnStartAndStop()));
    // 创建横纵坐标轴并设置显示范围
    myAxisX = new QValueAxis();
    myAxisY = new QValueAxis();
    myAxisX->setTitleText("V");
    myAxisY->setTitleText("T");
    myAxisX->setMin(0);
    myAxisY->setMax(0);
    myAxisX->setMax(AXIS_MAX_X);
    myAxisY->setMax(AXIS_MAX_Y);
    // 创建曲线对象
    myLineSeries = new QLineSeries();
    myLineSeries1 = new QLineSeries();
    // 将数据设置可见
    myLineSeries->setPointsVisible(true);
    myLineSeries1->setPointsVisible(true);
    myLineSeries->setName("V/T-Curve");
    myLineSeries1->setName("I/T-Curve");
    // 创建图表对象
    myChart = new QChart();
    // 坐标轴添加到图表中
    myChart->addAxis(myAxisX, Qt::AlignLeft);
    myChart->addAxis(myAxisY, Qt::AlignBottom);
    // 将曲线添加到图表
    myChart->addSeries(myLineSeries);
    myChart->addSeries(myLineSeries1);
    // 设置权限过渡动画
    myChart->setAnimationOptions(QChart::SeriesAnimations);
    // 曲线对象关联坐标轴,该步骤必须置于曲线添加到图标之后
    myLineSeries->attachAxis(myAxisX);
    myLineSeries->attachAxis(myAxisY);
    myLineSeries1->attachAxis(myAxisX);
    myLineSeries1->attachAxis(myAxisY);
    // 将图表对象设置到graphicsView上进行显示
    ui->graphicsView->setChart(myChart);
    // 为了使曲线看起来更加平滑设置渲染:抗锯齿
    ui->graphicsView->setRenderHint(QPainter::RenderHint::Antialiasing);
}
Widget::~Widget()
{
    delete ui;
}
// 清除chart中所有的坐标
void Widget::slotBtnClear()
{
    myLineSeries->clear();
    myLineSeries1->clear();
    myChart->axisX()->setMin(0);
    myChart->axisX()->setMax(AXIS_MAX_X);
    pointCount = 0;
}
// 设置定时器
void Widget::slotBtnStartAndStop()
{
    if(myTimer->isActive())
    {
        myTimer->stop();
        ui->btnStartAndStop->setText("timer start");
    }else
    {
        pointCount = 0;
        myTimer->start(1000);
        ui->btnStartAndStop->setText("timer stop");
    }
}
// 设置定时器触发函数,主要是更新数据
void Widget::slotTimeout()
{
    if(pointCount > AXIS_MAX_X)
    {
        myLineSeries->remove(0);
        myLineSeries1->remove(0);
        myChart->axisX()->setMin(pointCount - AXIS_MAX_X);
        // 更新X轴范围,此处设定一直保持0-10范围,超出后归零
        myChart->axisX()->setMax(pointCount);
    }
    // 第一条曲线显示数据
    myLineSeries->append(QPointF(pointCount, (rand() % AXIS_MAX_Y)));
    // 第二条曲线显示数据
    myLineSeries1->append(QPointF(pointCount, (rand() % AXIS_MAX_Y)+2));
    pointCount++;
    if(pointCount > 11)
    {
        myLineSeries->clear();
        myLineSeries1->clear();
        myChart->axisX()->setMin(0);
        myChart->axisX()->setMax(AXIS_MAX_X);
        pointCount = 0;
    }
}

此处main.cpp就不放上去了,新建工程时直接用默认的main.cpp即可,没有改动。需要整个工程目录的可以在评论中联系我,直接邮箱发送给你即可,一起学习以期提高。