Reputation: 301
Potentially related: https://stackoverflow.com/a/30860285/3363018
I've been trying to create a QML layout with items that span variable numbers of rows and columns. So, e.g., a rectangle that spans two rows and four columns, one to the right of it that spans one row and two columns, and one underneath that spans three rows and five columns. A generic attempt at creating this is below:
import QtQuick 2.5
import QtQuick.Layouts 1.2
import QtQuick.Controls 1.4
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Hello, World")
GridLayout {
anchors.fill: parent
columns: 5
rows: 2
Rectangle {
Layout.column: 0
Layout.columnSpan: 4
Layout.row: 0
Layout.rowSpan: 2
Layout.fillHeight: true
Layout.fillWidth: true
color: "red"
}
Rectangle {
Layout.column: 4
Layout.columnSpan: 1
Layout.row: 0
Layout.rowSpan: 2
Layout.fillHeight: true
Layout.fillWidth: true
color: "green"
}
Rectangle {
Layout.column: 0
Layout.columnSpan: 5
Layout.row: 2
Layout.rowSpan: 3
Layout.fillHeight: true
Layout.fillWidth: true
color: "blue"
}
}
}
which results in this:
As you can see, Layout.rowSpan
and Layout.columnSpan
don't seem to be working. Instead, the top two rows seem to take up 1:1 rather than 4:1, and the top part vs the bottom part are 1:1 rather than 2:3. I suspect this is related to Layout.fillHeight
and Layout.fillWidth
. The documentation states:
If this property is true, the item will be as wide as possible while respecting the given constraints.
But, I'm not sure what "the given constraints" are in this context. I had hoped it would include the row and column span but it seems not.
I could probably directly calculate the item widths and heights (or maybe Layout.preferredWidth
and Layout.preferredHeight
) but that would seem to make Layout.rowSpan
and Layout.columnSpan
completely superfluous. Is there a way to automatically calculate the heights based on grid rows and columns?
Upvotes: 17
Views: 31413
Reputation: 451
I ran into the same problem as you did but I think it's easy to misunderstand what the GridLayout is doing. If you have a grid with 5 columns and 2 rows, you get something like this, where each O represents a cell:
grid
OOOOO
OOOOO
rowSpan
determines how TALL an object is, columnSpan
determines how WIDE an object is.
You are wanting to fit these in this grid:
r1 r2 r3
OOOO OO OOOOO
OOOO OOOOO
OOOOO
You can easily see that they won't fit.
This was my solution to a 12x12 grid and should be easy to follow. GridLayout
doesn't seem to automatically know what width and height to assign to its children, but that's okay, you can define that easily. Essentially, I'm passing in the rectangles to Layout.columnSpan:2
and Layout.rowSpan:2
, respectively. You could pass rowSpan
or columnSpan
, but I prefer this way because then I don't have to remember which function takes what:
GridLayout {
id: grid
anchors.fill: parent
rows: 12
columns: 12
property double colMulti: grid.width / grid.columns
property double rowMulti: grid.height / grid.rows
function prefWidth(item){
return colMulti * item.Layout.columnSpan
}
function prefHeight(item){
return rowMulti * item.Layout.rowSpan
}
Rectangle {
color: 'red'
Layout.rowSpan: 10
Layout.columnSpan: 2
Layout.preferredWidth: grid.prefWidth(this)
Layout.preferredHeight: grid.prefHeight(this)
}
Rectangle {
color: 'yellow'
Layout.rowSpan: 10
Layout.columnSpan: 10
Layout.preferredWidth: grid.prefWidth(this)
Layout.preferredHeight: grid.prefHeight(this)
}
Rectangle {
id: greenRect
color: 'green'
Layout.rowSpan: 2
Layout.columnSpan: 12
Layout.preferredWidth: grid.prefWidth(this)
Layout.preferredHeight: grid.prefHeight(this)
}
}
Result:
Upvotes: 20
Reputation: 2118
@Kao recommended binding to the columnSpan and rowSpan. This works because they are unit proportions.
If all elements on a row have Layout.fillWidth
set true
, their preferred widths are used to determine their proportional width. Binding an element's preferredWidth
to its columnspan
establishes a ratio that the GridLayout uses to compute the element's width: a span of 4 in a grid with 5 columns results in the element taking up 80% of the total width of the grid. The same goes for elements in a column.
This solution uses a Qt 5.15 inline component:
GridLayout {
anchors.fill: parent
columns: 5
rows: 5
component ProportionalRect: Rectangle {
Layout.fillHeight: true
Layout.fillWidth: true
Layout.preferredWidth: Layout.columnSpan
Layout.preferredHeight: Layout.rowSpan
}
ProportionalRect {
Layout.columnSpan: 4
Layout.rowSpan: 2
color: "red"
}
ProportionalRect {
Layout.columnSpan: 1
Layout.rowSpan: 2
color: "green"
}
ProportionalRect {
Layout.columnSpan: 5
Layout.rowSpan: 3
color: "blue"
}
}
Upvotes: 2
Reputation: 2118
Description for top-right rect has rows and columns transposed. Should be:
one to the right of it that spans one column and two rows
The number of rows is incorrect. Should be:
columns: 5
rows: 5
Specify preferred widths and heights as percentages or units. I'm using units below because it is easier to relate to your 4:1 and 2:3 proportions:
GridLayout {
anchors.fill: parent
columns: 5
rows: 5 // was 2
Rectangle {
Layout.column: 0
Layout.columnSpan: 4
Layout.row: 0
Layout.rowSpan: 2
Layout.preferredWidth: 4 // 4 of 5 cols
Layout.preferredHeight: 2 // 2 of 5 rows
Layout.fillHeight: true
Layout.fillWidth: true
color: "red"
}
Rectangle {
Layout.column: 4
Layout.columnSpan: 1
Layout.row: 0
Layout.rowSpan: 2
Layout.preferredWidth: 1 // 1 of 5 cols
Layout.preferredHeight: 2 // 2 of 5 rows
Layout.fillHeight: true
Layout.fillWidth: true
color: "green"
}
Rectangle {
Layout.column: 0
Layout.columnSpan: 5
Layout.row: 2
Layout.rowSpan: 3
Layout.preferredHeight: 3 // 3 of 5 rows
Layout.fillHeight: true
Layout.fillWidth: true
color: "blue"
}
}
Below is minimal code using percentages to achieve the same result:
GridLayout {
anchors.fill: parent
columns: 2
Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.preferredWidth: 80
Layout.preferredHeight: 40
color: "red"
}
Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.preferredWidth: 20
Layout.preferredHeight: 40
color: "green"
}
Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.columnSpan: 2
Layout.preferredWidth: 100
Layout.preferredHeight: 60
color: "blue"
}
}
Upvotes: 2
Reputation: 557
If you are not planning to leave any empty spaces in grid, you can make width and height proportional to spans by binding preferred sizes to spans.
Layout.fillWidth: true
Layout.fillHeight: true
Layout.preferredWidth: Layout.columnSpan
Layout.preferredHeight: Layout.rowSpan
Upvotes: 1