Insert into ListView with Loader
-
Hi!
I'm a newbie to QML and have encountered some strange behaviour (at least to me).I have a ListView with a Loader as a delegate. The Loader loads component using a switch statement based on a name role in the model (the model is a sub-class of QAbstractListModel). So far so good. I can insert new items at the end of the list and they show up using the correct component definition. I can also remove elements and everything works fine. However if I try to insert a element before the last element the component gets created using the wrong component definition, it becomes the same as the last element (except when inserting the first elements, which is very strange).
Minimal example that always inserts before the last element. The rows that were inserted before app start work, but the rows inserted with the timer all become blue.
test.qmlimport QtQuick 2.11 import QtQuick.Window 2.2 import QtQuick.Controls 2.2 ApplicationWindow { visible: true width: 640 height: 480 ListView { model: provider.model anchors.fill: parent delegate: Loader { width: parent.width sourceComponent: switch(NameRole){ case 'red': return red break; case 'blue': return blue break; case 'green': return green break; } } } Component { id:red Rectangle { width: 100 height: 100 color: 'red' } } Component { id:blue Rectangle { width: 100 height: 100 color: 'blue' } } Component { id:green Rectangle { width: 100 height: 100 color: 'green' } } }
import sys from functools import partial from PySide2.QtGui import QGuiApplication from PySide2.QtCore import Slot, QObject, Property, QAbstractListModel from PySide2 import QtCore from PySide2.QtQml import QQmlApplicationEngine class RuleModel(QAbstractListModel): NameRole = QtCore.Qt.UserRole + 1001 def __init__(self, parent=None): super(RuleModel, self).__init__(parent) self._entries = [] def rowCount(self, parent=QtCore.QModelIndex()): if parent.isValid(): return 0 return len(self._entries) def data(self, index, role=QtCore.Qt.DisplayRole): if 0 <= index.row() < self.rowCount() and index.isValid(): item = self._entries[index.row()] if role == RuleModel.NameRole: return item['NameRole'] def roleNames(self): roles = dict() roles[RuleModel.NameRole] = b'NameRole' return roles def appendRow(self, name): self.beginInsertRows(QtCore.QModelIndex(), self.rowCount(), self.rowCount()) self._entries.insert(self.rowCount()-1, dict(NameRole=name)) self.endInsertRows() class ModelProvider(QObject): def __init__(self, parent=None): super(ModelProvider, self).__init__(parent) self._model = RuleModel() @Property(QObject, constant=False) def model(self): return self._model @Slot() def append(self, name): self.model.appendRow('a') def insert_brg(model): model.appendRow('blue') model.appendRow('red') model.appendRow('green') model.appendRow('green') def green(model): model.appendRow('green') if __name__ == '__main__': app = QGuiApplication(sys.argv) provider = ModelProvider() engine = QQmlApplicationEngine() engine.rootContext().setContextProperty("provider", provider) engine.load('test.qml') if not engine.rootObjects(): sys.exit(-1) insert_brg(provider.model) timer = QtCore.QTimer(interval=500) timer.timeout.connect(partial(green, provider.model)) timer.start() sys.exit(app.exec_())
-
Ah, I found the problem. I was telling beginInserRows I was going to insert at the end and then not inserting at the end. Telling it the right place solved the problem.