Search code examples
c++qtqmlrepeater

QML Repeater removes all delegate items and regenerates them again when model changes


By changing the model (adding or subtracting or editing a member of the model), the repeater removes all the created items (delegates) and rebuilds them again. For heavy models, this is a big problem.

How can I change the repeater, so that instead of removing all delegates, it only deletes the item related to the deleted member, and when a member is added, it creates only the item related to it, and in case of editing a member of the model, only that member is removed and recreated.

I studied the code related to the Repeater, but due to the use of private methods and classes in its source, I cannot reimplement it.

You can test the problem with the bellow code:

import QtQuick
import QtQuick.Controls
        
Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("Ronia Components")

    property var repeatreModel: [1, 2]

    Timer {
        interval: 2000
    running: true
    repeat: true

    property int count: 0
    onTriggered: {
             count++;

             // Add an item into ,odel
             repeatreModel.push(count);
    }

}

Column {
        anchors.fill: parent

    Repeater {
        id: repeater
        model: repeatreModel
        clip: true

        onItemRemoved: (item, index) => {
                         console.log("Remove : (item, index) ", item, index)
                       }

        onItemAdded: (item, index) => {
                      console.log("Add : (item, index) = ", item, index)
                     }

        delegate: Rectangle {

            width: 50
            height: 40

            Text {
                id: name
                anchors.centerIn: parent
                text: modelData
            }
        }

        onModelChanged: console.log("modelChanged")

        }
    }
}

Solution

  • SMR said:

    Integer and JavaScript array models are read-only 1. Therefore, you cannot update the model, and any changes will recreate all of your instances. You should use ListModel instead.

    Based on that, I figured out one of the possible solutions:

     import QtQuick
     import QtQuick.Controls
        
        Window {
            width: 640
            height: 480
            visible: true
            title: qsTr("Ronia Components")
        
            Timer {
                interval: 2000
                running: true
                repeat: true
        
                property int count: 0
                onTriggered: {
                    count++;
                    listModel.append({"counter": count, "counter2": count*10})
                }
        
            }
        
            ListModel {
                id: listModel
            }
        
            Repeater {
                id: repeater
        
                model: listModel
                clip: true
        
                onItemRemoved: (item, index) => {
                                   console.log("onItemRemoved: = ", item, index)
                               }
        
                onItemAdded: (item, index) => {
                                 console.log("item, index = ", item, index)
                             }
        
                delegate: Rectangle {
        
                    x: counter + 2
                    y: counter2 + 20
                    width: 20
                    height: 20
        
                    Text {
                        id: name
                        anchors.centerIn: parent
                        text: counter2  + counter
                    }
                }
        
                onModelChanged: console.log("modelChanged")
        
            }
        }
    

    Note:

    I do not to want change the model, because my model is used a lot in the software, and needs drastic changes.