[Solved] Nested QtQuick delegates based on C++ model
-
Hello everyone! I have developed an application in QML/QtQuick and I see that I need a more complex C++ based model.
I have successfully transitioned many views/delegates to base upon the C++ model but this one delegate which contains another delegate causes some issues. The situation is as follows.
There are 2 cpp based models:
Model_A
andModel_B
There are 2 corresponding delegates which render the entries of the above models:Delegate_A
andDelegate_B
Delegate_A
something like this:Rectangle { // some rendering of Model_A Repeater { delegate: Delegate_B{} model: { // some logic in JS which filters Model_B to get an entry } } }
The idea here is to recycle
Delegate_B
and if there are changes to change only this delegate to affect the whole visualization.Porting
Model_B
to C++ (QStandardItemModel derived) the filtering code broke. That is ok in the sense that QStandardItemModel and QML::ListModel have different manipulation interfaces an this can be addressed with some custom code.The real problem is how to have a Q_INVOKABLE method that returns something that QML can use as a model in the repeater. Ideally it would also be changed if a change to
Model_B
happens.Thanks in advance
-
I eventually found a solution/workaround to the problem. I am posting it here if anybody ever needs it.
The main issue it seems is wanting to filter the C++ model in QML/JavaScript. Getting elements out of the C++ model into QML seems to be possible as a returning a QVariantMap maps to a JS object in the QML engine. Using this returned object as a model proved not to work directly. This might work with further effort but due to time constraints this approach was abandoned.
The new approach was to create a C++ model derived from QAbstractItemModel and reimplementing the necessary functions. This model is essentially a filtering proxy for
Model_A
andModel_B
.The filtering is implemented in
QAbstractItemModel::getData()
and the elements are exposed through a reimplementation ofQAbstractItemModel::roleNames()
.For this filtering proxy to change state when the underlying data changes the
dataChanged()
signals of the underlying models was connected to a method in the proxy model computing the correct index invokingemit dataChanged(index)
.The QML delegate reuse was then implemented as follows:
Rectangle { // some rendering of Model_A Repeater { delegate: Delegate_B{} model: Item{ property var propertyDelegateB: model.propertyDelegateB // mulitple properties possible } } }
This worked for my use case as I needed only one element in the model. For multiple elements this approach might not be ideal.