Qt Chart在Qml中初体验

Chart之初体验

  • Qml与QCustomPlot
    • 准备
    • 使用
    • 实时曲线
      • Qml中获取数据
      • ChartView的Scroll函数让曲线移动起来
      • 坐标轴Range动起来
      • 坐标动起来,然后replace
        • Qml的坑

Qml与QCustomPlot

最近想在Qml中实现绘制实时曲线,一开始想到了好用且强大的[*QCustomPlot][1],但伤心的发现其在Qml中无法使用。因为其是基于QWidget开发而来的第三方库,所以只好用Qt自带的Chart来在Qml中画曲线了。
Qt Chart在Qml中初体验_第1张图片而且Chart的画图功能也很是炫酷
Qt Chart在Qml中初体验_第2张图片

准备

Qt的chart可以用在 QWidgets, QGraphicsWidget, or QML 工程中。如果在Qml文件中使用chart需要导入 如下包

  import QtCharts 2.2

如果在C++类中使用Qt Charts ,则需要使用include和using

  #include <QtCharts>
  using namespace QtCharts;

在Qml文件中使用Chart,有一点需要特别注意。就是需要替换qml模板中的QGuiApplication为QApplication,因为Chart需要依赖于Qt的 Graphics View Framework来渲染。
Qt帮助文档:关键词Qt Charts 最后还需要在qmake project文件中添加 QT += charts

使用

Page {
    width: 600
    height: 400

    ChartView {
        id:chartView
        title: "Spline"
        anchors.fill:parent;
        theme: ChartView.ChartThemeBlueNcs 
        antialiasing: true
        animationOptions:SeriesAnimations
        ValueAxis {
            id: axisX   
            min: 0
            max: 10
            tickCount:50
        }
        ValueAxis {
            id: axisY
            min: -1.5
            max: 2.5
        }
        SplineSeries {
                 id:spline1;
                 name: "SplineSeries"
                 axisX: axisX
                 axisY: axisY
                 color:"green"
                 width:2
                 capStyle:"RoundCap";
                 style :"DashLine"
                 XYPoint { x: 0; y: 0.19 }
                 XYPoint { x: 1; y: 2.0 }
                 XYPoint { x: 2; y: 0.8 }
                 XYPoint { x: 3; y: 1.5 }
                 XYPoint { x: 5; y: 0.5 }
                 XYPoint { x: 7; y: 2.3 }
      }
    }
}

运行结果如下
Qt Chart在Qml中初体验_第3张图片

实时曲线

Qml中获取数据

在C++类中定义信号

signals:   
    void dataReady(qreal x , qreal y);

在Qml文件中定义信号处理器

 Connections{
        target:MAVLinkProtocol;
        onDataReady:{
        	spline1.append(x,y);
        	//console.log("x:"+x.toString()+" "+"y:"+y.toString());
        }

需要注意
1.信号处理器onDataReady 是on+信号首字母大写
2.在信号处理器中可直接应用C++中信号声明时的参数名字,这里是 x和y
3.这里曲线当超出axisX .max 属性的值时将不会更新了

ChartView的Scroll函数让曲线移动起来

onDataReady:{
        	spline1.append(x,y);
        	if(scatter1.count>40) {       //这里40仅用于测试
                   chartView.scrollRight(1);
                }
        	//console.log("x:"+x.toString()+" "+"y:"+y.toString());
        }

一开始不知道怎么实现滚动条的效果,惊奇的发现ChartView QML Type 有个scrollRight(real pixels)方法,很是开心。
scrollRight但是实际运行起来很是卡顿,单单一个exe的CPU占用达到20%,说明Scroll效率极低,而且这里参数像素,和想要移动的距离是什么关系不知道。

坐标轴Range动起来

        onDataReady:{
	       spline1.append(x,y);
	       if(x>axisX.max){
	                axisX.min = axisX.min + (x-axisX.max);
	                axisX.max = x;
	                //axisX.min = axisX.min + (x-axisX.max)+0.2;//0.2是往左侧偏移一点,便于观察最右侧点
	                //axisX.max = x+0.2;
	          }
//            console.log("x:"+MAVLinkProtocol.xQml.toString()+" "+"y:"+MAVLinkProtocol.yQml.toString());
        }

实际运行起来,还是很卡顿,说明可能并不是Scroll导致的卡顿而是append效率低下。

坐标动起来,然后replace

在这里插入图片描述C++类定义中更改

  signals:
    void dataReady(QVector<QPointF> pointsBuffer);
  private slots:
    void handleDataGeneratorTimeout();
  private:
    static const int sampleCount = 5;   //测试取5
    QTimer *myDataGeneratorTimer;
    qreal x=0;
    qreal y=0;
    QVector<QPointF> pointsVector;

在构造函数中初始化Timer ,连接到相应槽,并启动,槽函数如下

void MAVLinkProtocol::handleDataGeneratorTimeout()
{
    x+=0.2;       //生成实时数据点
    y= sin(x);

    if (pointsVector.isEmpty()) {
        pointsVector.reserve(sampleCount);
        for (int i = 0; i < sampleCount; ++i)
            pointsVector.append(QPointF(i, 0));
    }

    int start = 0;
    const int availableSamples = 1;

    if (availableSamples < sampleCount) {
        start = sampleCount - availableSamples;
        for (int s = 0; s < start; s++)
        {
            pointsVector[s].setY(pointsVector.at(s + availableSamples).y());
            pointsVector[s].setX(pointsVector.at(s + availableSamples).x());
        }
    }
    for (int s = start; s < sampleCount; s++)
    {
        pointsVector[s].setY(y);
        pointsVector[s].setX(x);
    }
//   qDebug()<
    emit dataReady(pointsVector);
}

这里的槽函数参考Chart的例程Audio Example , pointsVector[s]类似于链表,每次更新availableSamples 个点。
这里sampleCount取5,总共5个点,每次更新一个点,实际情况画图便知。下面便来到Qml的大坑……

Qml的坑

        onDataReady:{
	       spline1.replace(pointsBuffer)
        }

运行起来后报错

qrc:/Page2Form.ui.qml:54: Error: Unable to determine callable overload.  Candidates are:
    replace(int,double,double)
    replace(double,double,double,double)

竟然不能调用重载,Qml竟然没有这个函数的重载……
后来一想onDataReady带来的C++中的QVector类型变量,这在Qml中是没有的,不可能有这个重载……
MD,Qml写界面是漂亮,但缺少很多C++的东西,还是用QtWidget 拥抱C++吧,说多都是泪……

如果您觉得本文对您有些许帮助,请小小打赏一下作者,我会更加有动力写出高质量Qt 、QGC、 PX4开发的文章
Qt Chart在Qml中初体验_第4张图片
[1][https://www.qcustomplot.com/]

你可能感兴趣的:(Qt开发)