简体   繁体   English

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

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

I want to change the text of a QML Object during runtime.我想在运行时更改 QML 对象的文本。

I tried it as following, but the text just stays empty.我尝试如下,但文本只是保持空白。

This is the BackEnd class:这是后端类:

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;
};

In the qml file, I include window.backend, create a new BackEnd instance and try to access the values like在 qml 文件中,我包含 window.backend,创建一个新的 BackEnd 实例并尝试访问类似的值

BackEnd {
 id: backend
}

Text {
 ...
 text: backend.userFieldText
}

I register the class like that.我就这样注册了课程。

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

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 类的实例并调用了 setter 函数。

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

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.我已经尝试将它放入 QML 代码中的计时器中并每秒更新一次,但似乎没有任何效果。

You have the following errors:您有以下错误:

  • 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.正如您指出的那样,您已经在一个线程中创建了一个Backend实例,并在 QML 中创建了另一个实例,因此修改一个实例的状态不会修改另一个实例。 In these cases where you want to have an object in C++ and QML it is better to create a context-property with setContextProperty() .在这些情况下,您希望在 C++ 和 QML 中拥有对象,最好使用setContextProperty()创建上下文属性。

  • 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 只接受存在于主线程中的对象,因此无法在另一个线程中创建 Backend 对象,一种可能性是您创建另一个存在于辅助线程中的对象并通过信号将数据传输到主线程,另一种可能性是使用接受信号创建的QThread并将其连接到Backend对象。

  • The properties that you want to do binding in QML must be notifiable through a signal.您想要在 QML 中进行绑定的属性必须通过信号通知。

Considering the above, an example is the following:考虑到上述情况,示例如下:

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
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM