Qt Charts 动态实时绘制各种曲线图
阅读原文时间:2021年04月15日阅读:21

在Qt Charts发布之前, Qt比较著名两个画图插件是 qwt和Qcustom, 其中Qcustom较轻量,只需要在project 中包含qcustomplot.h 和 qcustomplot.cpp 几乎就可以使用。
相比Qcustom,qwt功能更为强大,但是它的安装十分麻烦,阻挡了很多人(包括我)的使用。
但是qwt只是对静态图表的表示非常不错,动态曲线性能并不突出。如果只是静态绘图,或者动态绘制的点并不多,继续用qwt甚至Qcustom完全没问题。
但是如果是新入手Qt绘图,用Qt charts显然是更好的选择,因为它在各方面都比前两者要好,并且也易于使用。
并且qml也支持charts,qml的渲染默认用GPU,成长性更好。
如果你在安装Qt的时候,选择了Qt charts部分,那么在Qt中使用charts 只需要 在 .pro文件中

QT += charts

并且在程序的开头加上一句 using namespace Qtcharts或者一个宏 QT_CHARTS_USE_NAMESPACE

进入主题: 动态实时折线图绘制

动态绘图,也就是说折线随着横坐标的增长而实时变化。

从这一秒和上一秒的变化看来,就是坐标轴不动,整个图像往前移了一个单位,然后在空出的最后一个位置增加了一个新的点。

想一下,只要你的显示器不能够随着横坐标的增长变宽,上面说的就是不得不做的事情。或者除非你不把最前面的那个点淘汰掉,但是那样的话,你的点只有增,没有删,随着时间的增长,点越来越多,曲线最后只会挤成一团,啥也看不清。
【多说一句,从相对的角度来说,既然可以把图像往前移一个单位,当然也可以坐标轴往后移一个单位,两者造成的结果当然是一样的。
Qt有一个函数scroll可以实现后者的功能,它有两个参数,可以设置每次x、y轴向右和向上滚动的距离。但是scroll函数绘制坐标轴感觉很奇怪……真的有一种在滚的感觉,看起来很难受,具体可以看Qt欢迎界面里面的一个示例子dynamicspline】

Qt charts中,可以主要一下几个类: QChart 和 QChartView,QChart是用什么画,差不多画笔的意思,QChartView是在什么上画,差不多画布的意思。

 m_chartView = new QChartView(m_chart,this);//画布
    m_chart = m_chartView->chart();//画笔

画笔绑在画布上,就新建了一个QChartView 和一个 QChart 指针。
 类 Series 是用来添加数据的对象(可以理解为一个集合)。常见的 QLineSeries,折线类,画出来的先棱角更强,QSplineSeries,曲线类,画出来更平滑,QScatterSeries,点类,画出来是一个个单独的点。Qt文档对这些类都有很详细的说明,并配有图画。
类似于QChart 、QChartView、Series ,还有QValueAxis类(数值类型的坐标轴)等等,不再啰嗦,下面的代码里都有。并且有很详细的注释,想学的朋友一定仔细看一遍肯定能看明白。
 

 ui->setupUi(this);
    m_chart = new QChart();
    m_chartView = new QChartView(m_chart,this);//画布
    m_chart = m_chartView->chart();//画笔
    m_chartView->setRubberBand(QChartView::NoRubberBand);  //矩形缩放

    m_chartView->setRenderHint(QPainter::Antialiasing); //设置抗锯齿
    m_chartView->resize(600, 600);   //画布大小
    m_chartView->setContentsMargins(0,0,0,0);
    m_chartView->show(); //显示
    //设置x坐标轴
    axisX = new QValueAxis;
    axisX->setRange(0, 100);  //范围
    axisX->setLabelFormat("%d"); //图例的格式  %d为十进制显示
    axisX->setGridLineVisible(true);//网格
    axisX->setTickCount(10);   //主要刻度
//    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);  //设置图例可见
    m_chart->legend()->setLayoutDirection(Qt::LeftToRight);
    m_chart->legend()->setAlignment(Qt::AlignLeft);
  //生成一小段数据列表用作绘图初始数据
    QList<QPointF> mydata1;
    for (int i = 0; i <100; i++)
    {
        mydata1.append(QPointF(i, 0.1*i));
    }
    addSeries(mydata1); //增加一条曲线,数据集为mydata1
    connectMarkers();  //将曲线与图例连接起来,可以勾选进行显示与隐藏

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

线都是又一系列的点构成的,线是点的集合,容器里在包含一系列的线,用画笔绘制在画布上,这就是QChart

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

    QSplineSeries *series = new QSplineSeries(this);//平滑曲线的集合
    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());  //坐标轴初始范围为图表中的数据数。 这个在绘制多条曲线中需注释
    QPen splinePen ,linePen;
    splinePen.setBrush(Qt::red);
    splinePen.setColor(Qt::red);
    series->setPen(splinePen);

    QSplineSeries *lineSeries = new QSplineSeries(this);//折线类点的集合
    lineSeries->setName(QStringLiteral("折线"));
    QList<QPointF> lineData;
    QPoint newPoint;
    foreach (QPointF point, data) {
       newPoint.setX(point.x() * 1.5);
       newPoint.setY(point.y() * 1.5);
       lineData.append(newPoint);
    }
//    lineSeries->append(0,0);
//    lineSeries->append(10,10);
//    lineSeries->append(15,15);
    lineSeries->append(lineData);
    linePen.setBrush(Qt::yellow);
    lineSeries->setPen(linePen);
    m_serieslist.append(lineSeries);
    m_chart->addSeries(lineSeries);

}

的思想

利用定时器定时刷新不同的点,来实时绘制动态曲线

void Widget::timerEvent(QTimerEvent *event)    //定时器事件的重构
{
    if (event->timerId() == timeId)//定时器时间到,模拟数据填充
    {
        static QTime dataTime(QTime::currentTime());
        long int eltime = dataTime.elapsed();  //上次start经过毫秒数
        static int lastpointtime = 1;
        int size = (eltime - lastpointtime);//数据个数
        qDebug() << "size-->" << size;
        foreach (QSplineSeries  *splineSeries, m_serieslist) {
            if (splineSeries->isVisible())
            {
                QVector<QPointF> olddata = splineSeries->pointsVector();
                olddata.append(QPointF(lastpointtime +olddata.count(), lastpointtime*0.3));//填充数据--->>相当于每一分钟增加一点
                axisX->setRange(0, lastpointtime + splineSeries->count());//设置x坐标轴
                //后期需更改为一开始固定,只有当数据个数超出坐标轴范围时坐标轴开始扩展。
                splineSeries->replace(olddata);
                lastpointtime++;
            }
        }

    }
}

效果图

源码请在链接在找到源码

手机扫一扫

移动阅读更方便

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

你可能感兴趣的文章