从C 推动QML ChartView更新

Push QML ChartView updates from c++

本文关键字:ChartView 更新 QML 推动      更新时间:2023-10-16

我正在尝试调整QT5.9 QML示波器示例,以将图形数据从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中使用计时器,而是想在C 类中使用现有的超时将新数据推向QML ChartView。我有两个问题:

  1. 我将如何实现上面发布的QML示波器示例?
  2. 哪种格式最适合C 数据来促进这一点?我在想某种QVECTOR;数据将是带有向量索引的整数或浮动。

正如您在评论中所说的,您需要通过一个系列,然后我们创建一种接收该系列并将其保存在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);
    }
}

然后我们删除更新参数并使用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;
}

您可以在以下链接中找到完整的示例。