Python 无法在鼠标单击时将MapCircles添加到QML映射

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

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

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
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_())
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_())
DC.py

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
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_())
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.py

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
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_())
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_())

您必须在python中创建模型,而不是在QML中创建模型,以便能够直接为其处理模型,您必须从QAbstractListModel继承模型。要实现平滑移动,应使用QXXX动画作为QPropertyAnimation

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

main.py

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
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_())
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_())

你的问题不是很具有描述性,你能详细说明你想要什么吗?双击地图时是否要添加标记?plot_mark的用途是什么?self.dcs的用途是什么?您好。是的,当我双击地图时,我想在地图上显示一个MapCircle。稍后,我希望能够实时移动我绘制的地图圈。ATC.py包含许多我希望绘制的DC.py点(self.dcs)
plot_mark()
将QML信息发送到DC.py,我可以使用DC.py数据添加新的MapCircle您想通过双击QML添加点,然后使用python代码移动它吗?是的,我通过双击添加点,后来我调用了一些可以移动点的python代码。我使用的是QML 5.9,只能使用
QtQuick.Controls 2.2
这会导致动画不启动吗?@reverse\u engineer标记不移动是什么意思?您在控制台中是否收到任何消息?执行CMD/terminal中的代码以获取所有错误messages@reverse_engineer您是否在未修改的情况下使用我的代码?如果是,请检查控制台是否打印错误,如果不是,请先尝试我的初始代码,理解并修改它。@反向工程QtQuick.Controls 2.2或QtQuick.Controls 2.3是indifferent@reverse_engineer最后,我建议您始终使用最新版本(目前为5.12.1),或者至少指出您正在使用的PyQt5版本。您的Qt版本(如果已安装)不一定与PyQt5的版本一致,其中包括依赖项。