如何将不断更新的c ++数据显示为QML?

时间:2017-11-06 00:05:10

标签: c++ qt qml qt5

我有一个名为Data的类,这个类有一个带有从设备读取数据的循环的函数。循环永远不会停止读取数据。

为了这个例子,我们可以说类Data有以下代码:

class Data : public QObject
{
    Q_OBJECT

public:
    explicit Data(QObject *parent = nullptr){
        genData();
    }

    //the job of this function is to always get data
    void genData(){            
       while(true){
         m_number++;
    //somehow keep updating the value in QML and keep doing it?
       }    
    }

private:
    int m_number = 0;
};

所以,我需要做的是能够在main.qml中显示m_number,并在每次C ++更改时更新QML UI中的值。在这种情况下,循环正在递增m_number的值。

我有一些想法,我必须做些什么来完成这项工作,但我并不积极。 1.我知道我必须在不同的线程中运行该函数,以便它不会阻止程序的其余部分,并且我能够实现这一点。 2.我知道我必须实现Q_PROPERTY并且我也能够实现它,但它只显示Data :: m_number中的第一个值(初始值为0)。

我不知道的是如何使一切互动。我也不确定是否还需要实施其他任何东西。不过,我确信有很多东西我没有看到。我已经阅读了文档,但我只能理解我目前所处的观点。

我很感激任何人都可以提供的帮助和示例代码。谢谢。

1 个答案:

答案 0 :(得分:3)

QThread是一个管理低级别线程的类,更好的选择是使用QThreadPoolQRunnable

QRunnable是一个具有将在某个线程上运行的方法的类,该类将传递Data类型的对象,并使用invokeMethod通过setter更新数据。

<强> runnable.h

#ifndef RUNNABLE_H
#define RUNNABLE_H

#include <QObject>
#include <QRunnable>
#include <QThread>

class Runnable : public QRunnable
{
    int mNumber = 0;
    QObject *mReceiver;
    bool mRunning;
public:
    Runnable(QObject *receiver){
        mReceiver = receiver;
        mRunning = false;
    }
    void run(){
        mRunning = true;
        while(mRunning){
            mNumber++;
            QMetaObject::invokeMethod(mReceiver, "setNumber",
                                      Qt::QueuedConnection,
                                      Q_ARG(int, mNumber));
            QThread::msleep(10);
        }
    }
    bool isRunning() const{
        return mRunning;
    }
    void stop(){
        mRunning = false;
    }
};

#endif // RUNNABLE_H

使用QML交互C ++的一种方法是通过Q_PROPERTY,因此在这种情况下将使用它,在Runnable方法中我们将执行start()的类从QML调用,为此我们将使用Q_INVOKABLE

<强> data.h

#ifndef DATA_H
#define DATA_H

#include "runnable.h"

#include <QObject>
#include <QThreadPool>

class Data : public QObject
{
    Q_OBJECT
    Q_PROPERTY(int number READ number WRITE setNumber NOTIFY numberChanged)
public:
    explicit Data(QObject *parent = nullptr):QObject(parent){
        m_number = 0;
        runnable = new Runnable(this);
    }
    ~Data(){
        runnable->stop();
    }
    Q_INVOKABLE void start(){
        if(!runnable->isRunning())
            QThreadPool::globalInstance()->start(runnable);
    }
    int number() const{
        return m_number;
    }
public slots:
    void setNumber(int number){
        if(number == m_number)
            return;
        m_number = number;
        emit numberChanged(m_number);
    }
signals:
    void numberChanged(int);
private:
    int m_number;
    Runnable *runnable;
};

#endif // DATA_H

然后该类在main中注册,然后我们创建一个将建立连接的项目

<强>的main.cpp

#include "data.h"

#include <QGuiApplication>
#include <QQmlApplicationEngine>

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

    qmlRegisterType<Data>("com.example.data", 1, 0, "Data");

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

    return app.exec();
}

<强> main.qml

import QtQuick 2.6
import QtQuick.Window 2.2
import QtQuick.Layouts 1.3
import QtQuick.Controls 1.4

import com.example.data 1.0

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Example")

    ColumnLayout {
        anchors.centerIn: parent
        Button {
            id: button
            Layout.fillWidth: true
            text: "start"
            onClicked: data.start()
        }

        Text {
            id: text1
            text: data.number
            horizontalAlignment: Text.AlignHCenter
            Layout.fillWidth: true
        }
    }

    Data{
        id: data
    }
}

该示例可在以下link中找到。