将对象列表从pyqt5传递给qml将返回undefined

时间:2017-10-23 15:28:02

标签: python qt qml pyqt5

我想将pyqt5中的字典列表传递给qml,其中此列表成为model元素的ListView。以下代码是我目前所拥有的。

main.py

class MainWindow(QQuickView):

    def __init__(self, parent=None):
        super().__init__(parent)
        self.model = model.PersonModel()
        self.rootContext().setContextProperty('PersonModel', self.model)
        self.rootContext().setContextProperty('MainWindow', self)
        self.setSource(QUrl('main.qml'))

    @pyqtSlot()
    def personsList(self):
        print(self.model.persons) # this prints the list of objects perfectly fine
        return(self.model.persons)
        .
        .
        .

main.qml

ListView {
    id: listExample
    anchors.fill: parent
    model: MainWindow.personsList()
    delegate: PersonDelegate { }
    highlight: highlightComponent
    highlightMoveDuration: 0
    Component.onCompleted: {
        console.log(">>>", MainWindow.personsList()) // returns undefined, but why??
    }
}

model.py

from PyQt5.QtCore import QAbstractListModel, Qt, QModelIndex 

class PersonModel(QAbstractListModel):

    NAME_ROLE = Qt.UserRole + 1
    AGE_ROLE = Qt.UserRole + 2

    def __init__(self, parent=None):
        super().__init__(parent)
        self.persons = [
            {'name': 'jon', 'age': 20},
            {'name': 'jane', 'age': 25},
            {'name': 'pete', 'age': 25},
            {'name': 'winson', 'age': 25},
            {'name': 'ben', 'age': 25},
            {'name': 'jiahao', 'age': 25}            
        ]

        self.currentIndex = 0

    def data(self, index, role=Qt.DisplayRole):
        row = index.row()
        if role == PersonModel.NAME_ROLE:
            return self.persons[row]["name"]
        if role == PersonModel.AGE_ROLE:
            return self.persons[row]["age"]

    def rowCount(self, parent=QModelIndex()):
        return len(self.persons)

    def roleNames(self):
        return {
            PersonModel.NAME_ROLE: b'name',
            PersonModel.AGE_ROLE: b'age'
        }

    def updateIndex(self, int):
        self.currentIndex = int
        print("updating index from click", self.currentIndex)

    def addPerson(self, name, age):
        self.beginInsertRows(QModelIndex(), self.rowCount(), self.rowCount())
        self.persons.append({'name': name, 'age': age})
        self.endInsertRows()

    def insertPerson(self, row, name, age):
        self.beginInsertRows(QModelIndex(), row, row)
        self.persons.insert(row, {'name': name, 'age': age})
        self.endInsertRows()

    def editPerson(self, row, name, age):
        ix = self.index(row, 0)
        self.persons[row] = {'name': name, 'age': age}
        self.dataChanged.emit(ix, ix, self.roleNames())

    def deletePerson(self, row):
        self.beginRemoveColumns(QModelIndex(), row, row)
        del self.persons[row]
        self.endRemoveRows()

为什么人员列表在qml中返回undefined?

如果有人想知道,我正在尝试创建一个模型类,我可以通过传递任何字典列表来实例化,并将此列表用作不同model元素中的ListView属性。在这个模型类中,我有addinserteditdelete,我可以在所有实例中一致使用,从而避免重复。

此外,我正在尝试将模型与视图分开,以便数据流是一种方式,即qml通知python任何用户交互,model中的所有更改都将在python上处理每当model更改时,哪个qml会相应更改。

2 个答案:

答案 0 :(得分:1)

在Qt中有Q_INVOKABLE宏启用并注册该函数,以便可以在QML中使用它,在PyQt中它的等价物是pyqtSlot(),我们必须告诉你它通过result参数返回什么类型的数据。

@pyqtSlot(result=list)
def personsList(self):
    print(self.model.persons)
    return self.model.persons

在QML代码中观察到的错误是您作为模型传递给ListView的对象列表而不是模型:

import QtQuick 2.6

ListView {
    id: listExample
    anchors.fill: parent
    model: PersonModel
    delegate: Text{
        text: name
    }
    highlightMoveDuration: 0
    Component.onCompleted: {
        console.log(">>>", MainWindow.personsList()) // returns undefined, but why??
        var l = MainWindow.personsList();
        for(var counter in l){
            console.log(l[counter]['name'] + ": " + l[counter]['age'])
        }
    }
}

输出:

[{'name': 'jon', 'age': 20}, {'name': 'jane', 'age': 25}]
qml: >>> [[object Object],[object Object]]
[{'name': 'jon', 'age': 20}, {'name': 'jane', 'age': 25}]
qml: jon: 20
qml: jane: 25

答案 1 :(得分:0)

我在MeeGo手机中,仅限import QtQuick 1.0,并且一直试图通过Slot将python对象(列表,词典,元组)发送到用qml编写的用户界面:

@Slot(str, result=list)

qml结束时我一直在尝试这个:

var l = app.get_taxonomic_derivation(lookup_text.text)
print (l)
print (l.length)

我得到的只是:

QVariant(PySide::PyObjectWrapper)
undefined

我没有设法转换成列表,不知道如何。

我最终使用json,在客户端使用eval

@Slot(str, result=str)
def get_taxonomic_derivation(self, epithet):
    ....
    return json.dumps(result)