I am using a combination of ColumnLayout
with nested RowLayout
s:
and I'm trying to distribute items horizontally, so that the left edge of every row's first item lines up, and the right edge of every row's last item lines up, with a uniform spacing in between.
As an additional constraint, I want the window to automatically adjust its size to fit its contents, and I believe I achieved this by propagating implicitWidth
/implicitHeight
from root downwards.
I used Rectangle
s and Repeater
s to keep the code short:
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Layouts 1.12
Window {
width: rootRect.implicitWidth
height: rootRect.implicitHeight
visible: true
title: qsTr("Hello World")
readonly property var items: [
[[120, 80, 'red'], [100, 80, 'green'], [170, 40, 'blue']],
[[60, 120, 'yellow'], [140, 80, 'orange'], [60, 100, 'cyan']],
[[150, 100, 'purple'], [100, 80, 'blue'], [170, 40, 'orange']],
]
Rectangle {
id: rootRect
// achieve a padding of 5
implicitWidth: columnLayout.implicitWidth + 10
implicitHeight: columnLayout.implicitHeight + 10
ColumnLayout {
id: columnLayout
anchors.centerIn: parent // for above padding
Repeater {
model: items
Item {
id: row
implicitWidth: rowLayout.implicitWidth //[*]
//[*] Layout.fillWidth: true
implicitHeight: rowLayout.implicitHeight
readonly property var rowItems: modelData
RowLayout {
id: rowLayout
//[*] Layout.fillWidth: true
Repeater {
model: rowItems
Rectangle {
width: modelData[0]
height: modelData[1]
color: modelData[2]
}
}
}
}
}
}
}
}
However, no matter what I try (e.g. any combination of adding/removing the lines with //[*] ...
), I cannot get the items to distribute horizontally.
It looks like a non-trivial operation, as the row with maximum size should do what it is currently doing, while the other rows should simply set their size to follow, and distribute their items accordingly... or perhaps I overlook some property of Qt Quick Layouts.
Note: I'm using layouts and not positioners, as in reality I'm laying out Qt Quick Controls that could benefit from being resized by a layout.
EDIT: when I add an item to style rows, it breaks again: try it online
Here's another answer. This solution is based on the QML style in your question with minor tweaks.
I made use of the Frame
component. Frame
, if you haven't used it before, is a very convenient component for wrapping your contents with padding. So, instead of Rectangle
-ColumnLayout
. It's Frame
-ColumnLayout
. This is really useful because it allows you to delete the unnecessary pixel math that you had in both your Rectangle
and your ColumnLayout
.
I used Item
to solve your horizontal alignment problem. I did this by setting the Item
's Layout.preferredWidth
as well as setting Layout.fillWidth: true
. Both properties, when used together will cause the Item
to grow in size and distribute the spacing equally horizontally.
Finally, I do some anchoring to make sure the Rectangle
inside the Item
is anchored left, middle, or right.
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
Page {
background: Rectangle { color: "#444" }
readonly property var items: [
[[120, 80, 'red'], [100, 80, 'green'], [170, 40, 'blue']],
[[60, 120, 'yellow'], [140, 80, 'orange'], [60, 100, 'cyan']],
[[150, 100, 'purple'], [100, 80, 'blue'], [170, 40, 'orange']],
]
Frame {
background: Rectangle { }
ColumnLayout {
Repeater {
model: items
RowLayout {
id: rowLayout
Layout.fillWidth: true
Repeater {
model: modelData
Item {
Layout.preferredWidth: modelData[0]
Layout.preferredHeight: modelData[1]
Layout.fillWidth: true
Rectangle {
anchors.centerIn: index === 1 ? parent : undefined
anchors.right: index === 2 ? parent.right : undefined
width: modelData[0]
height: modelData[1]
color: modelData[2]
}
}
}
}
}
}
}
}
You can Try it Online!
Here's a demo link for your followup question. Each RowLayout is stylized with a Frame.