Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Dynamic creation/deletion of delegates inside delegates of ListView



  • Hi,

    I am currently working on a view that uses a ListView to display data. Let's call the ListView mainLog. The delegates in mainLog are typically collapsed and just show an overview of the item. When the user clicks on the delegate it expands and show details of the item. The items of mainLog itself contain another list of data items which might be quite long. Let's call this list itemData. Currently I am doing this with a Repeater but since a Repeater always instantiates all of its delegate this might have bad performance.

    My question now is: Is there a nice way to automatically (or manually) create and delete the visible delegates of itemData when scrolling the list of mainLog?

    Cheers Heiko


  • Qt Champions 2017

    Did you a get a chance to look at expanding delegate example in the example directory ?
    quick/views/views.qml



  • Well I know how to make an expandable delegate. The problem is how to handle other delegates inside there efficiently. Here is some example code to demonstrate what I have. I already thought one solution might be to use a TreeView with one nesting, restyle it to show a plain list and switch delegates... But I am not sure if the TreeView works with delegates of different size and I would rather work with less restructuring. Maybe there is something different.

    Here is some example code to show what I mean:

    import QtQuick 2.11
    import QtQuick.Window 2.11
    
    
    Window {
        visible: true
        width: 640
        height: 480
        property int size: 1000
        title: qsTr("Hello World")
    
        ListModel {
            id: mainLogModel
            ListElement {
                title: "This is the first Entry"
                itemData: [
                    ListElement {
                        detail: "Detail 1 of first Entry"
                    },
                    ListElement {
                        detail: "Detail 2 of first Entry"
                    }
                ]
            }
            ListElement {
                title: "This is the second Entry"
                itemData: [
                    ListElement {
                        detail: "Detail 1 of second Entry"
                    }
                ]
            }
        }
    
        ListView {
            id: listView
            anchors.fill: parent
            model: mainLogModel
            delegate: Column {
                id: delegateColumn
                width: listView.width
                height: titleText.height
    
                Text {
                    id: titleText
                    text: title
                    MouseArea {
                        anchors.fill: parent
                        onClicked: delegateColumn.state =
                                   delegateColumn.state !== "" ?
                                       delegateColumn.state = "" :
                                       delegateColumn.state = "open"
                    }
                }
    
                Column {
                    id: detailsItem
                    visible: false
                    Repeater {
                        id: repeater
                        delegate: Rectangle {
                            x: 10
                            width: listView.width
                            height: text.height
                            color: "lightblue"
                            Text {
                                id: text
                                text: detail
                            }
                        }
                    }
                }
    
                states: State  {
                    name: "open"
    
                    PropertyChanges {
                        target: delegateColumn
                        height: titleText.height + detailsItem.height
                    }
                    PropertyChanges {
                        target: detailsItem
                        visible: true
                    }
                    PropertyChanges {
                        target: repeater
                        model: itemData
                    }
                }
            }
        }
    
        Component.onCompleted: {
            for (var i = 0; i < size; i++) {
                var details = [];
                for (var j = 0; j < size; j++) {
                    details.push({"detail" : "Detail " + j + " of " + i + " Entry"});
                }
                mainLogModel.append({"title": "This is " + i + " Entry",
                                     "itemData" : details});
            }
        }
    }
    

    The question is how I can enable the part with the repeater to only construct its delegates when they are visible. Like is done by the surrounding ListView. As you can see I already have some optimization by only setting the itemData model once an entry is opened. Otherwise this example would already be unbearably slow.


Log in to reply