Как изменить свойства объекта QML во время выполнения в C ++? - PullRequest
0 голосов
/ 15 января 2019

Я хочу изменить текст объекта QML во время выполнения.

Я попробовал это следующим образом, но текст остается пустым.

Это класс BackEnd:

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 и пытаюсь получить доступ к таким значениям, как

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 и обновлять его каждую секунду, но, похоже, ничего не работает.

1 Ответ

0 голосов
/ 15 января 2019

У вас есть следующие ошибки:

  • Как вы указали, вы создали экземпляр Backend в одном потоке и другой экземпляр в QML, поэтому изменение состояния одного экземпляра не изменяет другой экземпляр. В этих случаях, когда вы хотите иметь объект в C ++ и QML, лучше создать свойство контекста с setContextProperty().

  • QML принимает только объекты, которые находятся в главном потоке, поэтому объект Backend не может быть создан в другом потоке, возможно, вы создадите другой объект, который живет во вторичном потоке и передаст данные в основной поток по сигналам другая возможность заключается в использовании 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
    }
}
...