В QML (как) я могу сделать MapItemGroup как компонент делегата MapItemView?

Ситуация: я могу использовать элемент карты QML с моделью / видом / делегатом. Я умею работать с отдельными предметами.

Проблема: в качестве следующего шага я хотел бы иметь возможность рисовать несколько элементов. Мне нужно поместить несколько QML MapItems (например, MapCircle, MapRectangle и т. Д.) В один компонент делегата. В общем, QML поддерживает несколько элементов в делегате. Проблема в делегате MapItemView: он не поддерживает несколько дочерних элементов.

Мой подход:

  1. Я думал, что с помощью MapItemGroup будет работать. Но, похоже, я что-то упустил. Документация также не настолько обширна, как я могу заставить ее работать как компонент делегата. Прикрепленный фрагмент демонстрирует эту реализацию.

    Документация Qt по MapItemGroup

В приведенном ниже коде:

  • DelegateCircle, DelegateRect работают нормально
  • DelegateGroup не отображается

Простая реализация:

import QtQuick 2.10
import QtPositioning 5.6
import QtLocation 5.9
import QtQuick.Controls 2.3 as QQc2

QQc2.ApplicationWindow {
    visible: true
    width: 640
    height: 480
    // Some list model
    ListModel {
        id: someModel
        ListElement {lat: 0; lon: 0}
        ListElement {lat: 5; lon: 0}
        ListElement {lat: 5; lon: 5}
        ListElement {lat: 0; lon: 5}
    }

    Map {
        id: map
        anchors.fill: parent
        plugin: Plugin {name: "osm"}
        center: QtPositioning.coordinate(2.5, 2.5)
        zoomLevel: 6

        // Some views to test the model
        // delegateCircle, delegateRect work fine
        // delegateGroup is not displayed 
        MapItemView {
            model: someModel
            delegate: MapCircle {
                id: delegateCircle
                border.color: "red"
                border.width: 1
                center: QtPositioning.coordinate(model.lat, model.lon)
                radius: 50*1000
            }
        }

        MapItemView {
            model: someModel
            delegate: MapRectangle {
                id: delegateRect
                border.color: "green"
                border.width: 3
                topLeft     : QtPositioning.coordinate(model.lat+1, model.lon-1)
                bottomRight : QtPositioning.coordinate(model.lat-1, model.lon+1)
            }
        }

        MapItemView {
            model: someModel
            delegate: MapItemGroup {
                id: delegateGroup
                MapCircle {
                    id: innerCircle
                    border.color: "green"
                    border.width: 3
                    center: QtPositioning.coordinate(model.lat, model.lon)
                    radius: 75*1000
                }

                MapRectangle {
                    id: innerRect
                    border.color: "red"
                    border.width: 6
                    topLeft     : QtPositioning.coordinate(model.lat+2, model.lon-2)
                    bottomRight : QtPositioning.coordinate(model.lat-2, model.lon+2)
                }
            }
        }
    }
}

Вывод вышеуказанного кода: Вывод кода QML

  1. Я также попытался использовать MapItemGroup в качестве sourceItem типа MapQuickItem. Это тоже не сработало.

Чего я хочу добиться:

Что ж. Мне нужно нарисовать несколько элементов карты, используя MapItemView. Любое другое решение / метод (включая бэкэнд-программу на C++) приветствуется.

РЕДАКТИРОВАТЬ

Спасибо @GrecKo и @Yoann. Оба ваших решения работают. Однако я решил продолжить работу с Instantiator, так как он больше подходит для моего приложения.

Я также нашел это интересным, увидев ваше решение: дискуссия разработчика о заполнении модели с использованием Repeater и Instantiator.

2 ответа

Решение

К несчастью, MapItemView работает только с MapItem предметы и MapItemGroup не один из них.

Вы могли бы использовать Repeater и это будет работать для делегатов, созданных с самого начала, но не будет работать, если вы добавите строки в вашу модель позже. Я объяснил в этом другом ответе, почему Repeater не очень подходит для Map,

В своем ответе советую использовать MapItemView но это не применимо здесь. Надеюсь, есть еще одно последнее доступное решение:
Instantiator с Map.addMapItemGroup() и Map.removeMapItemGroup ().

import QtQuick 2.10
import QtPositioning 5.6
import QtLocation 5.9
import QtQuick.Controls 2.3 as QQc2
import QtQml 2.2

QQc2.ApplicationWindow {
    visible: true
    width: 640
    height: 480

    ListModel {
        id: someModel
        ListElement {lat: 0; lon: 0}
        ListElement {lat: 5; lon: 0}
        ListElement {lat: 5; lon: 5}
        ListElement {lat: 0; lon: 5}
    }

    Timer {
        interval: 1000
        running: true
        repeat: true
        property bool toggle: true
        onTriggered: {
            if (toggle)
                someModel.append({lat: 2.5, lon: 2.5});
            else
                someModel.remove(4);
            toggle = !toggle;
        }
    }

    Map {
        id: map
        anchors.fill: parent
        plugin: Plugin {name: "osm"}
        center: QtPositioning.coordinate(2.5, 2.5)
        zoomLevel: 6

        Instantiator {
            model: someModel
            delegate: MapItemGroup {
                id: delegateGroup
                MapCircle {
                    id: innerCircle
                    border.color: "green"
                    border.width: 3
                    center: QtPositioning.coordinate(model.lat, model.lon)
                    radius: 75*1000
                }

                MapRectangle {
                    id: innerRect
                    border.color: "red"
                    border.width: 6
                    topLeft     : QtPositioning.coordinate(model.lat+2, model.lon-2)
                    bottomRight : QtPositioning.coordinate(model.lat-2, model.lon+2)
                }
            }
            onObjectAdded: map.addMapItemGroup(object)
            onObjectRemoved: map.removeMapItemGroup(object)
        }
    }
}

Это было исправлено в Qt 5.12, поэтому вы можете использовать свой код, как сейчас, с

import QtLocation 5.12
import QtPositioning 5.12

Вы могли бы использовать простой Repeater вместо MapItemView

import QtQuick 2.10
import QtPositioning 5.6
import QtLocation 5.9
import QtQuick.Controls 2.3

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    // Some list model
    ListModel {
        id: someModel
        ListElement {lat: 0; lon: 0}
        ListElement {lat: 5; lon: 0}
        ListElement {lat: 5; lon: 5}
        ListElement {lat: 0; lon: 5}
    }

    Map {
        id: map
        anchors.fill: parent
        plugin: Plugin {name: "osm"}
        center: QtPositioning.coordinate(2.5, 2.5)
        zoomLevel: 6

        Repeater
        {
            model: someModel
            MapItemGroup {
                id: delegateGroup
                MapCircle {
                    id: innerCircle
                    border.color: "green"
                    border.width: 3
                    center: QtPositioning.coordinate(model.lat, model.lon)
                    radius: 75*1000
                }

                MapRectangle {
                    id: innerRect
                    border.color: "red"
                    border.width: 6
                    topLeft     : QtPositioning.coordinate(model.lat+2, model.lon-2)
                    bottomRight : QtPositioning.coordinate(model.lat-2, model.lon+2)
                }

                Component.onCompleted: map.addMapItemGroup(this)
            }
        }
    }
}

Как указало GrecKo, для того, чтобы это работало с динамической моделью, itemGroup необходимо "вручную" добавить на карту, отсюда и строка Component.onCompleted: map.addMapItemGroup(this)

Другие вопросы по тегам