Nano Hash - криптовалюты, майнинг, программирование

Подключиться к QML Chart из c ++

У меня есть класс C ++, который собирает данные (в настоящее время это просто случайные числа, генерируемые между верхним и нижним порогами) и упаковывает их в QVector (QPointF). У меня есть файл QML, который включает ChartView. Я хотел бы построить график собранных данных c ++ в моем QML ChartView (LineSeries) и обновлять график каждый раз, когда функция сбора данных в c ++ завершается. Я хотел бы отправить собранный QVector второстепенному классу C ++ для выполнения обновления QML ChartView.

Ниже приведены выдержки из различных файлов, имеющих отношение к делу.

data.h:

#ifndef DATA_H
#define DATA_H

#include <QObject>
#include <QTimer>
#include <QtCore/QObject>

#include <QAbstractSeries>
#include <QXYSeries>

class Data : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QVector<int> wVector READ wVector NOTIFY wVectorChanged)

public:
    Data();

    Q_PROPERTY(float wValue READ wValue NOTIFY wValueChanged)
    float wValue(){return this->m_wValue;}

    QVector<int> wVector(){return m_wVector;}

signals:
    void wValueChanged();
    void wVectorChanged();

private slots:
    void wTimeout();

public slots:

private:
    float    m_wValue;
    QTimer * m_wTimer;

    QVector<int> m_wVector;
    QList<QVector<QPointF> > m_data;

};

#endif // DATAD_H

data.cpp:

#include "data.h"
#include "chart.h"
#include <QDebug>
#include <iostream>
#include <QTimer>
#include <QtCharts/QXYSeries>
#include <QtCharts/QAreaSeries>
#include <QtQuick/QQuickView>
#include <QtQuick/QQuickItem>
#include <QtMath>

Data::Data()

{
    this->m_wTimer = new QTimer(this);
    this->m_wTimer->setInterval((1000 / 5));
    connect(this->m_wTimer, &QTimer::timeout, this, &Data::wTimeout);
    this->m_wTimer->start();
}

void Data::wTimeout()
{
    int HIGH = 100;
    int LOW = 0;
    this->m_wValue = rand() % (HIGH - LOW + 1) + LOW;

    if (m_wVector.size() >= 5 && !m_wVector.isEmpty())
        m_wVector.removeFirst();

    this->m_wVector.append(m_wValue);
    m_data.clear();

    QVector<QPointF> dataStore;

    for (int i(0); i < m_wVector.size(); i++) {
        dataStore.append(QPointF(i+1, m_wVector[i]));
    }

    m_data.append(dataStore);

    emit wValueChanged();
    //SEND m_data to Chart.update() here??
}

chart.h:

#ifndef CHART_H
#define CHART_H

#include <QtCore/QObject>
#include <QtCharts/QAbstractSeries>
#include <QXYSeries>
class QTimer;

QT_CHARTS_USE_NAMESPACE

class Chart : public QObject
{
    Q_OBJECT
public:
    ConfigurationChart();

    Q_INVOKABLE void setSeries(QAbstractSeries *series);

public slots:
    void update();

private:
    QList<QVector<QPointF> > m_data;
    int m_index;
    QXYSeries *mSeries;
    QTimer *timer;
};

#endif // CHART_H

chart.cpp:

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

QT_CHARTS_USE_NAMESPACE

Q_DECLARE_METATYPE(QAbstractSeries *)
Q_DECLARE_METATYPE(QAbstractAxis *)

Chart::Chart()
{
    qRegisterMetaType<QAbstractSeries*>();
    qRegisterMetaType<QAbstractAxis*>();

}

void Chart::update()//Need to pass the m_data QList<QVector<QPointF>> parameter here??
{
    if (mSeries) {
        m_index++;
        if (m_index > m_data.count() - 1)
            m_index = 0;

        QVector<QPointF> points = m_data.at(m_index);
        mSeries->replace(points);
    }
}

void Chart::setSeries(QAbstractSeries *series)
{
    //I don't know how this is called, nor how this actually establishes a link to the QML chart??
    if (series) {
        mSeries = static_cast<QXYSeries *>(series);
    }
}

main.cpp:

#include <QApplication>
#include <QQmlApplicationEngine>
#include <QQmlEngine>
#include <QQmlContext>
#include <QQuickItem>
#include <thread>
#include <chrono>
#include <QDebug>
#include <time.h>
#include <iostream>
#include <typeinfo>
#include <QtCharts>
#include <QtQuick/QQuickView>

#include "data.h"
#include "hart.h"

using namespace std;
using namespace QtCharts;

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QQmlApplicationEngine engine;

    engine.rootContext()->setContextProperty(QStringLiteral("Data"), new Data());
    engine.rootContext()->setContextProperty(QStringLiteral("Chart"), new Chart());

    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

main.qml:

import QtQuick 2.8
...
import QtCharts 2.2

//I've removed unnecessary QML elements for simplicity

ChartView {
    id: chartView
    width: parent.width
    height: parent.height
    anchors.fill: parent
    margins.bottom: 0
    margins.top: 0
    margins.left: 0
    margins.right: 0
    animationOptions: ChartView.NoAnimation
    antialiasing: true
    legend.visible: false
    backgroundColor: "#1f1f1f"

    ValueAxis {
        id: axisY1
        min: 0
        max: 100
        gridVisible: false
        color: "#ffffff"
        labelsColor: "#ffffff"
        labelFormat: "%.0f"
    }

    ValueAxis {
        id: axisX
        min: 0
        max: 50
        gridVisible: false
        color: "#ffffff"
        labelsColor: "#ffffff"
        labelFormat: "%.0f"
        tickCount: 5
    }

    LineSeries {
        id: lineSeries1
        name: "signal 1"
        color: "white"
        axisX: axisX
        axisY: axisY1
    }
}

Мой вопрос: как подключить chart.cpp к QML LineSeries для построения графика данных chart.cpp (полученных из data.cpp) в QML ChartView?

Я использую Qt5.9.2.

10.12.2017

  • В чем разница с вашим предыдущим вопросом? 10.12.2017
  • Привет @eyllanesc! Ваш предыдущий пост очень помог, но он использовал QQuickView в файле main.cpp, который не соответствует моему существующему макету приложения. Как видите, я создал QPointF QVector, как вы вчера рекомендовали / подтвердили, и хотел бы отправить его на внешний .cpp (chart.cpp) и подключить этот файл к QML, что значительно отличается от QQuickView в примере с осциллографом. 10.12.2017
  • Я думаю, что класс Chart не нужен, вы можете напрямую отправлять и обновлять данные. QQuickView не имеет отношения к проблеме. 10.12.2017
  • Если бы у меня была функция в классе data.cpp для непосредственного обновления диаграммы, я бы с радостью это сделал. Я просто не понимаю компонент mSeries QXYSeries ваших файлов осциллографа; Я не вижу, где установлено соединение с QML LineSeries. 10.12.2017
  • Когда вы используете setSeries, вы передаете указатель на первую серию из QML: dataSource.setSeries(chartView.series(0)); 10.12.2017
  • Ооо, я вижу! Я обрезал большую часть файла QML ScopeView, чтобы попытаться упростить его, и случайно удалил этот указатель. Думаю, теперь я понимаю, как заставить это работать. 10.12.2017
  • Для чего вы используете wValue? 10.12.2017
  • Я обновляю некоторые элементы графического интерфейса в QML с помощью wValue. 10.12.2017
  • А зачем тогда использовать m_wVector? Вам не кажется, что вы лишний? 10.12.2017
  • Это вполне может быть так. mValue содержит единственный вывод с плавающей запятой, тогда как m_wVector является сборщиком 5 последних значений, которые затем добавляются к m_data для обновления диаграммы. Я определенно мог бы использовать m_wVector для обоих и, например, обновить элементы графического интерфейса QML с помощью m_wVector [0]. 10.12.2017

Ответы:


1

Нет необходимости использовать серию из C ++ (я думаю, что класс диаграммы не нужен), данные можно обновлять напрямую, как показано ниже:

data.h

#ifndef DATA_H
#define DATA_H

#include <QObject>
#include <QPointF>
#include <QTimer>

class Data : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QPointF wValue READ wValue NOTIFY wValueChanged)

public:
    Data(QObject *parent=Q_NULLPTR);
    QPointF wValue() const{
        return m_wValue;
    }
signals:
    void wValueChanged();
private slots:
    void wTimeout();
private:
    QTimer * m_wTimer;
    QPointF m_wValue;
};

#endif // DATA_H

data.cpp

#include "data.h"

void Data::wTimeout(){
    int HIGH = 100;
    int LOW = 0;
    int val = rand() % (HIGH - LOW + 1) + LOW;
    m_wValue.setX(m_wValue.x()+1);
    m_wValue.setY(val);
    emit wValueChanged();
}

Data::Data(QObject *parent):QObject(parent){
    m_wTimer = new QTimer(this);
    m_wTimer->setInterval((1000 / 5));
    connect(m_wTimer, &QTimer::timeout, this, &Data::wTimeout);
    m_wTimer->start();
}

main.cpp

#include "data.h"

#include <QApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>

int main(int argc, char *argv[])
{

    QApplication app(argc, argv);

    QQmlApplicationEngine engine;
    engine.rootContext()->setContextProperty("dataFromCpp", new Data());
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

main.qml

import QtQuick 2.8
import QtCharts 2.2
import QtQuick.Window 2.2

Window{
    visible: true
    width: 640
    height: 480

    Connections {
        target: dataFromCpp
        onWValueChanged: {
            if(lineSeries1.count > 5)
                lineSeries1.remove(0);
            lineSeries1.append(dataFromCpp.wValue.x, dataFromCpp.wValue.y)
            axisX.min = lineSeries1.at(0).x
            axisX.max = lineSeries1.at(lineSeries1.count-1).x
        }
    }

    ChartView {
        id: chartView
        width: parent.width
        height: parent.height
        anchors.fill: parent
        animationOptions: ChartView.NoAnimation
        antialiasing: true
        backgroundColor: "#1f1f1f"

        ValueAxis {
            id: axisY1
            min: 0
            max: 100
            gridVisible: false
            color: "#ffffff"
            labelsColor: "#ffffff"
            labelFormat: "%.0f"
        }

        ValueAxis {
            id: axisX
            min: 0
            max: 50
            gridVisible: false
            color: "#ffffff"
            labelsColor: "#ffffff"
            labelFormat: "%.0f"
            tickCount: 5
        }

        LineSeries {
            id: lineSeries1
            name: "signal 1"
            color: "white"
            axisX: axisX
            axisY: axisY1
        }
    }
}

Полный пример можно найти по следующей ссылке.

10.12.2017
  • Как можно изменить приведенное выше, чтобы оно содержало логику (m_wTimer и wTimeout) в файле data.cpp, а не в самом файле заголовка? Мне удобно удалять файлы chart.cpp / h, но я бы предпочел по возможности оставить логику вне файла заголовка. 10.12.2017
  • Просто переместите код в .cpp, я это уже сделал, теперь не забудьте отметить мой ответ как правильный. 10.12.2017
  • @eyllensc из интереса, могу ли я использовать описанный вами выше подход с QXYSeries на c ++, чтобы затем заменить () весь набор данных диаграммы, а не добавлять каждое инкрементное изменение? Замечу, что QML LineSeries не предоставляет средств для замены или добавления QVector / QList, это возможно только из c ++. 11.12.2017
  • Хорошо, отлично, спасибо за подтверждение. В этом случае я собираюсь работать над второй версией вашего кода, чтобы обеспечить построение целых векторов / списков, а не отдельных точек, так как я могу сделать такой уровень гибкости весьма полезным. 11.12.2017
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..