我有一个名为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)。
我不知道的是如何让所有的东西都相互作用。我也不确定是否还有其他需要实现的东西。不过,我确信有很多事情我没有看到。我已经阅读了文档,但我只能理解我目前所处的位置。
我将感谢任何人可以为我提供的帮助和示例代码。非常感谢。
QThread
是一个在低级别管理线程的类,更好的选择是使用QThreadPool
和QRunnable
。
QRunnable是一个类,它有一个将在某个线程上运行的方法,该类将传递一个Data类型的对象,并使用invokeMethod通过setter更新数据。
可运行.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
C++与QML交互的一种方式是通过Q_PROPERTY
,因此在这种情况下会使用它,在类中,当从QML调用start()
方法时,我们将执行Runnable
,为此我们将使用Q_INVOKABLE
。
数据.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
}
}
该示例可在以下链接中找到。