使用 QAbstractListModel 从 python 访问 QML 中的列表元素
Access list element in QML from python using the QAbstractListModel
我是 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(我使用了 和 Qt 的答案用于 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 的解决方案。
感谢您的帮助!
只有一些类型的变量可以导出到 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
As QVariant was removed, any function expecting it
can receive any Python object (None is an invalid QVariant). The same
rule is valid when returning something: the returned QVariant will be
converted to the its original Python object type.
When a method expects a QVariant::Type the programmer can use a
string (the type name) or the type itself.
(强调我的)
我是 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(我使用了
如果使用 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 的解决方案。 感谢您的帮助!
只有一些类型的变量可以导出到 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
As QVariant was removed, any function expecting it can receive any Python object (None is an invalid QVariant). The same rule is valid when returning something: the returned QVariant will be converted to the its original Python object type.When a method expects a QVariant::Type the programmer can use a string (the type name) or the type itself.
(强调我的)