如何在 C++ 运行时更改 QML 对象的属性?
我想在运行时更改 QML 对象的文本.
I want to change the text of a QML Object during runtime.
我尝试如下,但文本只是保持空白.
I tried it as following, but the text just stays empty.
这是后端类:
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 实例并尝试访问类似的值
In the qml file, I include window.backend, create a new BackEnd instance and try to access the values like
BackEnd {
id: backend
}
Text {
...
text: backend.userFieldText
}
我这样注册课程.
qmlRegisterType<BackEnd>("window.backend", 0, 1, "BackEnd");
在我想更改对象的单独线程中,我创建了一个 BackEnd 类的实例并调用 setter 函数.
In a seperate thread where I would like to change the objects I create an instance of the BackEnd class and call the setter function.
BackEnd backend;
QString user("set by backend");
backend.setUserFieldText(user);
编译工作,它运行但不会改变任何东西.我已经尝试将它放在 QML 代码中的计时器中并每秒更新一次,但似乎没有任何效果.
Compilation works, it runs but does not change anything. I already tried putting it in a timer in the QML code and updating it every second but nothing seems to work.
推荐答案
你有以下错误:
正如您所指出的,您在一个线程中创建了一个
Backend
实例,并在 QML 中创建了另一个实例,因此修改一个实例的状态不会修改另一个实例.在这些情况下,如果您希望在 C++ 和 QML 中拥有一个对象,最好使用setContextProperty()
创建一个上下文属性.
As you point you have created an instance of
Backend
in one thread, and another instance in QML, so the modification of the state of one instance does not modify the other instance. In these cases where you want to have an object in C++ and QML it is better to create a context-property withsetContextProperty()
.
QML 只接受存在于主线程中的对象,因此无法在另一个线程中创建 Backend 对象,一种可能性是您创建另一个存在于辅助线程中的对象并将数据传输到主线程通过信号,另一种可能性是使用 QThread
接受信号的创建并将其连接到 Backend
对象.
QML only accepts objects that live in the main thread so the Backend object can not be created in another thread, one possibility is that you create another object that lives in the secondary thread and transmits the data to the main thread by signals, another possibility is to use QThread
that accepts the creation of signals and connect it to the Backend
object.
您要在 QML 中绑定的属性必须通过信号通知.
The properties that you want to do binding in QML must be notifiable through a signal.
综合以上,举个例子:
ma??in.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"
ma??in.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
}
}
相关文章