Adjust ColumnLayout when a Repeater's delegate

2019-05-27 04:15发布

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?

标签: qt qml qt5.6
1条回答
姐就是有狂的资本
2楼-- · 2019-05-27 04:31

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

}
查看更多
登录 后发表回答