使用 QAbstractListModel 从 python 访问 QML 中的列表元素
Posted
技术标签:
【中文标题】使用 QAbstractListModel 从 python 访问 QML 中的列表元素【英文标题】:Access list element in QML from python using the QAbstractListModel 【发布时间】:2019-11-24 23:03:54 【问题描述】:我是 Qt 的初学者,我正在通过以下方式创建应用程序:
-
使用 QML 进行视图设计,
使用python主要用于Controller和Model部分。
因此,QML 需要与 python 对象进行交互。
我的问题:我通过以下(简化)代码在 python 中创建了一个QAbstractListModel
:
class MyList(QAbstractListModel):
_myCol1 = Qt.UserRole + 1
_myCol2 = Qt.UserRole + 2
def __init__(self, parent=None):
super().__init__(parent)
self.myData= [
'id': '01',
'name': 'test1',
,
'id': '02',
'name': 'test2',
]
def data(self, index, role=Qt.DisplayRole):
row = index.row()
if role == MyList._myCol1:
return self.myData[row]['id']
if role == MyList._myCol2:
return self.myData[row]['name']
def rowCount(self, parent=QModelIndex()):
return len(self.myData)
def roleNames(self):
return
MyList._myCol1: b'id',
MyList._myCol2: b'name'
def get(self, index):
# How to implement this?
以上代码工作正常,并通过QQmlApplicationEngine
和rootContext().setContextProperty(...)
将列表从python 公开到QML(我使用how to insert/edit QAbstractListModel in python and qml updates automatically? 的答案和Qt for Python 文档作为方向)。
如果使用 QML ListModel
,我可以使用文档 https://doc.qt.io/qt-5/qml-qtqml-models-listmodel.html 中描述的 object get(index)
函数。然而:
-
如何从 QML 访问实例化的 MyList 中的特定元素,如果它是原生 QML ListModel,我将使用
get(index)
方法访问该元素?
如何实现get(index)
方法?
我仍在寻找并期待一个涉及 python 和 QML 的解决方案。 感谢您的帮助!
【问题讨论】:
【参考方案1】:只有某些类型的变量可以导出到 QML,其中包括 str、int、float、list,但在字典的情况下,它必须导出为 QVariant。
另一方面,如果你想从 QML 访问一个方法,那么如果你使用 PyQt5 或 PySide2,则必须分别使用 @pyqtSlot 或 @Slot 装饰器,指示在这种情况下为 int 和结果参数的输出类型。
main.py
from PySide2 import QtCore, QtGui, QtQml
class MyList(QtCore.QAbstractListModel):
col1 = QtCore.Qt.UserRole + 1
col2 = QtCore.Qt.UserRole + 2
def __init__(self, parent=None):
super().__init__(parent)
self.myData = ["id": "01", "name": "test1",, "id": "02", "name": "test2",]
def data(self, index, role=QtCore.Qt.DisplayRole):
row = index.row()
if index.isValid() and 0 <= row < self.rowCount():
if role == MyList.col1:
return self.myData[row]["id"]
if role == MyList.col2:
return self.myData[row]["name"]
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.myData)
def roleNames(self):
return MyList.col1: b"id", MyList.col2: b"name"
@QtCore.Slot(int, result='QVariant')
def get(self, row):
if 0 <= row < self.rowCount():
return self.myData[row]
if __name__ == "__main__":
import os
import sys
app = QtGui.QGuiApplication(sys.argv)
current_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)))
qml_file = os.path.join(current_dir, "main.qml")
model = MyList()
engine = QtQml.QQmlApplicationEngine()
engine.rootContext().setContextProperty("listmodel", model)
engine.load(QtCore.QUrl.fromLocalFile(qml_file))
sys.exit(app.exec_())
main.qml
import QtQuick 2.13
import QtQuick.Controls 2.13
ApplicationWindow
id: root
visible: true
width: 640
height: 480
ListView
id: view
anchors.fill: parent
model: listmodel
delegate: Text
text: model.id + " " + model.name
Component.onCompleted:
var obj = listmodel.get(0)
console.log(obj["id"])
console.log(obj["name"])
输出:
qml: 01
qml: test1
加:
只有一些基本类型被直接接受,而 dict 不是这种情况,在这些情况下,您可以使用 QVariant 和 QVariantList(用于列表或元组),但在 PySide2 中没有 QVariant,因此您可以在C++ 通过将它们作为字符串传递:“QVariant”。 docs 中表示的内容:
QVariant
由于 QVariant 被移除,任何期待它的函数 可以接收任何 Python 对象(None 是无效的 QVariant)。相同 返回某些东西时规则是有效的:返回的 QVariant 将是 转换为其原始的 Python 对象类型。当方法需要 QVariant::Type 时,程序员可以使用 字符串(类型名称)或类型本身。
(强调我的)
【讨论】:
感谢您的快速回答!正如您在使用 PySide2 时指出的那样,我必须使用 Qt.Core.Slot 作为装饰器。但我的问题是 PySide2 中没有 QVariant 类型。在link“PySide 仅支持 PyQt 的“API 2”(PSEP 101)”下,我发现应该使用原生 python 类型。但是,如果我将result=dict
用于get
函数装饰器,我将无法像您那样访问该角色。使用您的代码 get
将在 qml 中返回 QVariant(PySide::PyObjectWrapper, )
作为 obj
。
好的。我发现,我必须按如下方式实现get
装饰器的result
关键字(至少对于PySide2):result='QVariant'
(在这里找到:link)但我不知道为什么要这样做.我会很感激一些解释。顺便说一句,官方“Qt for Python”文档中的任何地方都有记录吗?直到现在,我发现它们并不是很有用。
@BeCurious 当您意识到答案取决于绑定时:PyQt5 或 PySide2 所以对于下一个问题,您必须清楚地指出以避免混淆。查看我的更新。以上是关于使用 QAbstractListModel 从 python 访问 QML 中的列表元素的主要内容,如果未能解决你的问题,请参考以下文章
从 QAbstractListModel 继承的列表模型,列表项属性不会从 QML 更新
什么是最适合 QAbstractListModel 和 QListView 的 Qt 容器
为 QML ListView 实现 QAbstractListModel 子类?