Qt学习:QtCharts绘制动态曲线,实时更新数据与坐标轴
阅读原文时间:2020年11月10日阅读:89

1.首先是掌握qtchart的基本使用,封装一个属于自己的绘图类:
Mychart.h

#pragma once
#ifndef CHART_H
#define CHART_H

#include <QtCharts/QChart>    
#include<QtCharts\QChartView>   //两个基本模块
#include<QPointF>     //点类
#include<QList>         //列表
#include <QtCore/QTimer>   //定时器

QT_CHARTS_BEGIN_NAMESPACE    
class QSplineSeries;
class QValueAxis;                 //引入这两个类而免于引入整个头文件的方法
QT_CHARTS_END_NAMESPACE

QT_CHARTS_USE_NAMESPACE   //使用qtchart需要加入这条语句

//![1]
class Chart : public QChart
{
    Q_OBJECT
public:
    Chart(QGraphicsItem *parent = 0, Qt::WindowFlags wFlags = 0);
    QChartView *m_chartView;   //因为布局时其它函数会访问这个画布,所以设为public
    virtual ~Chart();
    QList<QPointF> setdata();    //预留这个函数作为一个设置图表数据的接口,将外界数据传给图表
public slots:
//    void handleTimeout();
//几个操作数据的槽函数
    void addSeries(QList<QPointF> &data);     //新增一条曲线
    void removeSeries();                            //移出一条曲线
    void connectMarkers();                   //连接图线与图例
    void disconnectMarkers();               //断开图线与图例
    void handleMarkerClicked();           //占击图例时的处理函数
protected:
    void timerEvent(QTimerEvent *event)Q_DECL_OVERRIDE;  //定时器触发事件,重构
private:
    QTimer m_timer;     //定时器指针

    QChart * m_chart;     //图表组件,可理解为画笔,用它画曲线
    QList<QSplineSeries *> m_serieslist;   //曲线列表,splineseries为光滑曲线

    QSplineSeries *m_series;     //曲线指针
    QStringList m_titles;             //标题
    QValueAxis *axisX;             //x坐标轴
    QValueAxis *axisY;             //y坐标轴

    qreal m_step;                  
    qreal m_x;
    qreal m_y;
};
//![1]

#endif /* CHART_H */

MyChart.cpp

#include "MyChart.h"
#include <QtCharts/QAbstractAxis>
#include <QtCharts/QSplineSeries>
#include <QtCharts/QValueAxis>
#include <QtCore/QTime>
#include <QtCore/QDebug>
#include <QPen>
#include<QPainter>
#include<QtCharts\QLegendMarker>
#include<qmath.h>

int timeId;

Chart::Chart(QGraphicsItem *parent, Qt::WindowFlags wFlags) :QChart(QChart::ChartTypeCartesian, parent, wFlags)
{
    m_chart = new QChart;
    m_chartView = new QChartView(m_chart);
    m_chartView->setRubberBand(QChartView::RectangleRubberBand);  //矩形缩放
    //设置x坐标轴
    axisX = new QValueAxis;
    //axisX->setRange(0, 1000);  //范围
    axisX->setLabelFormat("%d"); //图例的格式  %d为十进制显示
    axisX->setGridLineVisible(true);//网格
    //axisX->setTickCount(11);   //主要刻度
//    axisX->setMinorTickCount(5);//小刻度
    axisX->setTitleText("time/(s)");//标题
//设置y坐标轴
    axisY = new QValueAxis;
    axisY->setRange(0, 20);
    axisY->setLabelFormat("%d");
    axisY->setGridLineVisible(true);
    axisY->setTickCount(10);
    axisY->setMinorTickCount(5);
    axisY->setTitleText("altitude/(%)");

    m_chart->addAxis(axisX, Qt::AlignBottom);  //将坐标轴加到chart上,居下
    m_chart->addAxis(axisY, Qt::AlignLeft);//居左

   //m_chart->setTitle("example of chart");   //设置图表标题
    //m_chart->setAnimationOptions(QChart::SeriesAnimations);  //曲线动画模式,不能启用这一项或是选择这个选项,这个会导致曲线闪烁
    m_chart->legend()->setVisible(true);  //设置图例可见
  //生成一小段数据列表用作绘图初始数据
    QList<QPointF> mydata1;
    for (int i = 0; i <100; i++)
    {
        mydata1.append(QPointF(i, 0.01*i));
    }
    addSeries(mydata1); //增加一条曲线,数据集为mydata1
   connectMarkers();  //将曲线与图例连接起来,可以勾选进行显示与隐藏

    m_chart->setAxisX(axisX, m_serieslist.first());  //将x和y坐标轴与第一条曲线连接
    m_chart->setAxisY(axisY, m_serieslist.first());
    timeId = startTimer(500);    //qobject中的函数,设置定时器时间间隔

}

Chart::~Chart()
{

}


void Chart::addSeries(QList<QPointF> &data)  //用于新增曲线
{

    QSplineSeries *series = new QSplineSeries();
    m_serieslist.append(series);//将曲线加到曲线列表中进行管理
    series->setName(QString("line " + QString::number(m_serieslist.count()))); //设置曲线对应的名字,用于图例显示
    series->append(data);  //将数据加到曲线中
    m_chart->addSeries(series);//将曲线增入chart中
    axisX->setRange(0, series->count());  //坐标轴初始范围为图表中的数据数。 这个在绘制多条曲线中需注释

}

void Chart::removeSeries()  //移除一条曲线
{
    // Remove last series from chart
    if (m_serieslist.count() > 0) {
        QSplineSeries *series = m_serieslist.last();
        m_chart->removeSeries(series);
        m_serieslist.removeLast();
        delete series;
    }
}

void Chart::connectMarkers()  //将槽函数与图例的鼠标点击事件连接起来
{
    // Connect all markers to handler
    foreach(QLegendMarker* marker, m_chart->legend()->markers()) {
        // Disconnect possible existing connection to avoid multiple connections
        QObject::disconnect(marker, &QLegendMarker::clicked, this, &Chart::handleMarkerClicked);
        QObject::connect(marker, &QLegendMarker::clicked, this, &Chart::handleMarkerClicked);
    }
}

void Chart::disconnectMarkers()
{
    foreach(QLegendMarker* marker, m_chart->legend()->markers()) {
        QObject::disconnect(marker, &QLegendMarker::clicked, this, &Chart::handleMarkerClicked);
    }
}

void Chart::handleMarkerClicked()//图例点击事件
{
    QLegendMarker* marker = qobject_cast<QLegendMarker*> (sender());
    Q_ASSERT(marker);
    //![3]

    //![4]
    switch (marker->type())
        //![4]
    {
    case QLegendMarker::LegendMarkerTypeXY:
    {
        //![5]
        // Toggle visibility of series
        marker->series()->setVisible(!marker->series()->isVisible());

        // Turn legend marker back to visible, since hiding series also hides the marker
        // and we don't want it to happen now.
        marker->setVisible(true);
        //![5]

        //![6]
        // Dim the marker, if series is not visible
        qreal alpha = 1.0;

        if (!marker->series()->isVisible()) {
            alpha = 0.5;
        }

        QColor color;
        QBrush brush = marker->labelBrush();
        color = brush.color();
        color.setAlphaF(alpha);
        brush.setColor(color);
        marker->setLabelBrush(brush);

        brush = marker->brush();
        color = brush.color();
        color.setAlphaF(alpha);
        brush.setColor(color);
        marker->setBrush(brush);

        QPen pen = marker->pen();
        color = pen.color();
        color.setAlphaF(alpha);
        pen.setColor(color);
        marker->setPen(pen);

        //![6]
        break;
    }
    default:
    {
        qDebug() << "Unknown marker type";
        break;
    }
    }
}

QList<QPointF> Chart::setdata()  //设置图表数据的函数接口
{
    QList<QPointF> datalist;
    for (int i = 0; i < 500; i++)
        datalist.append(QPointF(i, i*0.01));
    return datalist;
}

void Chart::timerEvent(QTimerEvent *event)    //定时器事件的重构
{
    if (event->timerId() == timeId)//定时器时间到,模拟数据填充
    {
        static QTime dataTime(QTime::currentTime());
        long int eltime = dataTime.elapsed();  //经过的时间
        static int lastpointtime = 1;
        int size = (eltime - lastpointtime);//数据个数
        qDebug() << "size-->" << size;
        if (isVisible())
        {

            QVector<QPointF>olddata=m_serieslist.first()->pointsVector();
            olddata.append(QPointF(lastpointtime +olddata.count(), lastpointtime*0.3));//填充数据
            axisX->setRange(0, lastpointtime + m_serieslist.first()->count());//设置x坐标轴
            //后期需更改为一开始固定,只有当数据个数超出坐标轴范围时坐标轴开始扩展。
            m_serieslist.first()->replace(olddata);
            lastpointtime++;
        }
    }
}

关于绘制动态曲线,关键就是在设置好初始画布后进行曲线数据的更新,以及坐标轴的更新。
数据更新可以是定时,也可以新建增加数据的槽函数,当接收到外部数 据时,触发信号进行曲线更新。

坐标轴更新是用于扩展坐标轴以适应曲线。

动态绘制曲线的核心是数据点个数变化,数据个数一定的情况下,是通过进行数据更新通过平移以淘汰最开始的数据。
同时要相应地扩展坐标轴或改变坐标轴。

做上位机界面时,要绘制从下位机收到数据的曲线,需要有一个接收和更新数据的buffer或是datalist。 datalist可方便地去数据头和新增数据。可以作为首选。
收到的数据作为y, (count,data)作为新增的数据点。

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章