reckless
reckless

Reputation: 923

QML slow performance animating a lot of rectangles

I'm creating a "dotted paper" component for my QML app. Essentially this components consists of a dotted background that the user can zoom upon. To create this I used the following code:

DottedPaper.qml

import QtQuick 2.15

Rectangle{
    id: page

    property int spacing: 50
    // this property changes the spacing between the dots
    property real contentScale: 1.0

    Repeater{
        id: rowRepeater
        model: 200
        Repeater{
            id: row
            property int rowIndex: index
            model: 200
            Rectangle{
                id: circle
                color: "red"
                width: 4; height: 4
                x: index * spacing * page.contentScale + width/2;
                y: rowIndex * spacing * page.contentScale+ height/2
                radius: width/2
            }
        }
    }
}

Then in my main file I have the following:

import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15

Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("Hello World")

    Flickable{
        clip: true // doesn't improve anything
        anchors.fill: parent
        contentWidth: paper.width
        contentHeight: paper.height
        DottedPaper{
            id: paper
            width: 10000; height: 10000;
            clip: true
        }
    }

    // the slider changes the content scale of the dotted paper
    Slider{
        from: 1
        to: 3
        onValueChanged: paper.contentScale = value
    }
}

The problem with this code is that it's slow. Upon checking the application does not render the content at 60fps, but I get around 45 - 50 fps on my desktop. I suspect the issues is that QML is reevaluating the contentScale property binding for each circle in the background even if the circle is not visible on the screen. What is the best way to prevent this?

Upvotes: 0

Views: 962

Answers (1)

JarMan
JarMan

Reputation: 8277

It works a lot better if you change your Repeaters to be ListViews. That's because a ListView is smart enough to only create enough delegates as needed for the visible space. (At first I thought a GridView would work, but that doesn't give you enough control over rows/columns.)

Rectangle{
    id: page

    property int cellWidth: 50 * contentScale
    property int dotWidth: 4
    // this property changes the spacing between the dots
    property real contentScale: 1.0

    ListView {
        id: grid
        model: 200
        anchors.fill: parent
        anchors.leftMargin: page.dotWidth / 2
        anchors.topMargin: page.dotWidth / 2
        spacing: page.cellWidth - page.dotWidth

        delegate: ListView {
            model: 200
            width: window.width
            height: page.dotWidth
            orientation: ListView.Horizontal
            spacing: page.cellWidth - page.dotWidth
            property int rowIndex: index

            delegate: Rectangle{
                id: circle
                color: "red"
                width: page.dotWidth; height: page.dotWidth
                radius: width/2
            }
        }
    }
}

Upvotes: 3

Related Questions