如何在python和qml更新中自动插入/编辑QAbstractListModel?

如何在python和qml更新中自动插入/编辑QAbstractListModel?

问题描述:


我想插入/编辑一个python列表,这是从QAbstractListModel pyqt5中subclassed。这个python列表是在qml中的ListView元素的model属性中读取的。我没有问题在qml中显示数据。当我尝试将新数据追加到python列表中时出现问题。如何在python和qml更新中自动插入/编辑QAbstractListModel?

以下是我迄今所做的:

main.py:

import sys, model2 
from PyQt5.QtCore import QUrl 
from PyQt5.QtWidgets import QApplication 
from PyQt5.QtQuick import QQuickView 

class MainWindow(QQuickView): 
    def __init__(self, parent=None): 
     super().__init__(parent) 

     self.model = model2.PersonModel() 
     self.rootContext().setContextProperty('PersonModel', self.model) 
     self.rootContext().setContextProperty('MainWindow', self) 
     self.setSource(QUrl('test2.qml')) 

myApp = QApplication(sys.argv) 
ui = MainWindow() 
ui.show() 
sys.exit(myApp.exec_()) 

model2.py

from PyQt5.QtCore import QAbstractListModel, Qt, pyqtSignal, pyqtSlot 

class PersonModel(QAbstractListModel): 

    Name = Qt.UserRole + 1 
    Age = Qt.UserRole + 2 

    personChanged = pyqtSignal() 

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

    def data(self, QModelIndex, role): 
     row = QModelIndex.row() 
     if role == self.Name: 
      return self.persons[row]["name"] 
     if role == self.Age: 
      return self.persons[row]["age"] 

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

    def roleNames(self): 
     return { 
      Qt.UserRole + 1: b'name', 
      Qt.UserRole + 2: b'age' 
     } 

    @pyqtSlot() 
    def addData(self): 
     self.beginResetModel() 
     self.persons = self.persons.append({'name': 'peter', 'age': 22}) 
     self.endResetModel() 
     print(self.persons) 

    @pyqtSlot() 
    def editData(self): 
     print(self.model.persons) 

test2.qml:

import QtQuick 2.6 
import QtQuick.Controls 2.2 

Rectangle { 
    anchors.fill: parent 
    color: "lightgrey" 

    ListView { 
     id: listExample 
     anchors.fill: parent 
     model: PersonModel 
     delegate: Text { 
      text: name + " " + age 
     } 
    } 

    Button { 
     width: 50 
     height: 25 
     anchors.bottom: parent.bottom 
     text: "add" 
     onClicked: { 
      console.log("qml adding") 
      PersonModel.addData() 
     } 
    } 

    . 
    . 
    . 
} 

当我点击添加bu时发生错误tton在model2.py中调用addData方法。错误在于rowCount,错误消息是TypeError: object of type 'NoneType' has no len()。我是否必须发布更改或传递某些索引和角色值,以便qml知道新/旧是什么,并且只反映相应的更改?

任何形式的指导非常感谢!

你得到的错误是由下面的代码行造成的:

self.persons = self.persons.append({'name': 'peter', 'age': 22}) 

这是因为附加功能不返回任何东西造成的,所以它是为了分配给无self.persons

要插入新数据,您必须致电beginInsertRows()endInsertRows()以通知更改的视图。

的数据的方法必须是完全相同的文档中示出,即,它必须具有以下格式:

def data(self, index, role=Qt.DisplayRole): 

与根据rowCount方法相同的:

def rowCount(self, parent=QModelIndex()): 

我已经实现了方法addPerson,editPerson和deletePerson分别添加,编辑和删除列表中的数据。此外,我将必要的项目添加到.qml以便能够测试它。

model2.py

from PyQt5.QtCore import QAbstractListModel, Qt, pyqtSignal, pyqtSlot, QModelIndex  

class PersonModel(QAbstractListModel): 

    NameRole = Qt.UserRole + 1 
    AgeRole = Qt.UserRole + 2 

    personChanged = pyqtSignal() 

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

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

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

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

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

    @pyqtSlot(int, str, int) 
    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()) 

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

test2.qml

import QtQuick 2.6 
import QtQuick.Controls 2.2 

Rectangle { 
    anchors.fill: parent 
    color: "lightgrey" 

    ListView { 
     id: listExample 
     anchors.fill: parent 
     model: PersonModel 
     delegate: 
      Item { 
      width: 200 
      height: 60 
      Row { 
       Text { 
        width: 60 
        text: name + " " + age 
        horizontalAlignment: Text.AlignHCenter 
        anchors.verticalCenter: parent.verticalCenter 
       } 
       Button{ 
        width: 20 
        text: "+" 
        onClicked: PersonModel.editPerson(index, name, age+1) 
       } 
       Button{ 
        width: 20 
        text: "-" 
        onClicked: PersonModel.editPerson(index, name, age-1) 
       } 
       Button{ 
        width: 20 
        text: "X" 
        onClicked: PersonModel.deletePerson(index) 
       } 
      } 
     } 
    } 

    Button { 
     width: 50 
     height: 25 
     anchors.bottom: parent.bottom 
     anchors.right: parent.right 
     text: "add" 
     onClicked: { 
      console.log("qml adding") 
      PersonModel.addPerson("luis", 22) 
     } 
    } 
} 

编辑:

的.py

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

。qml

PersonModel.insertPerson(2, "luis", 1111) 
+0

hey eyllanesc!感谢您再次回答我对pyqt5和qml的问题!我试图玩弄'beginInsertRows'方法的第二和第三参数,但我似乎无法将新添加的数据插入jon和jane之间。应该怎么做?哦,顺便说一句,你碰巧知道pyqt5和qml上的任何资源? – eugeneoei

+0

@eugeneoei好的,稍后我会创建一个插入方法。第二点没有官方文档,实际上PyQt的官方文档指向Qt的文档,所以如果你知道C++的最少部分,你可以理解它。请不要忘记标记我的答案是正确的。 – eyllanesc

+0

酷!我知道我现在出了什么问题。试图将字典追加到列表中的特定位置。那绝对不行。 python仍然很新。至少我现在知道了。感谢eyllanesc! – eugeneoei