如何在 C++ 运行时更改 QML 对象的属性? [英] How to change properties of a QML Object during runtime in C++?

查看:30
本文介绍了如何在 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 with setContextProperty().

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

这篇关于如何在 C++ 运行时更改 QML 对象的属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆