c++qtqmlqtlocation

QT add Map QML Items via C++


I try to add QML map items like MapQuickItem or MapCircle from C++ to my map. Unfortunately, they don't show up on the map. The same code with just a QML rectangle works. rect v1 is the rectangle for testing which works. rect v2 is the mapCircle which doesn't work. When I add my circle QML code 1:1 into my map QML code it works fine.

main.cpp:

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    QQuickView *view = new QQuickView;
    view->setSource(QUrl("qrc:/map.qml"));

    QQmlComponent compRect (view->engine(), QUrl("qrc:/rect.qml"));

    view->setWidth(1000);
    view->setHeight(650);
    view->setTitle("GUI");


    QQuickItem *map = view->findChild<QQuickItem*>("map1");

    QQuickItem *rect = qobject_cast<QQuickItem*>(compRect.create(view->rootContext()));

    rect->setParentItem(map);
    rect->setParent(map); //know this is not for visual objects, just for test

    view->show();
    return app.exec();
}

rect.qml v1

import QtQuick 2.14
import QtLocation 5.14
import QtPositioning 5.14

Rectangle
{
        color: "grey"
        opacity: .8

        width: 100
        height: 100
        radius: 4
        Text
        {
            id: text
            anchors.centerIn: parent
            text: "hi"
            color: "orangered"
            font.weight: Font.Bold
        }
}

rect.qml v2

import QtQuick 2.14
import QtLocation 5.14
import QtPositioning 5.14

MapCircle 
{
    center 
    {
        latitude: 47.5
        longitude: 8.9
    }
    radius: 5000.0
    color: 'green'
    border.width: 3
}

map.qml

import QtQuick 2.12
import QtQuick.Window 2.12
import QtPositioning 5.14
import QtLocation 5.14

Map
{
    objectName: "map1"
    id: map_map
    anchors.centerIn: parent;
    anchors.fill: parent
    plugin: Plugin
    {
        name: "mapboxgl" // "osm", "esri", ...
    }
    center: QtPositioning.coordinate(47.6,9.5)
    zoomLevel: 8

    // get position of device and set map center to it
    PositionSource
    {
        active: true
        onPositionChanged:
        {
            map.center(position.coordinate)
            console.log(position.coordinate)
        }
    }

    Timer
    {
        id: timerReload
        interval: 1000
        repeat: true
        running: true

        onTriggered:
        {
            controller.triggerReload();
        }
    }
}

Solution

  • That it is established that an item is a child of the map does not imply that it is shown on the map, if you want to add an item you must use the addMapItem() method and in C++ you can use QMetaObject::invokeMethod() to invoke that method but you need to access the type QDeclarativeGeoMapItemBase that belongs to the private Qt API, considering the above the solution is:

    *.pro

    QT += quick location location-private
    CONFIG += c++11
    DEFINES += QT_DEPRECATED_WARNINGS
    SOURCES += main.cpp
    RESOURCES += qml.qrc
    

    main.cpp

    #include <QGuiApplication>
    #include <QQuickItem>
    #include <QQuickView>
    
    #include <QtLocation/private/qdeclarativegeomapitembase_p.h>
    
    int main(int argc, char *argv[]){
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
        QGuiApplication app(argc, argv);
        QQuickView view;
        view.setSource(QUrl("qrc:/map.qml"));
        view.resize(1000, 650);
        view.setTitle("GUI");
        view.show();
        if(QQuickItem *map = view.findChild<QQuickItem*>("map1")){
            QQmlComponent component(view.engine(), QUrl("qrc:/rect.qml"));
            if(QDeclarativeGeoMapItemBase *rect = qobject_cast<QDeclarativeGeoMapItemBase*>(component.create(view.rootContext()))){
                bool status = QMetaObject::invokeMethod(map,
                                          "addMapItem",
                                          Qt::DirectConnection,
                                          Q_ARG(QDeclarativeGeoMapItemBase*, rect));
                Q_ASSERT(status);
            }
        }
        return app.exec();
    }
    

    The problem with the previous method is that it is dangerous since the map or any QML element can be removed at any time so that it could generate a problem, in addition it limits the modification of QML and finally it is necessary to access the private Qt API That can change without notice. Therefore I will offer better alternatives: