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

Qt 5.12下QML SwipeView重置Repeater模型时闪烁问题

QML SwipeView with Repeater & QAbstractListModel: Fixing Reset Glitches & Instantiator Issues

Let's break down your problem and walk through practical solutions tailored for Qt 5.12:

Why the Repeater Flicker Happens

In Qt 5.12, SwipeView and Repeater have a synchronization gap when the underlying QAbstractListModel is reset. Here's the root cause:

  • When you call beginResetModel() and endResetModel(), the Repeater destroys all old delegates and spawns new ones immediately.
  • SwipeView doesn't properly clean up old page components before the new ones are added, causing overlapping rendering of the first page's old and new instances—this is the flicker you're seeing.
  • The issue doesn't pop up with an empty initial model because there are no old components to clash with new ones. Standalone Repeater works fine because it lacks SwipeView's complex page management logic.

Fix 1: Sync Repeater Model Updates with SwipeView Cleanup

You can work around the flicker by temporarily disconnecting the Repeater from the model during reset, giving SwipeView time to clear old pages. Here's the modified QML:

Item {
    id: root
    property var viewModel
    height: 30 * Screen.pixelDensity
    width: 60 * Screen.pixelDensity

    Rectangle {
        id: wrapper
        anchors.fill: parent
        color: "grey"

        SwipeView {
            id: swipe
            clip: true
            anchors.fill: parent

            Repeater {
                id: pageRepeater
                model: null // Start with empty model

                Rectangle {
                    width: 20
                    height: 20
                    border.color: "black"
                    border.width: 1
                    Text { text: index }
                }
            }
        }

        // Sync model resets with SwipeView cleanup
        Connections {
            target: root.viewModel
            onModelReset: {
                // Clear repeater first to let SwipeView remove old pages
                pageRepeater.model = null
                // Short delay ensures cleanup finishes before reassigning
                Qt.callLater(() => {
                    pageRepeater.model = root.viewModel
                })
            }
        }

        // Initialize model when root.viewModel is set
        Component.onCompleted: {
            if (root.viewModel) pageRepeater.model = root.viewModel
        }
    }
}

This ensures old pages are fully removed before new ones are created, eliminating the flicker.

Fix 2: Correctly Using Instantiator (Why Your Code Failed)

Instantiator creates component instances but doesn't automatically add them to SwipeView's child list. You need to manually manage adding/removing instances. Here's the corrected code:

Rectangle {
    id: wrapper
    anchors.fill: parent
    color: "grey"

    SwipeView {
        id: swipe
        clip: true
        anchors.fill: parent
    }

    Instantiator {
        id: pageInstantiator
        model: root.viewModel

        delegate: Rectangle {
            width: 20
            height: 20
            border.color: "black"
            border.width: 1
            Text { text: index }
            Component.onCompleted: console.log("Created page", index)
        }

        // Add new instances to SwipeView when created
        onObjectCreated: {
            if (object) swipe.addItem(object)
        }

        // Remove and destroy instances when model resets
        onObjectRemoved: {
            if (object) {
                swipe.removeItem(object)
                object.destroy()
            }
        }
    }
}

Key points here:

  • Use swipe.addItem(object) to attach instantiated delegates to the SwipeView's page list.
  • When the model resets, onObjectRemoved triggers for old instances—we remove them from SwipeView and destroy them to free resources.
  • This gives you full control over page lifecycle, avoiding the synchronization issues with Repeater.

Alternative: Manual Page Management (Full Control)

If you want maximum control over page creation/destruction, skip Repeater/Instantiator entirely and manage pages directly when the model changes:

SwipeView {
    id: swipe
    clip: true
    anchors.fill: parent

    function updatePages(model) {
        // Clear all existing pages
        while (swipe.count > 0) {
            const page = swipe.itemAt(0)
            swipe.removeItem(page)
            page.destroy()
        }
        // Add new pages from model
        for (let i = 0; i < model.count; i++) {
            const page = pageComponent.createObject(swipe)
            page.pageIndex = i
            swipe.addItem(page)
        }
    }

    Connections {
        target: root.viewModel
        onModelReset: swipe.updatePages(root.viewModel)
    }

    Component {
        id: pageComponent
        Rectangle {
            property int pageIndex
            width: 20
            height: 20
            border.color: "black"
            border.width: 1
            Text { text: pageIndex }
        }
    }
}

This method is more verbose but eliminates any built-in synchronization conflicts between SwipeView and repeater components.


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 18:02:37