Adjust ColumnLayout when a Repeater's delegate height changes
Asked Answered
H

1

6

I've set up a file called test1.qml with the following contents:

import QtQuick 2.6
import QtQuick.Layouts 1.3

Rectangle {
    width: 800; height: 1000;

    ColumnLayout {
        anchors.centerIn: parent

        // Header goes here

        Repeater {
            model: 3
            delegate: MyRectangle {
                width: 150
                height: width
                color: "#44ff0000"
            }
        }

        // Footer goes here

    }
}

I've also setup a file called test2.qml defined as follows:

import QtQuick 2.6
import QtQuick.Layouts 1.3

Rectangle {
    width: 800; height: 1000;

    ColumnLayout {
        anchors.centerIn: parent

        // Header goes here

        Repeater {
            model: 3
            delegate: Column {
                MyRectangle {
                    width: 150
                    height: width
                    color: "#44ff0000"
                }
            }
        }

        // Footer goes here

    }
}

Finally, MyRectangle.qml has the following contents:

import QtQuick 2.6

Rectangle {
    MouseArea {
        anchors.fill: parent
        onClicked: {
            parent.height += 50
        }
    }
}

My goal is that when instances of MyRectangle are clicked, their heights change, and the ColumnLayout should enlarge so that the items maintain their spacing.

When I run test.qml, the result is not what I expect, in that the instances of MyRectangle overlap each other as they are clicked. However, test2.qml gives the desired behavior, and the instances of MyRectangle maintain their spacing as the ColumnLayout enlarges.

At the request of derM, I think the GIFs below may help to explain this more clearly.

The (undesired) behavior of test1.qml:

The (undesired) behavior of **test1.qml**

The (desired) behavior of test2.qml:

The (desired) behavior of **test2.qml**

Why is it that I have to wrap the objects in a Column to achieve the desired result?

Hofmannsthal answered 18/11, 2017 at 6:17 Comment(5)
A repeater has no layout. Why would you use a Column or RowLayout as a delegate when you have only one child within them?Mesoglea
A Repeater simply creates a number of instances of the delegate, possible passing model data for each instance. The layout can be either applied externaly by having the Repeater inside a Layout to which the delegates will be parented, or each delegate can tale care of its own positioning e.g by setting x and y valuesMesoglea
Your comments make sense, and I originally tried using just a Rectangle. However, when I did that, all my items got stacked on top of each other. Adding 'height: myDelegate.height' to the Rectangle lays out the delegates properly, but then the Repeater (which is itself part of a ColumnLayout) doesn't get the correct height, and the item below the Repeater gets laid out on top of it. After much trial and error, I found that Column or ColumnLayout takes care of my issues. I would be interested in knowing why Rectangle isn't working properly, though.Hofmannsthal
Please add a small graphic illustrating what exactly you try to achieve.Mesoglea
I edited the question, adding some graphics that I hope will explain my problem more clearly.Hofmannsthal
M
11

The reason might sound strange:

The [...]Layout-family is not just there to arrange the objects, but also to resize them. You are not supposed to set or alter sizes in it.

To do its job, when you don't use the available attached properties to set the sizes, it will use the implicitWidth/Height of your Items.

If you have not set implicit dimension, uppon adding new items to the layout, their implicit dimensions will be set to be equal to their set dimsions. But this is not a binding! So if you now update the height, the implicitHeight will stay at the original size, thus the Layout won't react to the change.

If you add the Column to your delegate, things change: The Column updates its implicitHeight in accordeance to the bounding rectangle of its children. If you now resize the Rectangles height, the Column will adapt the implicitHeight and the Layout will react to the change.

Now you have the following solutions:

  1. Use the Layout attached property, to set and change the size hints.
  2. Use the delegates implicitHeight instead of the height. This might be semantically wrong though.
  3. Don't use the ColumnLayout but just a regular Column when you don't need the additional layouting capatibilities (the attached properties and resizing of the Items and so on), which seems to be the case in your problem.

Column {
    anchors.centerIn: parent
    spacing: 5

    // Header goes here

    Repeater {
        model: 3
        delegate:
            Rectangle {
                width: 150
                height: width
                color: "#44ff0000"
                MouseArea {
                    anchors.fill: parent
                    onClicked: {
                        console.log(parent.implicitHeight)
                        parent.height += 50
                    }
                }

        }
    }
    // Footer goes here

}
Mesoglea answered 27/11, 2017 at 20:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.