В QML (как) я могу сделать MapItemGroup как компонент делегата MapItemView?
Ситуация: я могу использовать элемент карты QML с моделью / видом / делегатом. Я умею работать с отдельными предметами.
Проблема: в качестве следующего шага я хотел бы иметь возможность рисовать несколько элементов. Мне нужно поместить несколько QML MapItems (например, MapCircle, MapRectangle и т. Д.) В один компонент делегата. В общем, QML поддерживает несколько элементов в делегате. Проблема в делегате MapItemView: он не поддерживает несколько дочерних элементов.
Мой подход:
Я думал, что с помощью 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)
}
}
}
}
}
- Я также попытался использовать 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)