如何在C++运行时更改QML对象的属性

How to change properties of a QML Object during runtime in C++?

本文关键字:QML 对象 属性 C++ 运行时      更新时间:2023-10-16

我想在运行时更改QML对象的文本。

我按如下所示进行了尝试,但文本始终为空。

这是后端类:

class BackEnd : public QObject {
Q_OBJECT
Q_PROPERTY(QString userFieldText READ userFieldText WRITE setUserFieldText)
public:
explicit BackEnd(QObject *parent = nullptr);
QString userFieldText();
void setUserFieldText(QString &username);
private:
QString _userFieldText;
};

在qml文件中,我包括window.backend,创建一个新的后端实例,并尝试访问等值

BackEnd {
id: backend
}
Text {
...
text: backend.userFieldText
}

我是这样注册的。

qmlRegisterType<BackEnd>("window.backend", 0, 1, "BackEnd");

在一个我想更改对象的单独线程中,我创建了一个BackEnd类的实例并调用setter函数。

BackEnd backend;
QString user("set by backend");
backend.setUserFieldText(user);

编译工作,它运行,但不会改变任何东西。我已经试着把它放在QML代码中的计时器中,并每秒更新一次,但似乎什么都不起作用。

您有以下错误:

  • 正如您所指出的,您已经在一个线程中创建了Backend的实例,并在QML中创建了另一个实例,因此对一个实例的状态的修改不会修改其他实例。在这些情况下,如果您希望在C++和QML中有一个对象,最好使用setContextProperty()创建一个上下文属性。

  • QML只接受存在于主线程中的对象,因此后端对象不能在另一个线程中创建,一种可能性是您创建了另一个存在于次线程中并通过信号将数据传输到主线程的对象,另一种可能是使用接受信号创建的QThread并将其连接到Backend对象。

  • 要在QML中进行绑定的属性必须通过信号进行通知。

考虑到以上情况,示例如下:

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QThread>
class BackEnd : public QObject {
Q_OBJECT
Q_PROPERTY(QString userFieldText READ userFieldText WRITE setUserFieldText NOTIFY userFieldTextChanged)
public:
explicit BackEnd(QObject *parent = nullptr):
QObject(parent){}
QString userFieldText() const {
return _userFieldText;
}
void setUserFieldText(const QString &username){
if(userFieldText() == username) return;
_userFieldText = username;
emit userFieldTextChanged();
}
signals:
void userFieldTextChanged();
private:
QString _userFieldText;
};
class WorkerThread: public QThread
{
Q_OBJECT
public:
using QThread::QThread;
~WorkerThread() override {
requestInterruption();
quit();
wait();
}
signals:
void textChanged(const QString &);
protected:
void run() override{
while (!isInterruptionRequested()) {
emit textChanged(QString("set by backend: %1 ").arg(counter));
QThread::msleep(100);
counter++;
}
}
private:
int counter = 0;
};
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
BackEnd backend;
WorkerThread thread;
QObject::connect(&thread, &WorkerThread::textChanged, &backend, &BackEnd::setUserFieldText);
thread.start();
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("backend", &backend);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
#include "main.moc"

main.qml

import QtQuick 2.9
import QtQuick.Window 2.2
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Text {
anchors.centerIn: parent
text: backend.userFieldText
}
}