Macias
Macias

Reputation: 717

QML changing Pathview's path without reloading content

I'm facing the problem with Pathview. I need to change the path property to reorganize the children items, but when I'm doing this, it causes all of the created elements (specified by model) to be destroyed and created again.

Is there any way to do that without reloading content, or maybe 'cover' the blink effect?

Example:

import QtQuick 2.6
import QtQuick.Window 2.2
import QtQuick.Controls 1.2

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("PathView path test")

    Path {
        id: path1
        startX: 100; startY: 100
        PathLine{ x: 300; y: 100 }
    }
    Path {
        id: path2
        startX: 100; startY: 100
        PathLine{ x: 100; y: 300 }
    }

    ListModel {
        id: pvModel
        ListElement{ name: "rectangle" }
        ListElement{ name: "rectangle" }
        ListElement{ name: "rectangle" }
    }

    Component {
        id: pvDelegate
        Rectangle {
            width: 50
            height: 50
            color: "red"
            border.width: 1
            Component.onCompleted: console.log("Rectangle created")
            Component.onDestruction: console.log("Rectangle deleted")
        }
    }

    property bool currentPath;
    PathView {
        anchors.fill: parent
        model: pvModel
        delegate: pvDelegate
        path: (currentPath ? path1 : path2)
    }

    Button {
        width: 100
        height: 40
        text: "Switch path"
        onClicked: currentPath = !currentPath
    }
}

Upvotes: 1

Views: 945

Answers (2)

derM
derM

Reputation: 13691

The PathView seems to use this trick, to force a re-layout after the Path has changed. I found no ideal way to do this sofar, but to stop the PathView from destroying your delegates can be done by using a intermediate DelegateModel.

The DelegateModel instantiates the Items for the view and you can chose, to have the Items persistent, by adding them to the persistedItems-group.

As we might want to use the dynamic instantiation of a model, for this example, I add only those Items to this group, that are instantiated, when the Path will switch, and remove them from the group right after the switch.

As I said: I did not find (but was not looking too much) for a nice way to force a relayout. So for the moment, I resort to moving the view a little bit, as otherwise the x and y-values of the delegates won't be updated.

If all your Items are visible anyway, you can just mark all of them as persistent in the Component.onCompleted-slot

import QtQuick 2.6
import QtQuick.Window 2.2
import QtQuick.Controls 1.2
import QtQml.Models 2.2

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("PathView path test")

    Path {
        id: path1
        startX: 100; startY: 100
        PathLine{ id: line1; x: 300; y: 100 }
    }
    Path {
        id: path2
        startX: 100; startY: 100
        PathLine{ x: 100; y: 300 }
    }

    ListModel {
        id: pvModel
        ListElement{ name: "rectangle" }
        ListElement{ name: "rectangle" }
        ListElement{ name: "rectangle" }
    }

    DelegateModel {
        id: pvDelegateModel
        model: pvModel
        delegate: Rectangle {
            id: delegate
            width: 50
            height: 50
            color: 'red'
            border.width: 1

            Component.onCompleted: console.log("Rectangle created")
            Component.onDestruction: console.log("Rectangle destroyed")
            Connections {
                target: button
                onStart: delegate.DelegateModel.inPersistedItems = true // Make them persistent befor the switch 
                onEnd: delegate.DelegateModel.inPersistedItems = false // Make them non-persistent after the switch
            }
        }
    }

    PathView {
        id: pv
        anchors.fill: parent
        model: pvDelegateModel
        path: path1
        clip: true
    }

    Button {
        id: button
        width: 100
        height: 40
        text: "Switch path"
        signal start
        signal end
        onClicked: {
            start()
            pv.path = (pv.path === path1 ? path2 : path1)
            end()
            pv.currentIndex +=1   // To force a refresh of the layout
            pv.currentIndex -= 1
        }
    }
}

Upvotes: 2

jpnurmi
jpnurmi

Reputation: 5836

I don't know if it's just the path in the above test case, or whether this is possible with the path you have in your real app, but one option could be to change the attributes of the path instead of changing the whole path. Looks like you can even animate the path attributes:

import QtQuick 2.6
import QtQuick.Window 2.2
import QtQuick.Controls 1.2

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("PathView path test")

    Path {
        id: pvPath
        startX: 100; startY: 100
        PathLine{
            x: currentPath ? 300 : 100
            y: currentPath ? 100 : 300
            Behavior on x { SmoothedAnimation { duration: 125 } }
            Behavior on y { SmoothedAnimation { duration: 125 } }
        }
    }

    ListModel {
        id: pvModel
        ListElement{ name: "rectangle" }
        ListElement{ name: "rectangle" }
        ListElement{ name: "rectangle" }
    }

    Component {
        id: pvDelegate
        Rectangle {
            width: 50
            height: 50
            color: "red"
            border.width: 1
            Component.onCompleted: console.log("Rectangle created")
            Component.onDestruction: console.log("Rectangle deleted")
        }
    }

    property bool currentPath;
    PathView {
        anchors.fill: parent
        model: pvModel
        delegate: pvDelegate
        path: pvPath
    }

    Button {
        width: 100
        height: 40
        text: "Switch path"
        onClicked: currentPath = !currentPath
    }
}

Upvotes: 0

Related Questions