QT добавляет Map QML Items через C ++ - PullRequest
1 голос
/ 24 февраля 2020

Я пытаюсь добавить на карту такие элементы карты QML, как MapQuickItem или MapCircle из C ++. К сожалению, они не отображаются на карте. Тот же код с просто прямоугольником QML работает. rect v1 - это прямоугольник для тестирования, который работает. rect v2 - это mapCircle, который не работает. Когда я добавляю код QML своего круга 1: 1 в код QML своей карты, он работает нормально.

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();
        }
    }
}

1 Ответ

2 голосов
/ 25 февраля 2020

То, что установлено, что элемент является дочерним элементом карты, не означает, что он отображается на карте, если вы хотите добавить элемент, вы должны использовать метод addMapItem() и в C ++ вы можете использовать QMetaObject::invokeMethod() для вызова этого метода, но вам нужно получить доступ к типу QDeclarativeGeoMapItemBase, который принадлежит частному API Qt, учитывая, что приведенное выше решение:

*. 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();
}

Проблема предыдущего метода заключается в том, что он опасен поскольку карта или любой элемент QML могут быть удалены в любое время, что может вызвать проблему, кроме того, это ограничивает изменение QML и, наконец, необходимо получить доступ к частному API Qt, который может быть изменен без уведомления. Поэтому я предложу лучшие альтернативы:

  • Используйте QObject и экспортируйте его в QML, где элементы создаются и добавляются на карту:

    #include <QGuiApplication>
    #include <QQuickView>
    #include <QGeoCoordinate>
    #include <QQmlContext>
    
    class Helper: public QObject{
        Q_OBJECT
    public:
        void addCircle(const QGeoCoordinate & coordinate){
            Q_EMIT circleSignal(coordinate);
        }
    Q_SIGNALS:
        void circleSignal(const QGeoCoordinate & coordinate);
    };
    
    int main(int argc, char *argv[]){
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
        QGuiApplication app(argc, argv);
        QQuickView view;
        Helper helper;
        view.rootContext()->setContextProperty("helper", &helper);
        view.setSource(QUrl("qrc:/map.qml"));
        view.resize(1000, 650);
        view.setTitle("GUI");
        view.show();
        helper.addCircle(QGeoCoordinate(47.6, 9.5));
        return app.exec();
    }
    
    #include "main.moc"
    
    import QtQuick 2.14
    import QtPositioning 5.14
    import QtLocation 5.14
    
    Map{
        id: map_map
        anchors.centerIn: parent;
        anchors.fill: parent
        plugin: Plugin {
            name: "mapboxgl" // "osm", "esri", ...
        }
        center: QtPositioning.coordinate(47.6,9.5)
        zoomLevel: 8
        Connections{
            target: helper
            onCircleSignal: {
                var component = Qt.createComponent("rect.qml");
                if (component.status === Component.Ready){
                    var o = component.createObject(map_map);
                    o.center = coordinate
                    map_map.addMapItem(o)
                }
            }
        }
    }
    

    или

    import QtQuick 2.14
    import QtPositioning 5.14
    import QtLocation 5.14
    
    Map{
        id: map_map
        anchors.centerIn: parent;
        anchors.fill: parent
        plugin: Plugin {
            name: "mapboxgl" // "osm", "esri", ...
        }
        center: QtPositioning.coordinate(47.6,9.5)
        zoomLevel: 8
    
        Component{
            id: provider
            MapCircle{
                center{
                    latitude: 47.6
                    longitude: 9.5
                }
                radius: 5000.0
                color: 'green'
                border.width: 3
            }
        }
        function createCirle(map, position){
            var o  = provider.createObject(map)
            o.center = position
            map.addMapItem(o)
            return o
        }
    
        Connections{
            target: helper
            onCircleSignal: {
                var o = createCirle(map_map, coordinate)
            }
        }
    }
    
  • Использование модели с MapItemView:

    #include <QGuiApplication>
    #include <QQuickView>
    #include <QGeoCoordinate>
    #include <QQmlContext>
    #include <QStandardItemModel>
    
    int CoordinateRole = Qt::UserRole + 1000;
    
    int main(int argc, char *argv[]){
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
        QGuiApplication app(argc, argv);
        QQuickView view;
        QStandardItemModel model;
        QHash<int, QByteArray> roles;
        roles[CoordinateRole] = QByteArray("coordinate");
        model.setItemRoleNames(roles);
        view.rootContext()->setContextProperty("circle_model", &model);
        view.setSource(QUrl("qrc:/map.qml"));
        view.resize(1000, 650);
        view.setTitle("GUI");
        view.show();
    
        QStandardItem *item = new QStandardItem;
        item->setData(QVariant::fromValue(QGeoCoordinate(47.6, 9.5)), CoordinateRole);
        model.appendRow(item);
    
        return app.exec();
    }
    
    import QtQuick 2.14
    import QtPositioning 5.14
    import QtLocation 5.14
    
    Map{
        id: map_map
        anchors.centerIn: parent;
        anchors.fill: parent
        plugin: Plugin {
            name: "mapboxgl" // "osm", "esri", ...
        }
        center: QtPositioning.coordinate(47.6,9.5)
        zoomLevel: 8
    
        MapItemView{
            model: circle_model
            delegate: MapCircle{
                center: model.coordinate
                radius: 5000.0
                color: 'green'
                border.width: 3
            }
        }
    }
    
...