4

我正在使用 PyQt5 通过 UI 文件中的 QQuickWidget 访问 QML 代码。我的 QML 文件创建地图并绘制点。我想从我的 python 代码中添加/修改这些点。我可以在 python 中访问 QML 中的 Map 对象,但 PyQt 将它和 MapQuickItem 视为 QQuickItems。我不确定如何在 python 中实际创建一个新的 MapQuickItem 并将其添加到 Map 对象中。我尝试使用必要的属性创建 QQuickItem,然后使用 addMapItem 方法,但收到此错误:

TypeError: 无法将 QQuickItem.addMapItem 的参数 0 从 'QQuickItem' 转换为 'QDeclarativeGeoMapItemBase*'"

我不知道如何QDeclarativeGeoMapItemBase在 PyQt 中创建一个对象,或者我是否应该以另一种方式进行。

如您所见,我在正确引用 QML 文件中的对象时也遇到了一些问题。self.map或者self.map.rootObject()在 UI 中为我获取 QQuickWidget,在self.map.rootObject().children()[1]QML 中获取 Map 对象。我更喜欢使用 findChild() 通过它们的 ID 来定位这些项目,但一直没能做到。有没有更好的方法?是否应该创建一个复制我的 QML 文件结构的 Python 对象?

这是 QML 代码的示例。我在 UI 文件中将此 QML 文件作为 QQuickWidget 引用。

 Rectangle {
id:rectangle

Plugin {
    id: osmPlugin
    name: "osm"
}

property variant locationTC: QtPositioning.coordinate(44.951, -93.192)

Map {
    id: map
    anchors.fill: parent
    plugin: osmPlugin
    center: locationTC
    zoomLevel: 10

    MapQuickItem {
        coordinate: QtPositioning.coordinate(44.97104,-93.46055)
        anchorPoint.x: image.width * 0.5
        anchorPoint.y: image.height
        sourceItem:
            Image { id: image; source: "marker.png" }

    }
  }
}

下面是我尝试创建 MapQuickItem 并将其添加到地图的 PyQt 代码示例。

from PyQt5 import QtCore, uic, QtWidgets, QtPositioning, QtLocation, QtQml, QtQuick

form_class = uic.loadUiType("TTRMS.ui")[0]     

class MainWindow(QtWidgets.QMainWindow, form_class):
    '''
    classdocs
    '''
    def __init__(self, parent=None):
        QtWidgets.QMainWindow.__init__(self, parent)
        self.setupUi(self)        

        tmc = QQuickItem()
        new_coordinate = QtPositioning.QGeoCoordinate()
        new_coordinate.setLatitude(44.951)
        new_coordinate.setLongitude(-93.192)
        tmc.setProperty("coordinate",new_coordinate)
        tmc.setProperty("anchorPoint",QtCore.QPointF(12.5, 32.0))
        image = QQuickItem()
        image.setProperty("source", QtCore.QUrl.fromLocalFile(("marker.png")))
        tmc.setProperty("sourceItem", image)
        image.setParent(tmc)
        self.map.rootObject().children()[1].addMapItem(tmc)

我在 Windows 7 上运行一切。PyQt5 开发是在 Eclipse 中使用 PyDev 和 Python 3.4(32 位)、Qt Creator 5.5 中的 QML 编码和 Qt Designer 5.5 中的 UI 完成的。

4

1 回答 1

2

在您想使用 QML 与 C++/Python 交互的情况下,最好向 QML 公开一些对象,以便将 C++/Python 的数据传输到 QML,因为后者具有不同的生命周期。

在这种特殊情况下,我将创建一个存储数据的模型,通过 setContextProperty() 将其发送到 QML,并在 QML 端使用带有委托的 MapItemView,这样您就可以拥有许多标记。

主文件

import os
from PyQt5 import QtCore, QtWidgets, QtQuickWidgets, QtPositioning

class MarkerModel(QtCore.QAbstractListModel):
    PositionRole, SourceRole = range(QtCore.Qt.UserRole, QtCore.Qt.UserRole + 2)

    def __init__(self, parent=None):
        super(MarkerModel, self).__init__(parent)
        self._markers = []

    def rowCount(self, parent=QtCore.QModelIndex()):
        return len(self._markers)

    def data(self, index, role=QtCore.Qt.DisplayRole):
        if 0 <= index.row() < self.rowCount():
            if role == MarkerModel.PositionRole:
                return self._markers[index.row()]["position"]
            elif role == MarkerModel.SourceRole:
                return self._markers[index.row()]["source"]
        return QtCore.QVariant()

    def roleNames(self):
        return {MarkerModel.PositionRole: b"position_marker", MarkerModel.SourceRole: b"source_marker"}

    def appendMarker(self, marker):
        self.beginInsertRows(QtCore.QModelIndex(), self.rowCount(), self.rowCount())
        self._markers.append(marker)
        self.endInsertRows()

class MapWidget(QtQuickWidgets.QQuickWidget):
    def __init__(self, parent=None):
        super(MapWidget, self).__init__(parent,
            resizeMode=QtQuickWidgets.QQuickWidget.SizeRootObjectToView)
        model = MarkerModel(self)
        self.rootContext().setContextProperty("markermodel", model)
        qml_path = os.path.join(os.path.dirname(__file__), "main.qml")
        self.setSource(QtCore.QUrl.fromLocalFile(qml_path))

        positions = [(44.97104,-93.46055), (44.96104,-93.16055)]
        urls = ["http://maps.gstatic.com/mapfiles/ridefinder-images/mm_20_gray.png", 
                "http://maps.gstatic.com/mapfiles/ridefinder-images/mm_20_red.png"]

        for c, u in zip(positions, urls):
            coord = QtPositioning.QGeoCoordinate(*c)
            source = QtCore.QUrl(u)
            model.appendMarker({"position": coord , "source": source})


if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = MapWidget()
    w.show()
    sys.exit(app.exec_())

main.qml

import QtQuick 2.11
import QtPositioning 5.11
import QtLocation 5.11

Rectangle {
    id:rectangle
    width: 640
    height: 480
    Plugin {
        id: osmPlugin
        name: "osm"
    }
    property variant locationTC: QtPositioning.coordinate(44.951, -93.192)
    Map {
        id: map
        anchors.fill: parent
        plugin: osmPlugin
        center: locationTC
        zoomLevel: 10
        MapItemView{
            model: markermodel
            delegate: MapQuickItem {
                coordinate: model.position_marker
                anchorPoint.x: image.width
                anchorPoint.y: image.height
                sourceItem:
                    Image { id: image; source: model.source_marker }
            }
        }
    }
}

在此处输入图像描述

于 2018-12-12T05:14:55.713 回答