无法在鼠标单击上将地图圆圈添加到QML地图

问题描述 投票:1回答:1

我正在尝试创建一些将在QML地图上动态移动的标记。然而,在此之前,我需要使用鼠标将它们全部绘制在地图上,以便我以后可以更新它们。我一直在使用pyqtProperty将我需要的坐标发送到QML,但是当我尝试将它们添加到MapItemView时,它们是未定义的。以下代码演示了我希望实现的目标。问题是我将pyqtProperty传递给QML来自另一个没有像setContextProperty()那样添加main.py的python对象?或者我错误地使用MapItemView委派?

main.qml

import QtQuick 2.7
import QtQml 2.5
import QtQuick.Controls 1.3
import QtQuick.Controls.Styles 1.3
import QtQuick.Window 2.2
import QtQuick.Layouts 1.2
import QtPositioning 5.9
import QtLocation 5.3
import QtQuick.Dialogs 1.1

ApplicationWindow {
    id: root
    width: 640
    height: 480
    visible: true

    ListModel {
        id: markers
    }

    Plugin {
        id: mapPlugin
        name: "osm" //"mapboxgl" "osm" "esri"
    }

    Map {
        id: map
        anchors.fill: parent
        plugin: mapPlugin
        center: atc.location
        zoomLevel: 14

        MapItemView {
            model: markers
            delegate: MapCircle {
                radius: 50
                color: 'red'
                center: markLocation //issue here? 
            }
        }

        MapCircle {
            id: home
            center: atc.location
            radius: 40
            color: 'white'
        }

        MouseArea {
            id: mousearea
            anchors.fill: map
            acceptedButtons: Qt.LeftButton | Qt.RightButton
            hoverEnabled: true
            property var coord: map.toCoordinate(Qt.point(mouseX, mouseY))

            onDoubleClicked: {
                if (mouse.button === Qt.LeftButton)
                {
                    //Capture information for model here
                    atc.plot_mark(
                        "marker",
                        mousearea.coord.latitude,
                        mousearea.coord.longitude)
                    markers.append({
                        name: "markers",
                        markLocation: atc.get_marker_center("markers")
                    })
                }
            }
        }
    }
}

ATC.朋友

import geocoder
from DC import DC
from PyQt5.QtPositioning import QGeoCoordinate
from PyQt5.QtCore import QObject, pyqtSignal, pyqtProperty, pyqtSlot

class ATC(QObject):
    #pyqt Signals
    locationChanged = pyqtSignal(QGeoCoordinate)

    def __init__(self, parent=None):
        super().__init__(parent)
        self._location = QGeoCoordinate()
        self.dcs = {}
        g = geocoder.ip('me')
        self.set_location(QGeoCoordinate(*g.latlng))


    def set_location(self, coordinate):
        if self._location != coordinate:
            self._location = coordinate
            self.locationChanged.emit(self._location)


    def get_location(self):
        return self._location


    #pyqt Property
    location = pyqtProperty(QGeoCoordinate,
        fget=get_location,
        fset=set_location,
        notify=locationChanged)


    @pyqtSlot(str, str, str)
    def plot_mark(self, mark_name, lat, lng):
            dc = DC(mark_name)
            self.dcs[mark_name] = dc
            self.dcs[mark_name].set_location(
                QGeoCoordinate(float(lat), float(lng)))


    @pyqtSlot(str)
    def get_marker_center(self, mark_name):
        return self.dcs[mark_name].location

DC.朋友

from PyQt5.QtPositioning import QGeoCoordinate
from PyQt5.QtCore import QObject, pyqtSignal, pyqtProperty, pyqtSlot

class DC(QObject):
    #pyqt Signals
    locationChanged = pyqtSignal(QGeoCoordinate)

    def __init__(self, name, parent=None):
        super().__init__(parent)
        self.name = name
        self._location = QGeoCoordinate()        


    def set_location(self, coordinate):
        if self._location != coordinate:
            self._location = coordinate
            self.locationChanged.emit(self._location)


    def get_location(self):
        return self._location


    #pyqt Property
    location = pyqtProperty(QGeoCoordinate,
        fget=get_location,
        fset=set_location,
        notify=locationChanged)

卖弄.朋友

from PyQt5.QtGui import QGuiApplication
from PyQt5.QtQml import QQmlApplicationEngine
from PyQt5.QtCore import QObject, QUrl, pyqtSignal, pyqtProperty
from PyQt5.QtPositioning import QGeoCoordinate

from ATC import ATC

if __name__ == "__main__":
    import os
    import sys

    app = QGuiApplication(sys.argv)

    engine = QQmlApplicationEngine()

    atc = ATC()

    engine.rootContext().setContextProperty("atc", atc)

    qml_path = os.path.join(os.path.dirname(__file__), "main.qml")
    engine.load(QUrl.fromLocalFile(qml_path))

    if not engine.rootObjects():
        sys.exit(-1)

    engine.quit.connect(app.quit)
    sys.exit(app.exec_())
python pyqt qml pyqt5 qtlocation
1个回答
1
投票

您不必在QML中创建模型,而是必须在python中创建它以便能够直接处理它,您必须从QAbstractListModel继承它。为了平滑移动,您应该使用QxxxAnimation作为QPropertyAnimation。

在下面的示例中,每次插入标记时,都会调用on_markersInserted函数,该函数会将标记移向窗口的中心。

卖弄.朋友

from functools import partial
from PyQt5 import QtCore, QtGui, QtQml, QtPositioning
import geocoder

class Marker(QtCore.QObject):
    locationChanged = QtCore.pyqtSignal(QtPositioning.QGeoCoordinate)

    def __init__(self, location=QtPositioning.QGeoCoordinate(), parent=None):
        super().__init__(parent)
        self._location = location

    def set_location(self, coordinate):
        if self._location != coordinate:
            self._location = coordinate
            self.locationChanged.emit(self._location)

    def get_location(self):
        return self._location

    location = QtCore.pyqtProperty(QtPositioning.QGeoCoordinate,
        fget=get_location,
        fset=set_location,
        notify=locationChanged)

    def move(self, location, duration=1000):
        animation = QtCore.QPropertyAnimation(
            targetObject=self, 
            propertyName=b'location',
            startValue=self.get_location(),
            endValue=location,
            duration=duration,
            parent=self
        )
        animation.start(QtCore.QAbstractAnimation.DeleteWhenStopped)

    def moveFromTo(self, start, end, duration=1000):
        self.set_location(start)
        self.move(end, duration)

class MarkerModel(QtCore.QAbstractListModel):
    markersInserted = QtCore.pyqtSignal(list)

    PositionRole = QtCore.Qt.UserRole + 1000

    def __init__(self, parent=None):
        super().__init__(parent)
        self._markers = []
        self.rowsInserted.connect(self.on_rowsInserted)

    def rowCount(self, parent=QtCore.QModelIndex()):
        return 0 if parent.isValid() else len(self._markers)

    def data(self, index, role=QtCore.Qt.DisplayRole):
        if index.isValid() and 0 <= index.row() < self.rowCount():
            if role == MarkerModel.PositionRole:
                return self._markers[index.row()].get_location()
        return QtCore.QVariant()

    def roleNames(self):
        roles = {}
        roles[MarkerModel.PositionRole] = b'position'
        return roles

    @QtCore.pyqtSlot(QtPositioning.QGeoCoordinate)
    def appendMarker(self, coordinate):
        self.beginInsertRows(QtCore.QModelIndex(), self.rowCount(), self.rowCount())
        marker = Marker(coordinate)
        self._markers.append(marker)
        self.endInsertRows()
        marker.locationChanged.connect(self.update_model)

    def update_model(self):
        marker = self.sender()
        try:
            row = self._markers.index(marker)
            ix = self.index(row)
            self.dataChanged.emit(ix, ix, (MarkerModel.PositionRole,))
        except ValueError as e:
            pass

    @QtCore.pyqtSlot(QtCore.QModelIndex, int, int)
    def on_rowsInserted(self, parent, first, end):
        markers = []
        for row in range(first, end+1):
            markers.append(self.get_marker(row))
        self.markersInserted.emit(markers)


    def get_marker(self, row):
        if 0 <= row < self.rowCount():
            return self._markers[row]

class ManagerMarkers(QtCore.QObject):
    locationChanged = QtCore.pyqtSignal(QtPositioning.QGeoCoordinate)

    def __init__(self, parent=None):
        super().__init__(parent)
        self._center= Marker(parent=self)
        self._model = MarkerModel(self)  
        g = geocoder.ip('me')
        self.moveCenter(QtPositioning.QGeoCoordinate(*g.latlng)) 

    def model(self):
        return self._model     

    def center(self):
        return self._center

    def moveCenter(self, position):
        self._center.set_location(position)

    center = QtCore.pyqtProperty(QtCore.QObject, fget=center, constant=True)
    model = QtCore.pyqtProperty(QtCore.QObject, fget=model, constant=True)


# testing
# When a marker is added
# it will begin to move toward
# the center of the window
def on_markersInserted(manager, markers):
    end = manager.center.get_location()
    for marker in markers:
        marker.move(end, 5*1000)

if __name__ == "__main__":
    import os
    import sys

    app = QtGui.QGuiApplication(sys.argv)
    manager = ManagerMarkers()
    engine = QtQml.QQmlApplicationEngine()
    engine.rootContext().setContextProperty("manager", manager)
    qml_path = os.path.join(os.path.dirname(__file__), "main.qml")
    engine.load(QtCore.QUrl.fromLocalFile(qml_path))
    if not engine.rootObjects():
        sys.exit(-1)
    manager.model.markersInserted.connect(partial(on_markersInserted, manager))
    engine.quit.connect(app.quit)
    sys.exit(app.exec_())

main.qml

import QtQuick 2.7
import QtQuick.Controls 2.2
import QtPositioning 5.9
import QtLocation 5.3

ApplicationWindow {
    id: root
    width: 640
    height: 480
    visible: true

    Plugin {
        id: mapPlugin
        name: "osm" // "mapboxgl" "osm" "esri"
    }

    Map {
        id: map
        anchors.fill: parent
        plugin: mapPlugin
        center: manager.center.location
        zoomLevel: 14

        MapCircle {
            id: home
            center: manager.center.location
            radius: 40
            color: 'white'
        }

        MapItemView {
            model: manager.model
            delegate: MapCircle {
                radius: 50
                color: 'red'
                center: model.position
            }
        }

        MouseArea {
            id: mousearea
            anchors.fill: map
            acceptedButtons: Qt.LeftButton | Qt.RightButton
            onDoubleClicked: if (mouse.button === Qt.LeftButton)  
                                manager.model.appendMarker(map.toCoordinate(Qt.point(mouseX, mouseY)))
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.