使用QAbstractListModel

时间:2019-11-24 23:03:54

标签: python qml pyside2

我是Qt的初学者,我通过以下方式创建应用程序:

  1. 将QML用于View设计,
  2. 主要在控制器和模型部分使用python。

因此,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?

上面的代码工作正常,并且通过QQmlApplicationEnginerootContext().setContextProperty(...)将列表从python公开到QML(我使用了how to insert/edit QAbstractListModel in python and qml updates automatically?和Python文档的Qt的答案作为方向)

如果使用QML ListModel,则可以使用文档https://doc.qt.io/qt-5/qml-qtqml-models-listmodel.html中所述的object get(index)函数。但是:

  1. 如何从QML访问实例化的MyList中的特定元素,就像如果它是本地QML ListModel那样,我将使用get(index)方法来执行此元素一样?
  2. 如何实现get(index)方法?

我仍在寻找并期望有一个有关python和QML的解决方案。 谢谢您的帮助!

1 个答案:

答案 0 :(得分: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对象(没有一个是无效的QVariant)。相同   返回某条规则时有效:返回的QVariant将是   转换为其原始Python对象类型。

     

当方法需要QVariant :: Type时,程序员可以使用   字符串(类型名称)或类型本身。

(重点是我的)