Search code examples
pythonqtqmlpyside2qtlocation

Multiple Marker with different Images as Icons in QML Map Widget


What do I want ? I have a widget in QML which displays a map with OSM plugin. On this map whenever I click I want to place a marker. If I click on another position a new marker should be added. In the top I have a Tabbar. Depending on which Button (currentIndex) a different type of Image/Marker Icon should be displayed with the click on the map (currently for test reasons on the first tab blue rectangles on the second red circles). And all markers should stay visible on the map.

Current Code:

import QtPositioning 5.11
import QtLocation 5.11
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
import QtQuick.Controls.Styles 1.4

Rectangle {
    id:rectangle
    width: 640
    height: 480
    Plugin {
        id: osmPlugin
        name: "osm"

        PluginParameter{
            name:"osm.mapping.providersrepository.address"
            value: "http://127.0.0.1:8080/"
        }
    }
    
    property variant locationTC: QtPositioning.coordinate(52.5200, 13.4050)

    ListModel {
        id: markermodel
        dynamicRoles: true
    }
    
    Loader{
        id: mloader
        sourceComponent:
            if(bar.currentIndex == 0)//some condition
                return idRect
            else if(bar.currentIndex == 1) //another condition
                return idCircle

    }
    Component{
        id: idRect
        Rectangle{
            width: 20
            height: 20
            color: "blue"
        }
    }
    Component{
        id: idCircle
        Rectangle{
            color: "red"
            width: 20
            height: 20
            radius: 50
        }
    }

    Map {
        id: map
        anchors.fill: parent
        plugin: osmPlugin
        center: QtPositioning.coordinate(59.91, 10.75) 
        zoomLevel: 3
        MapItemView{
            model: markermodel
            delegate: MapQuickItem {
                id: marker
                coordinate: model.position_marker
                sourceItem: model.marker_source
            }
        }
        
         

        MouseArea
        {
            id: mouseArea
            anchors.fill: parent
            hoverEnabled: true
            onClicked: {
                var coord = map.toCoordinate(Qt.point(mouse.x,mouse.y));
                var msource =  mloader.item;
                markermodel.append({"position_marker": coord, "marker_source": msource})
                Hugo.getCoordinates((map.toCoordinate(Qt.point(mouse.x,mouse.y)).latitude), (map.toCoordinate(Qt.point(mouse.x,mouse.y)).longitude))
            }
        }
        
        Item {
            TabBar {
                id: bar
                width: 500
                height:25
                background: Rectangle{
                    opacity:0
                }
                Repeater {
                    model: [qsTr("C1"), qsTr("C2"), qsTr("C3"), qsTr("C4"), qsTr("C5")]
                    TabButton {
                        text: modelData
                        width: 100
                        property int roundedEdge: 0 // 0 - no rounded edges, 1 - left side rounded, 2 - right side rounded
                        background: Item
                        {
                            Rectangle {
                                id:     roundRect
                                height: 25
                                width:  100
                                radius: roundedEdge == 0 ? 0 : 5
                                color:  "#35383b"
                            }

                            Rectangle {
                                id:     leftSquareRect
                                visible: roundedEdge == 2
                                color:  "#35383b"
                                height: roundRect.height
                                width:  roundRect.width - roundRect.radius
                                anchors.bottom : roundRect.bottom
                                anchors.left : roundRect.left
                            }

                            Rectangle {
                                id:     rightSquareRect
                                visible: roundedEdge == 1
                                color:  "#35383b"
                                height: roundRect.height
                                width:  roundRect.width - roundRect.radius
                                anchors.bottom : roundRect.bottom
                                anchors.right : roundRect.right
                            }
                        }
                    }
                }
                onCountChanged: {
                    for(let i = 0; i < bar.count; i++)
                    {
                        if(i == 0)
                            bar.itemAt(i).roundedEdge = 1
                        else if(i == bar.count - 1)
                            bar.itemAt(i).roundedEdge = 2
                        else
                            bar.itemAt(i).roundedEdge = 0
                    }
                }
                onCurrentIndexChanged: {
                    if(bar.currentIndex == 2)
                        print("currentIndex changed to", currentIndex)
                       
                }
                
            }
        }
    }
}


.getCoordinates is a Signal to a Python backend.

I tried to realise the above desired functionality in the MouseArea.onClicked event. However in the current implementation only the switching of the marker icons work but only the latest marker remains.

Moving the loader definition to the MapQuickItem.sourceItem definition results in the following. The markers remain but changing the tab index switches the icon for all marker new and old.

What am I doing wrong and how can I achieve the desired functionality ? Moreover do i have a misconception on the interactions ?


Solution

  • You should create a new component for each delegate(MapQuickItem), instead of reusing a single instance(the mloader.item).

    So do like this, removing the mloader and the "marker_source" role.

    ...
    Rectangle {
        ...
        Map {
            ...
            MapItemView {
                model: markermodel
                delegate: MapQuickItem {
                    id: marker
                    coordinate: model.position_marker
                    sourceItem: Loader {
                        sourceComponent: [idRect, idCircle][model.type]                    
                    }
                }
            }
    
            MouseArea
            {
                ...
                onClicked: {
                    var coord = map.toCoordinate(Qt.point(mouse.x, mouse.y));
                    markermodel.append({"position_marker": coord, "type": bar.currentIndex})
                    ...
                }
            }
        }
        ...
    }
    ...