使用 Python 从 QML 中动态创建的列表中访问数据
Posted
技术标签:
【中文标题】使用 Python 从 QML 中动态创建的列表中访问数据【英文标题】:Accessing data from a dynamically created list in QML with Python 【发布时间】:2019-03-29 19:53:57 【问题描述】:我在 QML 中有一个列表并在 listView 对象中显示它。按下按钮时,我需要从 python 访问这些数据。在 Python 中,我创建了一个 QStringListModel 对象,并使用 setContextProperty 将它绑定到我在 QML 中的 listModel。我可以看到在 QML 中按预期创建和显示列表,但是当我想从 python 访问数据时,列表是空的。代码如下:
QML:
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 列表应该自动填充该数据吗?我错过了什么?
【问题讨论】:
从我们这里看到的,你的列表是空的,你在哪里添加你的项目?显示sendChar
以及您的delegate
的实现。开发人员喜欢在可以复制粘贴代码并查看其中有什么问题时提供帮助。
嘿,我已将代码更改为一个简短的示例。我在 qml 中有一个列表,但我无法从 python 访问它的数据。我是 Qml 新手,所以我不确定我在这里缺少什么!
【参考方案1】:
您假设因为您通过 setContextProperty() 传递的模型与 ListModel 具有相同的名称,所以它是相同的,不,相反,它会导致您的程序不稳定,因为 QML 与两个名称重叠。相反,您必须在 python 中创建一个模型并将其导出,但由于您还想与 QML 交互,因此最好导出一个具有该模型的 QObject 作为 qproperty。不要使用 findChild、findChildren 在 python 中获取 QML 元素,必须与将元素从 python 导出到 QML 相反。
考虑到上述情况,除了可以从 QML 调用的插槽之外,我还实现了一个具有 qproperty 模型的 Manager 类。为避免代码复杂化,我使用 QStandardItemModel 类作为模型的基础,QStringListModel 是只读模型,因此不适用于这种情况。
main.py
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")
我建议您阅读my another answer 以获得更详细的说明。
【讨论】:
以上是关于使用 Python 从 QML 中动态创建的列表中访问数据的主要内容,如果未能解决你的问题,请参考以下文章
使用 QAbstractListModel 从 python 访问 QML 中的列表元素
类型错误:无法在嵌套列表视图中读取 null 的属性“newdaycalendar”,其中 listmodel 动态创建了 qml