Reputation: 519
I have a simple StudentListModel class that implements QAbstractListModel.
class StudentListModel(QAbstractListModel):
NAME = Qt.UserRole + 1
AGE = Qt.UserRole + 2
def __init__(self, students):
super().__init__()
self.students = students
def roleNames(self):
return {
StudentListModel.NAME: b'name',
StudentListModel.AGE: b'age',
}
def rowCount(self, parent=None, *args, **kwargs):
return len(self.students)
def data(self, QModelIndex, role=None):
row = self.students[QModelIndex.row()]
if role == StudentListModel.NAME:
return row["name"]
elif role == StudentListModel.AGE:
return row["age"]
return None
def remove(self, index):
self.students.pop(index)
StudentListModel is passed to the QML file. The QML will display the models entries.
import QtQuick 2.15
import QtQuick.Controls 2.15
Rectangle {
id: container
signal remove(int index)
Column {
spacing: 15
Repeater {
model: studentListModel
Row {
spacing: 10
Text {
text: model.name
}
Button {
text: "Remove"
onClicked: container.remove(index)
}
}
}
}
}
The code that connects the QML with StudentListModel is represented here:
def main():
students = [
{"name": "Vitaliy ", "age": "21"},
{"name": "Eugene", "age": "26"},
{"name": "Tommy", "age": "26"}
]
model = StudentListModel(students)
app = QApplication(sys.argv)
widget = QQuickWidget()
widget.setSource(QUrl('stack.qml'))
widget.rootContext().setContextProperty('studentListModel', model)
widget.rootObject().remove.connect(lambda index: model.remove(index))
widget.setGeometry(0, 0, 320, 800)
widget.show()
return app.exec_()
if __name__ == '__main__':
sys.exit(main())
And here is the screenshot of the app in action:
There is no problems with displaying the model entries in the QML. The problem is when I want to remove an entry. When I click remove, the QML gets the index of the clicked entry and send a signal. The main() block will handle the signal emmittion via lambda function. Lambda function will receive the index, and will call the remove method from the model by passing the received index. After this the model will remove the entry, however QML doesn't display the updated model. Is there a way how to sync the model with QML, so that when an entry is removed, it is removed in the QML as well ?
Upvotes: 0
Views: 98
Reputation: 243983
You have to call the beginRemoveRows and endRemoveRows methods before and after the removal, respectively:
class StudentListModel(QAbstractListModel):
NAME = Qt.UserRole + 1
AGE = Qt.UserRole + 2
def __init__(self, students):
super().__init__()
self.students = students
def roleNames(self):
return {
StudentListModel.NAME: b"name",
StudentListModel.AGE: b"age",
}
def rowCount(self, parent=QModelIndex()):
return len(self.students)
def data(self, index, role=Qt.DisplayRole):
row = self.students[index.row()]
if role == StudentListModel.NAME:
return row["name"]
elif role == StudentListModel.AGE:
return row["age"]
def remove(self, index):
self.beginRemoveRows(QModelIndex(), index, index)
self.students.pop(index)
self.endRemoveRows()
Upvotes: 1