Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

[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 and Model_B
    There are 2 corresponding delegates which render the entries of the above models: Delegate_A and Delegate_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 and Model_B.

    The filtering is implemented in QAbstractItemModel::getData() and the elements are exposed through a reimplementation of QAbstractItemModel::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 invoking emit 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.