简体   繁体   中英

How to change property of QML item from c++

I am writing a small QT(5.12) application in C++, which will be moving center of QMap every second. I am trying to update the coordinates so the center will refresh, but after debugging it, it's always staying the same (original value). That's my first attempt with QML, so I am helping myself with the link bellow, but apparently I am not doing something right.

https://doc.qt.io/qt-5/qtqml-cppintegration-interactqmlfromcpp.html

Update function called every second by timer

#include <QQmlEngine>
#include <QQmlComponent>

void MainWindow::UpdateCoordinates()
{
    float LATDEGM = (60 * 1853.181);
    float DEG2RAD = (PI / 180.0);

    QString speedData = ui->sboxSpeed->text();
    bool ok;
    AirSpeed = speedData.toInt(&ok);
    AirCourse = (AirCourse + 360) % 360;

    Dx = AirSpeed * sin((float)AirCourse * DEG2RAD);
    Dy = AirSpeed * cos((float)AirCourse * DEG2RAD);

    QString dat = ui->txtLatitude->text();
    Lat = dat.toDouble();
    QString dat2 = ui->txtLongtitude->text();
    Lon = dat2.toDouble();

    Dx /= 3.6;
    Dy /= 3.6;

    Lat += Dy / LATDEGM;
    Lon += Dx / (LATDEGM * cos(Lat * DEG2RAD));

    ui->txtLatitude->setText(QString::number(Lat));
    ui->txtLongtitude->setText(QString::number(Lon));

    // Using QQmlComponent
    QQmlEngine engine;
    QQmlComponent component(&engine,QUrl(QStringLiteral("qrc:/Map.qml")));
    QObject *object = component.create();
    QObject *map = object->children().at(1);

    if (map)
    {
        map->setProperty("newLatitude", Lat);
        map->setProperty("newLongitude", Lon);
        std::cout << "Property value:" << map->property("latitude").toDouble() << std::endl;
        std::cout << "Property value:" << map->property("longitude").toDouble() << std::endl;
    }
}

Map.qml

import QtQuick 2.0
import QtQuick.Window 2.0
import QtLocation 5.6
import QtPositioning 5.6

Item{
    id: itemControl
    width: 512
    height: 512
    visible: true

    property alias newLongitude : map.longitude;
    property alias newLatitude : map.latitude;

    Plugin {
        id: mapPlugin
        name: "esri"
    }

    Map {
        id: map
        anchors.fill: parent
        maximumZoomLevel: 15
        minimumZoomLevel: 15
        width: 512
        height: 512
        plugin: mapPlugin
        center {
            property real latitude: 45.5082047
            property real longitude: 13.5757492
        }
        zoomLevel: 14
    }
}

By doing this:

    // Using QQuickView
    QQmlEngine engine;
    QQmlComponent component(&engine,QUrl(QStringLiteral("qrc:/Map.qml")));
    QObject *object = component.create();
    QObject *map = object->children().at(1);

You're creating a new local instance of you view. So, you don't modify your current view.

The easiest to send data to your view is to use signals/slots. Or, you can pass a pointer on your component to your MainWindow :

For example:

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    property int foobar: -1
    Label {
        text: foobar
    }
}
class Worker: public QObject
{
public:
    Worker(QObject* map): QObject(),
        map(map)
    {
        startTimer(500);
    }

    void timerEvent(QTimerEvent* ev)
    {
        static int i = 0;
        ++i;
        map->setProperty("foobar", i);
    }
private:
    QObject* map;
};

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QApplication app(argc, argv);
    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    QObject* obj = engine.rootObjects().first();

    Worker* worker = new Worker(obj);

    return app.exec();
}

An quick example with signals/slots (useful when the class Worker doesn't have to know the inner component):


ApplicationWindow {
    visible: true
    width: 640
    height: 480

    function update(value) {
        label.text = value;
    }

    Label {
        id: label
        text: "None"
    }
}
class Worker: public QObject
{
    Q_OBJECT
public:
    Worker(): QObject()
    {
        startTimer(500);
    }

    void timerEvent(QTimerEvent* ev)
    {
        static int i = 0;
        ++i;
        emit update(i);
    }

signals:
    void update(QVariant newValue);
};

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QApplication app(argc, argv);
    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    QObject* obj = engine.rootObjects().first();

    Worker* worker = new Worker();

    QObject::connect(worker, SIGNAL(update(QVariant)), obj, SLOT(update(QVariant)));
    return app.exec();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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