qtdelegatesqmlmodel-view

In QML, (how) can I make MapItemGroup as a MapItemView's delegate component?


Situation: I am able to use QML Map item with Model/View/delegate. I am able to work with individual items.

Problem: As a next step, I would like to be able to draw multiple items. I need to put multiple QML MapItems (like MapCircle, MapRectangle, etc..) in a single delegate component. In general, QML supports multiple items within a delegate. The problem is with MapItemView's delegate: it does not support multiple children items.

My Approach:

  1. I thought using MapItemGroup would work. But it seems like I am missing something. The documentation is also not so extensive on how I can make it work as a delegate component. The attached snippet shows this implementation.

    Qt's Documentation on MapItemGroup

In the code below:

A simple implementation:

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

The output of the above code is: The output of the QML code

  1. I also tried using the MapItemGroup as a sourceItem of MapQuickItem type. This did not work either.

What I want to achieve:

Well. I need to draw multiple map items using a MapItemView. Any other solution/method (including c++ backend program) is welcome.

EDIT

Thank you @GrecKo and @Yoann. Both of your solutions work. However, I chose to continue with Instantiator since it is more suited for my application.

I also found this interesting after seeing your solution: a developer's discussion on populating a model using Repeater and Instantiator.


Solution

  • Unfortunately, MapItemView only works with MapItem-derived items, and MapItemGroup is not one of them.

    You could use a Repeater and it will work for delegates created from the start, but it won't work if you add rows in your model later on. I explained in this other answer why Repeater is not well suited for a Map.

    In my answer I advise to use MapItemView but it's not applicable here. Hopefully, there is still one last available solution :
    Instantiator with Map.addMapItemGroup() and 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)
            }
        }
    }