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

时间:2019-01-14 21:44:44

标签: c++ qt qml qt5

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

我尝试了以下操作,但文本仍然为空。

这是BackEnd类:

//Did update method
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    let location = locations[locations.count - 1]
    if location.horizontalAccuracy > 0 {
    self.locationManager.stopUpdatingLocation()

        print("latitude = \(location.coordinate.latitude), longitude = \(location.coordinate.longitude)")

        let latitude = String(location.coordinate.latitude)
        let longitude = String(location.coordinate.longitude)

        getWindData(url: base_URL, key: api_Key, latitude: latitude, longitude: longitude)

    }
}


//Did fail with error method
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
    print(error)
    yard.text = "Error"
}

在qml文件中,我包含window.backend,创建一个新的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;
};

我这样注册课程。

BackEnd {
 id: backend
}

Text {
 ...
 text: backend.userFieldText
}

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

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

编译有效,它可以运行,但不会改变任何内容。 我已经尝试过将其放入QML代码的计时器中,并每秒进行更新,但似乎无济于事。

1 个答案:

答案 0 :(得分:0)

您遇到以下错误:

  • 正如您所指出的,您已经在一个线程中创建了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
    }
}