Search code examples
c++qtqmlopenstreetmap

Qt control OSM location from C++


In my Qt5.9 widget application project (Windows), I added a QQuickWidget in the ui and set the source file to a QML file.

My itention is to display open street maps in the QQuickWidget. By clicking a button, the center location of the map should change to specific lat/long coordinates.

The map gets displayed in the QQuickWidget as expected, however, I can't get the location change by button click to work.

I am using this QML file content to display the map:

//================================
// map.qml
//================================
import QtQuick 2.0
import QtQuick.Window 2.0
import QtLocation 5.6
import QtPositioning 5.6

Item {
    id: qmlMap

    Plugin {
        id: osmPlugin
        name: "osm"
    }

    Map {
        id: map
        anchors.fill: parent
        plugin: osmPlugin
        center: QtPositioning.coordinate(59.91, 10.75)
        zoomLevel: 10
        objectName: "mainMap"

    MapQuickItem {
      id: marker
      coordinate {latitude: 59.91
                 longitude: 10.75}
      anchorPoint.x: image.width * 0.5
      anchorPoint.y: image.height

      sourceItem: Image {
         id: image
         height: 35
         width: 35
         source: "geotag.png"
      }
            function recenter(lat,lng) {
                  map.clearMapItems();
                  marker.coordinate.latitude = lat;
                  marker.coordinate.longitude = lng;
                  map.addMapItem(marker);
                  map.center.latitude = lat;
                  map.center.longitude = lng;
                  map.update();
            }
    }
    }
}

On application start up, I can see the OSM centered on my specified location and I also can see the marker at the right location.

Loaded map on start up

However, when I click my button to call the function recenter(lat,lng) from C++, nothing seems to happen (no location change on map visible).

My C++ button code for location change is:

void mapproject::on_btnUpdatePos_clicked()
{
    QQmlEngine engine;
    QQmlComponent component(&engine, "qrc:/map.qml");
    QObject *object = component.create();

    QVariant returnedValue;
    QVariant pos = QVariant(0);

    if(object != NULL){
       QMetaObject::invokeMethod(object, "recenter",
       Q_RETURN_ARG(QVariant, returnedValue),
       Q_ARG(QVariant, pos),
       Q_ARG(QVariant, pos));
    }
}

Why does the location change not work? Is there a mistake in my QML file or in my C++ code?


Solution

  • Assuming that the QQuickWidget has been added through Qt Designer and it is called quickWidget, so you can access it using ui->quickWidget.

    To do a simple search you can set an objectName in the MapQuickItem:

    MapQuickItem {
        id: marker
        objectName: "mapItem"
        coordinate {latitude: 59.91
        [...]
    

    You should not create a new component, you should use the QQuickWidget, the first thing is to get the item that shows the QQuickWidget through the rootObject() method, then look for the child named mapItem and invoke the recenter method:

    void MainWindow::on_btnUpdatePos_clicked()
    {
        QQuickItem *item = ui->quickWidget->rootObject();
        QObject *object = item->findChild<QObject*>("mapItem");
        QVariant posx = QVariant(-12.0464);
        QVariant posy = QVariant(-77.0428);
    
        if(object != NULL){
            QMetaObject::invokeMethod(object, "recenter",
                                      Q_ARG(QVariant, posx),
                                      Q_ARG(QVariant, posy));
        }
    }
    

    The complete example can be found in the following link