Declaratively create items for use in models exported to QML.
See also
Traditionally, data is exposed to QML through the use of roles. Each role represents a number and associated name, the name is used from QML and it's equivalent role is used for lookup in the QAbstract*Model.
app.qml
Text {
text: name // String-equivalent of role
}
app.py
class Model(QtCore.QAbstractListModel):
def __init__(self, parent=None):
super(Model, self).__init__(self, parent)
self.items = [{"name": "Marcus"}, {"name": "Lukas"}]
def data(self, index, role):
key = self.roleNames()[role]
return self.items[index.row()][key]
def roleNames(self):
return {QtCore.Qt.UserRole: "name"}
The problem:
- Roles are implementation detail
- Keys are duplicated both in
roleNames
and each item declaration
The model could potentially look like this, without interfering with it's interface towards QML.
class Model(QtCore.QAbstractListModel):
def __init__(self, parent=None):
super(Model, self).__init__(self, parent)
self.items = [{"name": "Marcus"}, {"name": "Lukas"}]
def data(self, index, role):
return self.items[index.row()][role]
Another disadvantage (debatable) of exposing data via roles is the lack of namespaces in their usage.
app.qml
Text {
text: name // No namespace
}
No namespace adds cognintive load in that it is easily mistaken for scope variables.
In this implementation, only a single role is exposed to QML - item
. Each data member is then accessible via item
, making item
effectively into a namespace whilst allowing a single implementation of a model to be reused with an arbitrary amount of implementations for items.
app.py
class CustomItem(AbstractItem):
name = str
age = int
item = CustomItem(name="Marcus", age=10)
app.qml
Text {
text: item.name
}
- QML Bindings are made to each item as opposed to the model, which may decrease performance in large models.
- Model items may be destroyed, causing errors such as
RuntimeError: wrapped C/C++ object of type Item has been deleted
Make sure to explicitly assign the model as parent to your QObjects such that they get properly garbage collected.
- dataChanged not emitted when data changes. Other objects such as QSortFilterProxyModel relies on this signal to invalidate itself.
A workaround is to emit this signal explicitly in your items.
See also