I have a ColumnLayout which contains a ListView with a Button below. Both the ListView and the Button have 'Layout.fillwidth = true' to make sure they have the same width. The width of the delegates (Labels) should occupy the full width of the Listview (to center them horizontally, and to -later on- use different background colors). If the Button is wider then the ListView, the width of the delegates should grow to still accommodate the full width of the ListView.
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
Window {
id: root
width: 640
height: 480
visible: true
title: qsTr("Layout test")
Rectangle {
color: 'grey'
anchors.fill: vert_layout
}
ColumnLayout {
id: vert_layout
anchors.centerIn: parent
spacing: 0
ListView {
id: list
readonly property int itemHeight: 20
property int visibleItems: 14
height: visibleItems * itemHeight
clip: true
Layout.fillWidth: true
Layout.minimumWidth: contentItem.childrenRect.width
model: 20
delegate: Label {
id: itemlabel
height: list.itemHeight
// width: list.width // <== this doesn't work
color: 'black'
padding: 4
horizontalAlignment: Text.AlignHCenter
text: "entry number " index
}
}
Button {
id: btn
Layout.fillWidth: true
implicitHeight: 20
text: "SMALL"
// text: "REALLY WIDE BUTTON"
}
}
}
This code has the problem that the delegates don't occupy the full width of the ListView. Because of this the entries in the list are left aligned and not centered horizontally.
If I comment out the line that sets the width of the delegate to the width of the ListView, the entries are horizontally aligned, but the text of the entries is not fully visible anymore. Layout management doesn't seem to calculate the widths correctly anymore.
I would love to learn how to handle this properly.
CodePudding user response:
I had a number of goes at this and found this to be an interesting but frustrating problem. In the end, I felt that your logic was sound in having the ListView resize to the contents of the children. I found a trick by using a mock Item as the parent delegate for sizing the ListView. Then, inside that Item, I put a Frame and the real Label. Whilst the Item and the Label share the same size, the Frame is bigger to allow me to draw the cell Rectangle as well as to help me position the Label.
ListView {
id: list
Layout.minimumWidth: contentItem.childrenRect.width
Layout.fillWidth: true
delegate: Item {
width: itemLabel.width
height: list.itemHeight
Frame {
width: list.width
height: parent.height
padding: 0
background: Rectangle {
color: (index & 1) ? "#ccc" : "#aaa"
}
Label {
id: itemLabel
anchors.centerIn: parent
text: "entry number " index
color: "black"
}
}
}
}
Here's a fully working version:
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
Page {
id: root
width: 640
height: 480
visible: true
title: qsTr("Layout test")
Frame {
anchors.centerIn: parent
padding: 0
background: Rectangle { color: "grey" }
ColumnLayout {
id: vert_layout
spacing: 0
ListView {
id: list
readonly property int itemPadding: 4
readonly property int itemHeight: tm.height itemPadding * 2
readonly property TextMetrics tm: TextMetrics { text: "#" }
property int visibleItems: 14
Layout.preferredHeight: visibleItems * itemHeight
Layout.minimumWidth: contentItem.childrenRect.width itemPadding * 2
Layout.fillWidth: true
clip: true
model: 20
delegate: Item {
property string txt: wideDelegates.checked
? "really wide entry number " index
: "entry number " index
width: itemLabel.width
height: list.itemHeight
Frame {
id: frame
width: list.width
height: parent.height
padding: 0
background: Rectangle {
color: (index & 1) ? "#ccc" : "#aaa"
}
Label {
id: itemLabel
anchors.centerIn: parent
text: wideDelegates.checked
? "really wide entry number " index
: "entry number " index
color: "black"
}
}
}
}
Button {
id: btn
Layout.fillWidth: true
implicitHeight: 20
text: wideButton.checked
? "REALLY WIDE BUTTON"
: "SMALL"
}
}
}
footer: RowLayout {
Item { Layout.fillWidth: true }
CheckBox {
id: wideDelegates
text: "Wide Delegates"
}
CheckBox {
id: wideButton
text: "Wide Button"
}
Item { Layout.fillWidth: true }
}
}
You can Try it Online!