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

567 Views Asked by At

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")

        }
    }
}
2

There are 2 best solutions below

0
Mohsen Kondori On BEST ANSWER

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.

1
Tassos On

Don't use Repeater for large models. Prefer ListView or similar items (TreeView, TableView). Quote from Qt's documentation:

Considerations when using Repeater

The Repeater type creates all of its delegate items when the repeater is first created. This can be inefficient if there are a large number of delegate items and not all of the items are required to be visible at the same time. If this is the case, consider using other view types like ListView (which only creates delegate items when they are scrolled into view) or use the Dynamic Object Creation methods to create items as they are required.