You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

QML Repeater模型变更时全量重建代理的优化方案咨询

问题描述

当修改QML Repeater的模型(添加、删除或编辑成员)时,Repeater会移除所有已创建的代理项并重新构建,处理大型模型时会引发严重性能问题。如何调整Repeater的使用方式,使其仅针对删除的模型成员移除对应代理、新增成员时仅创建对应代理、编辑成员时仅更新对应项?

我研究了Repeater的源码,但因大量私有方法和类无法直接重实现。以下是复现问题的测试代码:

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++;
             // 向模型添加元素,此时Repeater会全量重建
             repeatreModel.push(count);
        }
    }

    Column {
        anchors.fill: parent

        Repeater {
            id: repeater
            model: repeatreModel
            clip: true

            onItemRemoved: (item, index) => {
                console.log("移除项: (item, index) ", item, index)
            }

            onItemAdded: (item, index) => {
                console.log("新增项: (item, index) = ", item, index)
            }

            delegate: Rectangle {
                width: 50
                height: 40
                Text {
                    id: name
                    anchors.centerIn: parent
                    text: modelData
                }
            }

            onModelChanged: console.log("modelChanged")
        }
    }
}
解决方案

原生Repeater对普通JS数组的变更无法感知增量操作——JS数组的push等操作不会触发模型的增量信号通知,Repeater只能检测到整个模型对象变化,从而全量重建代理。要实现增量更新,核心是使用支持动态数据变更通知的模型类型,而非普通JS数组:

1. 使用QML内置ListModel

ListModel是QML原生支持的可动态修改模型,会自动向Repeater发送rowsInserted、rowsRemoved、dataChanged等增量信号,Repeater据此仅更新对应项:

修改后的示例代码:

import QtQuick
import QtQuick.Controls

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

    // 用ListModel替代普通JS数组
    ListModel {
        id: repeatModel
        ListElement { value: 1 }
        ListElement { value: 2 }
    }

    Timer {
        interval: 2000
        running: true
        repeat: true

        property int count: 2
        onTriggered: {
            count++;
            // 仅触发新增代理,而非全量重建
            repeatModel.append({ value: count })
        }
    }

    Column {
        anchors.fill: parent

        Repeater {
            id: repeater
            model: repeatModel
            clip: true

            onItemRemoved: (item, index) => {
                console.log("移除项: (item, index) ", item, index)
            }

            onItemAdded: (item, index) => {
                console.log("新增项: (item, index) = ", item, index)
            }

            delegate: Rectangle {
                width: 50
                height: 40
                color: "lightblue"
                Text {
                    anchors.centerIn: parent
                    // 绑定ListModel的字段
                    text: value
                }
            }

            onModelChanged: console.log("modelChanged")
        }
    }
}

2. 自定义C++ QAbstractListModel

如果需要处理复杂业务逻辑或高性能数据场景,可自定义继承自QAbstractListModel的C++模型:

  • 重写rowCount、data等核心方法
  • 在数据新增、删除、修改时,主动调用beginInsertRows/endInsertRows、beginRemoveRows/endRemoveRows、dataChanged等方法发送增量信号
  • 注册模型到QML后,Repeater会自动识别这些信号,仅执行必要的代理操作

关键原理

Repeater的增量更新依赖Qt模型/视图框架的标准变更信号,普通JS数组无法发出这类信号,因此Repeater只能全量重建。而ListModel或自定义C++模型会在数据变更时发送精准的增量信号,Repeater收到后仅创建、销毁或更新对应代理项。

内容的提问来源于stack exchange,提问作者Mohsen Kondori

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 15:05:22