QML Repeater在模型更改时会删除所有委托项目,然后重新生成它们。

huangapple go评论65阅读模式
英文:

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

问题

以下是您提供的文本的中文翻译:

通过更改模型(添加、删除或编辑模型的成员),重复器会移除所有已创建的项(代理),然后重新构建它们。对于大型模型来说,这是一个大问题。

我应该如何更改重复器,以便它不是移除所有代理,而是只删除与已删除成员相关的项,并在添加成员时仅创建与之相关的项,在编辑模型的成员时只删除并重新创建该成员。

我已经研究了与[Repeater](https://codebrowser.dev/qt5/qtdeclarative/src/quick/items/qquickrepeater.cpp.html#_ZN14QQuickRepeaterC1EP10QQuickItem)相关的代码,但由于其源代码中使用了私有方法和类,我无法重新实现它。

您可以使用下面的代码测试这个问题:

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

请注意,这只是您提供的代码的中文翻译部分。如果您需要进一步的帮助或解释,请告诉我。

英文:

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

        }
    }
}

答案1

得分: 0

不要为大型模型使用Repeater。更倾向于使用ListView或类似的项目(TreeView、TableView)。

引用自Qt的文档

在使用Repeater时要考虑的事项

Repeater类型在创建时会同时创建所有的委托项目。如果有大量的委托项目,并且并非所有项目都需要同时可见,这可能会效率低下。如果情况如此,考虑使用其他视图类型,如ListView(仅在它们滚动到视图中时才创建委托项目),或者使用动态对象创建方法在需要时创建项目。

英文:

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.

答案2

得分: 0

SMR 说:

> Integer 和 JavaScript 数组模型是只读的 1。因此,您无法更新模型,任何更改都将重新创建所有实例。您应该使用 ListModel 代替。

基于此,我找到了一种可能的解决方案:

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

注意:

我不想更改模型,因为我的模型在软件中被广泛使用,需要进行重大更改。

英文:

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.

huangapple
  • 本文由 发表于 2023年5月11日 12:26:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/76224159.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定