作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试创建一些将在 QML map 上动态移动的标记。然而,在此之前,我需要使用鼠标将它们全部绘制在 map 上,以便稍后更新它们。我一直在使用 pyqtProperty 将我需要的坐标发送到 QML,但是当我尝试将它们添加到 MapItemView 时,它们是未定义的。下面的代码演示了我希望实现的目标。问题是我从另一个 python 对象传递 pyqtProperty 到 QML,而该对象没有像 main.py
中那样使用 setContextProperty()
添加吗?或者我是否错误地使用了 MapItemView 委托(delegate)?
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.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
DC.py
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)
main.py
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 中创建模型,而不是在 QML 中创建模型,以便能够直接处理它,您必须从 QAbstractListModel 继承。为了平滑移动,您应该使用 QxxxAnimation 作为 QPropertyAnimation。
在下面的示例中,每次插入标记时,都会调用 on_markersInserted 函数,该函数会将标记移向窗口的中心。
main.py
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)))
}
}
}
关于python - 无法通过 MouseClick 将 MapCircles 添加到 QML map ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55290279/
我正在尝试创建一些将在 QML map 上动态移动的标记。然而,在此之前,我需要使用鼠标将它们全部绘制在 map 上,以便稍后更新它们。我一直在使用 pyqtProperty 将我需要的坐标发送到 Q
我是一名优秀的程序员,十分优秀!