[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.



Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.