1

我在 QML 中有一个列表并将其显示在 listView 对象中。按下按钮时,我需要从 python 访问这些数据。在 Python 中,我创建了一个 QStringListModel 对象,并使用 setContextProperty 将它绑定到我在 QML 中的 listModel。我可以看到在 QML 中按预期创建和显示列表,但是当我想从 python 访问数据时,列表是空的。这是代码:

质量管理体系:

import QtQuick 2.0
import QtQuick.Controls 2.3

Rectangle{
    id: root
    width:800
    height:600

    ListView {
        id: listView
        x: 476
        y: 64
        width: 110
        height: 160
        model: myModel
        ListModel {
            id: myModel
            ListElement {
                name: "Grey"
                colorCode: "grey"
            }

            ListElement {
                name: "Red"
                colorCode: "red"
            }

            ListElement {
                name: "Blue"
                colorCode: "blue"
            }

            ListElement {
                name: "Green"
                colorCode: "green"
            }
        }
        delegate: Item {
            x: 5
            width: 80
            height: 40
            Row {
                id: row1
                Rectangle {
                    width: 40
                    height: 40
                    color: colorCode
                }

                Text {
                    text: name
                    anchors.verticalCenter: parent.verticalCenter
                    font.bold: true
                }
                spacing: 10
            }
        }
    }
}

Python:

import sys
from PyQt5.QtCore import QUrl, QStringListModel
from PyQt5.QtWidgets import QApplication
from PyQt5.QtQuick import QQuickView


app = QApplication(sys.argv)
view = QQuickView()
view.setSource(QUrl("main.qml"))

pyList = QStringListModel()
view.rootContext().setContextProperty("myModel",pyList)
print(pyList.stringList())
print(pyList.rowCount())
view.show()
print("Done!")
sys.exit(app.exec_())

我的印象是,当我们使用 python 绑定时,在 python 中创建的对象绑定到 QML 对象。因此,如果 QML 列表有数据(在 UI 中动态创建),python 列表应该自动填充该数据吗?我错过了什么?

4

1 回答 1

2

您假设因为您通过 setContextProperty() 传递的模型与 ListModel 具有相同的名称,所以它是相同的,不,相反,它会导致您的程序不稳定,因为 QML 与两个名称重叠。相反,您必须在 python 中创建一个模型并将其导出,但由于您还想与 QML 交互,因此最好导出一个具有该模型的 QObject 作为 qproperty。不要使用 findChild、findChildren 在 python 中获取 QML 元素,必须与将元素从 python 导出到 QML 相反。

考虑到上述情况,除了可以从 QML 调用的插槽之外,我还实现了一个具有 qproperty 模型的 Manager 类。为避免代码复杂化,我使用 QStandardItemModel 类作为模型的基础,QStringListModel 是只读模型,因此不适用于这种情况。

主文件

from enum import Enum
from PyQt5 import QtCore, QtGui, QtQuick

class ElementRoles:
    NameRole = QtCore.Qt.UserRole + 1000
    ColorRole = QtCore.Qt.UserRole + 1001

class ElementModel(QtGui.QStandardItemModel, ElementRoles):
    QtCore.Q_ENUM(ElementRoles)

    def __init__(self, parent=None):
        super(ElementModel, self).__init__(parent)
        roles = {
            ElementModel.NameRole: b'name',
            ElementModel.ColorRole: b'colorCode'
        }
        self.setItemRoleNames(roles)

    @QtCore.pyqtSlot(str, QtGui.QColor)
    def addElement(self, name, color):
        item = QtGui.QStandardItem()
        item.setData(name, ElementModel.NameRole)
        item.setData(color, ElementModel.ColorRole)
        self.appendRow(item)

class Manager(QtCore.QObject):
    def __init__(self, parent=None):
        super(Manager, self).__init__(parent)
        self._model = ElementModel()

    @QtCore.pyqtProperty(QtCore.QObject, constant=True)
    def model(self):
        return self._model

    @QtCore.pyqtSlot()
    def on_clicked(self):
        print("count:", self._model.rowCount())
        for row in range(self._model.rowCount()):
            it = self._model.item(row)
            print("row:", row)
            for role, name in self._model.roleNames().items():
                print("role:", name, "data:", it.data(role))

if __name__ == '__main__':
    import os
    import sys
    app = QtGui.QGuiApplication(sys.argv)
    manager = Manager()
    view = QtQuick.QQuickView()
    file = os.path.join(os.path.dirname(os.path.realpath(__file__)), "main.qml")
    view.rootContext().setContextProperty("manager", manager)
    view.setSource(QtCore.QUrl.fromLocalFile(file))
    view.show()
    sys.exit(app.exec_())

main.qml

import QtQuick 2.0
import QtQuick.Controls 2.3
import QtQuick.Layouts 1.3

Rectangle{
    id: root
    width:800
    height:600

    ColumnLayout{
        anchors.fill: parent
        ListView {
            id: listView
            Layout.alignment: Qt.AlignLeft
            Layout.fillHeight: true
            model: manager.model
            delegate: Item {
                x: 5
                width: 80
                height: 40
                Row {
                    id: row1
                    Rectangle {
                        width: 40
                        height: 40
                        color: colorCode
                    }

                    Text {
                        text: name
                        anchors.verticalCenter: parent.verticalCenter
                        font.bold: true
                    }
                    spacing: 10
                }
            }
        }

        Button{
            Layout.alignment: Qt.AlignCenter
            text: "click me"
            onClicked: manager.on_clicked()
        }
    }

    Component.onCompleted:{
        manager.model.addElement("Gray", "gray")
        manager.model.addElement("Red", "red")
        manager.model.addElement("Blue", "blue")
        manager.model.addElement("Green", "green")
    }
}

我建议您阅读我的另一个答案以获得更详细的解释。

于 2019-04-01T22:26:51.543 回答