【问题标题】:how to insert/edit QAbstractListModel in python and qml updates automatically?如何在 python 和 qml 中自动插入/编辑 QAbstractListModel 更新?
【发布时间】:2018-03-30 14:38:29
【问题描述】:

我正在尝试插入/编辑一个从 pyqt5 中的QAbstractListModel 子类化的 python 列表。这个 python 列表是在 qml 中 ListView 元素的 model 属性中读取的。我在 qml 中显示数据没有问题。当我尝试将新数据附加到 python 列表中时出现问题。

以下是我目前所做的:

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()
        }
    }

    .
    .
    .
}

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

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

【问题讨论】:

    标签: python pyqt qml pyqt5 qabstractlistmodel


    【解决方案1】:

    也许这是个错误:

    self.dataChanged.emit(ix, ix, self.roleNames())
    

    毕竟信号已经公布了:

    personChanged = pyqtSignal()
    

    也就是说,应该是:

    self.personChanged.emit(ix, ix, self.roleNames())
    

    【讨论】:

      【解决方案2】:

      您得到的错误是由以下代码行引起的:

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

      这是因为 append 函数没有返回任何内容,所以它是为了将 None 分配给 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)
      

      【讨论】:

      • 嘿 eyllanesc!感谢您再次回复我关于 pyqt5 和 qml 的问题!我试图使用beginInsertRows 方法的第二个和第三个参数,但我似乎无法在 jon 和 jane 之间插入新添加的数据。那应该怎么做?哦对了,你知道pyqt5和qml的资源吗?
      • @eugeneoei 好的,稍后我将创建一个插入方法。第二点没有官方文档,实际上PyQt的官方文档指向了Qt的文档,所以如果你对C++了解的最少,你就可以理解它。请不要忘记将我的答案标记为正确。
      • 酷!我现在知道我哪里出错了。试图将字典附加到列表中的特定位置。那肯定行不通。对python来说还是很新的。至少我现在知道了。谢谢eyllanesc!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-12-03
      • 2023-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多