So I have this idea of using Q_PROPERTY
s of QObjects instead of role names of QAbstractListModel
to have notifiable properties be exposed to QML.
My question is if this a good practice, because it feels a bit unatural for using with classes inherited from QAbstractItemModel
.
Let me explain this in a more detail.
So, recommended way of creating C++ model for QML is:
- Inherit
QAbstractListModel
(or others) for creating your custom model. - Overload
rowCount()
- Define your own data roles.
e.g:
enum DataRoles {
Name = Qt::UserRole + 1,
Description,
CustomData
};
...
QHash<int, QByteArray> TestList::roleNames() const
{
QHash<int, QByteArray> res;
res[static_cast<int>(DataRoles::Name)] = "name";
res[static_cast<int>(DataRoles::Description)] = "description";
res[static_cast<int>(DataRoles::CustomData)] = "customData";
return res;
}
- Return corresponding data in overloaded
data()
member function.
e.g.:
QVariant TestList::data(const QModelIndex & index, int role) const
{
QVariant result = QVariant();
if ( index.isValid() == true ) {
EntityPtr entityPtr = entities_.at(index.row());
switch (role) {
case DataRoles::Name:
result = entityPtr->name();
break;
case DataRoles::Description:
result = entityPtr->description();
break;
case DataRoles::CustomData:
result = entityPtr->customData();
break;
}
}
return result;
}
Than, after registering your model instance in QML's context, you can access entity fields in the ListView delegate by name, defined in rolesNames(), e.g.:
ListView {
model: yourModelInstance
...
delegate: Item {
...
Text {
text: name // access DataRoles::Name
}
...
}
}
IMO, this implementation is all good, but when it comes to changing properties from C++ side, you should call dataChaged() signal of QAbstractListView
on each change of entity's property.
And I want to be able to automatically inform view about changes, e.g. when I'm calling entity->setName()
.
What I have in mind is to register only one data role, e.g. "object" which will return whole QObject, which will have Q_PROPERTY
s and then access it from qml like:
Text {
text: object.name //access `name` Q_PROPERTY of the object
}
This way, if setters will emit right signals, registered in Q_PROPERTY declaration, QML side will be automatically informed about changes on setting new value.
So the question is, if this is a good way for achieving my goal, because, as I've said above, it feels a bit unnatural, and Qt library is a good in indicating that you are doing something wrong by making it hard (unnatural) to do wrong things.
EDIT:
As was requested in the comments, I've made a small Qt example app showing what I want to achieve.