如何 insert/edit QAbstractListModel in python 和 qml 自动更新?
how to insert/edit QAbstractListModel in python and qml updates automatically?
我正在尝试 insert/edit 一个 python 列表,它是 pyqt5 中 QAbstractListModel
的子类。此 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 知道什么是 new/old 并仅相应地反映更改?
非常感谢任何形式的指导!
您得到的错误是由以下代码行引起的:
self.persons = self.persons.append({'name': 'peter', 'age': 22})
是因为append函数没有return任何东西,所以本来是想把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)
也许这是一个错误:
self.dataChanged.emit(ix, ix, self.roleNames())
毕竟信号公布了:
personChanged = pyqtSignal()
即应该是:
self.personChanged.emit(ix, ix, self.roleNames())
我正在尝试 insert/edit 一个 python 列表,它是 pyqt5 中 QAbstractListModel
的子类。此 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 知道什么是 new/old 并仅相应地反映更改?
非常感谢任何形式的指导!
您得到的错误是由以下代码行引起的:
self.persons = self.persons.append({'name': 'peter', 'age': 22})
是因为append函数没有return任何东西,所以本来是想把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)
也许这是一个错误:
self.dataChanged.emit(ix, ix, self.roleNames())
毕竟信号公布了:
personChanged = pyqtSignal()
即应该是:
self.personChanged.emit(ix, ix, self.roleNames())