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

qml ListView delegate containing a Loader doesn't expand when loading some components?



  • Hi,
    I've a ListView using a delagate that is a Column with first a Rectangle { id: firstLine } and under a Loader { id: childView } that is not loaded.

    There is a checkabe Button in firsLine that is suppose to load / unload a Component in the Loader. Here is its code:

                        onClicked: {
                            if (checked) {
                                childView.sourceComponent = myComponent;
                                childView.height = 100;
                            }
                            else {
                                childView.sourceComponent = undefined;
                                childView.height = 0;
                            }
                        }
    

    So the idea is to simulate a TreeView inside my ListView and being able to dynamically expand my rows using the Delegate.

    If I use a simple Text Delegate like this:

        Component {
            id: myComponent
            Text { text: modelIndex }  
        }
    

    It is working as expected. cf the number the modelIndex with extra space under each row.
    alt text

    BUT of course I'm loading a more complex component (another ListView) and it is not working :'(
    Basically the row is not expanding and the Component loaded is drawn on top of the firstLine Rectangle.

    I've this behaviour if I just encapsulate the component above in an item like this:

        Component {
            id: myComponent
    //        Text { text: modelIndex } 
    
            Item {
    //            height: 100
    //            width: parent.width
                Text {
    //                height: 100
                    text: modelIndex
                }    //okay
            }
        }
    

    Any idea why?
    alt text

    Edit: I don't have this issue if I don't use the Loader but instead directly define my childView and play on it's visible attribute in the expand button.
    I don't understand why it is not working dynamically with a Loader... It will allow to have some kind of easy loading for the child view and performance will improve


  • Moderators

    @mbruel AFAIK the loader superimposes its own hight and width on the component it loads.
    change the loader hight and it should work.

    The fact that you see it "working" with a text element is not surprising, text is drawn outside the boundaries of the TextElement without a problem (is the default)



  • @J-Hilk well in my JS function I change the height of the Loader. I even tried to change the one of its item but it doesn't do anything.
    And why is the Loader painted on top of my firstLine although my Delegate is a Column?


  • Moderators

    @mbruel it's hard for me to understand the issue at hand,

    can you share the example you quoted? Seems like a small enough project, could clarify things :D



  • @J-Hilk arf I thought I could avoid doing a small example and just manage to describe it...
    sure it will be easier with a small use case. Ok I'll do that after lunch ;)



  • So thanks to @LeLev who gave me a solution using a ColumnLayout, here is from where I was starting

        ListView{
            anchors.fill: parent
            spacing: 10
            model: 5
            delegate: Column {
                width: parent.width
                height: exp.checked ? r.height +  v.height + spacing : r.height
                spacing: 10
                Rectangle{
                    id: r
                    width: parent.width
                    height: 50
                    color: "grey"
    
                    CheckBox{
                        id:exp
                        anchors.right: parent.right
                        text: "expand " + index
                    }
                }
    
                ListView {
                    id: v
                    model: 10
                    spacing: 1
                    clip : true
                    height: contentHeight
                    width: parent.width
                    visible: exp.checked
                    delegate: Rectangle{
                        height: 30
                        width: parent.width
                        color: "lightblue"
                    }
                }
            }
        }
    

    The goal was to dynamically load the second ListView in Loader so the page loads much faster.

    Here is @LeLev solution using a ColumnLayout:

        // 2.: Solution with a ColumnLayout
        Component{
            id:view
            ListView {
                model: 10
                spacing: 1
                clip : true
                height: contentHeight
                delegate: Rectangle{
                    height: 30
                    width: parent.width
                    color: "lightblue"
                }
            }
        }
    
        ListView{
            anchors.fill: parent
            spacing: 10
            model: 5
            delegate: ColumnLayout{
                height: exp.checked ? 50 + l.item.contentHeight : 50
                width: root.width
                spacing: 1
                Rectangle{
                    Layout.fillHeight: true
                    Layout.fillWidth: true
                    Layout.preferredHeight: 50
                    Layout.maximumHeight: 50
                    color: "grey"
                    CheckBox{
                        id:exp
                        anchors.right: parent.right
                        text: "expand " + index
                        onCheckedChanged: {
                            l.sourceComponent = checked ? view : undefined
                        }
                    }
                }
                Loader{
                    id:l
                    Layout.fillHeight: sourceComponent != undefined
                    Layout.fillWidth: true
    //                Layout.preferredHeight: sourceComponent != undefined ? 100 : 0
                }
            }
        }
    

    and finally after a break and fighting with Column, it is also working without a Layout :)

        // 3.: Solution with a Column
        Component{
            id:view
            ListView {
                model: 10
                spacing: 1
                clip : true
                height: contentHeight
                width: root.width
                delegate: Rectangle{
                    height: 30
                    width: parent.width
                    color: "lightblue"
                }
            }
        }
    
        ListView{
            anchors.fill: parent
            spacing: 10
            model: 5
            delegate: Column{
                width: parent.width
                height: exp.checked ? r.height +  l.item.height + spacing : r.height
                spacing: 10
    
                Rectangle{
                    id: r
                    width: parent.width
                    height: 50
                    color: "grey"
    
                    CheckBox{
                        id:exp
                        anchors.right: parent.right
                        text: "expand " + index
                        onCheckedChanged: {
                            l.sourceComponent = checked ? view : undefined
                        }
                    }
                }
                Loader{
                    id:l
                }
            }
        }
    

Log in to reply