首页 > 解决方案 > 使用 qml 中的元素显示的 python 中的数组

问题描述

我应该用 qml 显示一些矩形。这些 Rectangle{} 的位置取决于 x=array[i][0] 和 y=array[i][1],其数量取决于 array.lenght()。

qml 中的数组应该等于 Python 中的 self.__rectanglePos

所以我需要一种方法来在不同的位置和不同的数量上绘制矩形,这取决于数组。

我怎样才能做到这一点?

_____.py

class NN(QObject):
    def __init__(self):
        QObject.__init__(self)
        self.__rectanglePos = [] #each element contains:[x,y,orientation 360°]

    #signals
    rectanglePosChanged = Signal(type(self.__rectanglePos))

    @Slot()
    def rects(self):   
        self.rectanglePosChanged.emit(self.__rectanglePos)   


if __name__ == '__main__':
    app = QGuiApplication(sys.argv)
    engine = QQmlApplicationEngine()
    qmlRegisterType(NN, 'gnn', 1, 0, 'NN')
    engine.load(QUrl.fromLocalFile(gnn.qml))
    if not engine.rootObjects():
        sys.exit(-1)   
    sys.exit(app.exec_())

这在 qml 中不起作用:________.qml

#[...]
import gnn 1.0


ApplicationWindow {
     ListView{
            id: rect
            function f(){
                for (var i = 0; i < array.lenght(); ++i){
                     Rectangle {      
                          x: array[i][0]
                          y: array[i][1]
                     }
                }                  
            }
    }
    MouseArea{
    onClicked: rects()
    }
    NN{
        id: nn

        signal getRectangles(var array) // not working

        Component.onCompleted: {

            nn.rectanglePosChanged.connect(getRectangles)

        }
    }
    Connections {
        target: nn

        onGetRectangles: {

        }

    }
}

标签: pythonqtqmlpyside2

解决方案


您的代码有很多错误,例如您想访问类的属性:self.__rectanglePos)这仅在从创建类之前执行的部分代码创建对象时才有意义:rectanglePosChanged = Signal(type(self.__rectanglePos)),因此我将避免指出您的错误除了我的解决方案所必需的之外。

如果您想将信息作为添加、替换或删除项目的列表发送,那么最好使用模型,因为它会根据更改通知您。在这种情况下,为了简单起见,我使用 QStandardItemModel,因此元素的每个部分作为“x”和“y”都将通过角色访问。

在 QML 的情况下,由于您想将 Rectangles 放置在任何位置,因此使用 ListView 不是正确的选择,因为此视图限制了位置,而您必须使用 Repeater。

主文件

import os
import sys

from PySide2 import QtCore, QtGui, QtQml

XRole = QtCore.Qt.UserRole + 1000
YRole = QtCore.Qt.UserRole + 1001
AngleRole = QtCore.Qt.UserRole + 1002


class RectangleManager(QtCore.QObject):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.m_model = QtGui.QStandardItemModel(self)

        roles = {XRole: b"x", YRole: b"y", AngleRole: b"angle"}

        self.m_model.setItemRoleNames(roles)

    @QtCore.Property(QtCore.QObject, constant=True)
    def model(self):
        return self.m_model

    @QtCore.Slot(float, float, float)
    def add_rectangle(self, x, y, angle):
        it = QtGui.QStandardItem()
        it.setData(x, XRole)
        it.setData(y, YRole)
        it.setData(angle, AngleRole)
        self.model.appendRow(it)

    @QtCore.Slot()
    def clear_rectangles(self):
        self.model.clear()


def main(args):
    app = QtGui.QGuiApplication(args)

    manager = RectangleManager()

    import random

    for _ in range(10):
        manager.add_rectangle(
            random.randint(0, 500), random.randint(0, 500), random.randint(0, 360)
        )

    engine = QtQml.QQmlApplicationEngine()
    engine.rootContext().setContextProperty("rectangle_manager", manager)
    current_dir = os.path.dirname(os.path.realpath(__file__))
    filename = os.path.join(current_dir, "main.qml")
    engine.load(QtCore.QUrl.fromLocalFile(filename))
    if not engine.rootObjects():
        return -1
    ret = app.exec_()
    return ret


if __name__ == "__main__":
    sys.exit(main(sys.argv))

main.qml

import QtQuick 2.12
import QtQuick.Controls 2.12

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

    Repeater{
        model: rectangle_manager.model

        Rectangle{
            x: model.x
            y: model.y
            rotation: model.angle
            width: 100
            height: 100
            color: Qt.rgba(Math.random(), Math.random(), Math.random(), 1)
        }
    }
}

在此处输入图像描述


推荐阅读