从c ++推送QML ChartView更新

时间:2017-12-09 00:14:52

标签: c++ qt qml

我试图调整Qt5.9 QML Oscilloscope example以使图表数据从c ++推送而不是从QML请求。以下是QML示波器示例中的相关部分。

datasource.h:

#ifndef DATASOURCE_H
#define DATASOURCE_H

#include <QtCore/QObject>
#include <QtCharts/QAbstractSeries>

QT_BEGIN_NAMESPACE
class QQuickView;
QT_END_NAMESPACE

QT_CHARTS_USE_NAMESPACE

class DataSource : public QObject
{
    Q_OBJECT
public:
    explicit DataSource(QQuickView *appViewer, QObject *parent = 0);

Q_SIGNALS:

public slots:
    void generateData(int type, int rowCount, int colCount);
    void update(QAbstractSeries *series);

private:
    QQuickView *m_appViewer;
    QList<QVector<QPointF> > m_data;
    int m_index;
};

#endif // DATASOURCE_H

datasource.cpp:

#include "datasource.h"
#include <QtCharts/QXYSeries>
#include <QtCharts/QAreaSeries>
#include <QtQuick/QQuickView>
#include <QtQuick/QQuickItem>
#include <QtCore/QDebug>
#include <QtCore/QtMath>

QT_CHARTS_USE_NAMESPACE

Q_DECLARE_METATYPE(QAbstractSeries *)
Q_DECLARE_METATYPE(QAbstractAxis *)

DataSource::DataSource(QQuickView *appViewer, QObject *parent) :
    QObject(parent),
    m_appViewer(appViewer),
    m_index(-1)
{
    qRegisterMetaType<QAbstractSeries*>();
    qRegisterMetaType<QAbstractAxis*>();

    generateData(0, 5, 1024);
}

void DataSource::update(QAbstractSeries *series)
{
    if (series) {
        QXYSeries *xySeries = static_cast<QXYSeries *>(series);
        m_index++;
        if (m_index > m_data.count() - 1)
            m_index = 0;

        QVector<QPointF> points = m_data.at(m_index);
        // Use replace instead of clear + append, it's optimized for performance
        xySeries->replace(points);
    }
}

void DataSource::generateData(int type, int rowCount, int colCount)
{
    // Remove previous data
    m_data.clear();

    // Append the new data depending on the type
    for (int i(0); i < rowCount; i++) {
        QVector<QPointF> points;
        points.reserve(colCount);
        for (int j(0); j < colCount; j++) {
            qreal x(0);
            qreal y(0);
            switch (type) {
            case 0:
                // data with sin + random component
                y = qSin(3.14159265358979 / 50 * j) + 0.5 + (qreal) rand() / (qreal) RAND_MAX;
                x = j;
                break;
            case 1:
                // linear data
                x = j;
                y = (qreal) i / 10;
                break;
            default:
                // unknown, do nothing
                break;
            }
            points.append(QPointF(x, y));
        }
        m_data.append(points);
    }
}

main.cpp中:

#include <QtWidgets/QApplication>
#include <QtQml/QQmlContext>
#include <QtQuick/QQuickView>
#include <QtQml/QQmlEngine>
#include <QtCore/QDir>
#include "datasource.h"

int main(int argc, char *argv[])
{
    // Qt Charts uses Qt Graphics View Framework for drawing, therefore 
QApplication must be used.
    QApplication app(argc, argv);

    QQuickView viewer;

    // The following are needed to make examples run without having to install the module
    // in desktop environments.
#ifdef Q_OS_WIN
    QString extraImportPath(QStringLiteral("%1/../../../../%2"));
#else
    QString extraImportPath(QStringLiteral("%1/../../../%2"));
#endif
    viewer.engine()->addImportPath(extraImportPath.arg(QGuiApplication::applicationDirPath(),
                                  QString::fromLatin1("qml")));
    //QObject::connect(viewer.engine(), &QQmlEngine::quit, &viewer, &QWindow::close);

    viewer.setTitle(QStringLiteral("QML Oscilloscope"));

    DataSource dataSource(&viewer);
    viewer.rootContext()->setContextProperty("dataSource", &dataSource);

    viewer.setSource(QUrl("qrc:/qml/qmloscilloscope/main.qml"));
    viewer.setResizeMode(QQuickView::SizeRootObjectToView);
    viewer.setColor(QColor("#404040"));
    viewer.show();

    return app.exec();
}

ScopeView.qml:

import QtQuick 2.0
import QtCharts 2.1

ChartView {
    id: chartView
    animationOptions: ChartView.NoAnimation
    theme: ChartView.ChartThemeDark
    property bool openGL: true
    property bool openGLSupported: true
    onOpenGLChanged: {
        if (openGLSupported) {
            series("signal 1").useOpenGL = openGL;
        }
    }
    Component.onCompleted: {
        if (!series("signal 1").useOpenGL) {
            openGLSupported = false
            openGL = false
        }
    }

    ValueAxis {
        id: axisY1
        min: -1
        max: 4
    }

    ValueAxis {
        id: axisX
        min: 0
        max: 1024
    }

    LineSeries {
        id: lineSeries1
        name: "signal 1"
        axisX: axisX
        axisY: axisY1
        useOpenGL: chartView.openGL
    }

    Timer {
        id: refreshTimer
        interval: 1 / 60 * 1000 // 60 Hz
        running: true
       repeat: true
        onTriggered: {
            dataSource.update(chartView.series(0));
        }
    }
}

我不想在QML中使用Timer,而是希望在c ++类中使用现有的Timeout将新数据推送到QML ChartView。我有两个问题:

  1. 如何为上面发布的QML示波器示例实现此目的?
  2. 最适合c ++数据的格式是什么?我正在考虑某种QVector;数据将是带矢量索引的整数或浮点数。

1 个答案:

答案 0 :(得分:3)

正如你在评论中所说,你需要传递一个系列,然后我们创建一个方法来接收系列并将其保存在C ++类的成员中,我们也创建一个QTimer,我们也这样做更新间隔:

<强> *的.h

public:
    Q_INVOKABLE void setSeries(QAbstractSeries *series);
    Q_INVOKABLE void setInterval(int interval);
    [...]
private:
    QXYSeries *mSeries;
    QTimer *timer;
    [...]

<强> *。CPP

void DataSource::setSeries(QAbstractSeries *series)
{
    if (series) {
        mSeries = static_cast<QXYSeries *>(series);
    }
}

然后我们删除update参数并使用mSeries:

DataSource::DataSource(QQuickView *appViewer, QObject *parent) :
    QObject(parent),
    m_appViewer(appViewer),
    m_index(-1)
{
    [...]
    timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this, &DataSource::update);
    timer->start(1 / 60 * 1000 );
}

void DataSource::update()
{
    if (mSeries) {
        m_index++;
        if (m_index > m_data.count() - 1)
            m_index = 0;

        QVector<QPointF> points = m_data.at(m_index);
        // Use replace instead of clear + append, it's optimized for performance
        mSeries->replace(points);
    }
}

void DataSource::setInterval(int interval)
{
    if(timer){
        if(timer->isActive())
            timer->stop();
        timer->start(interval);
    }
}

<强> *。QML

Component.onCompleted: {
    dataSource.setSeries(chartView.series(0));
    if (!series("signal 1").useOpenGL) {
        openGLSupported = false
        openGL = false
    }
}
[...]
function changeRefreshRate(rate) {
    dataSource.setInterval(1 / Number(rate) * 1000);
    //refreshTimer.interval = 1 / Number(rate) * 1000;
}

您可以在以下link中找到完整示例。