Reputation: 76720
I have rectangles with a certain aspect ratio and rectangles with the inverse aspect ratio. I would like to arrange them in a grid layout of my choosing (doesn't need to be a regular grid, on the contrary: I'd prefer a solution where I can build up RowLayout
s and ColumnLayout
s at will).
I know I can have scaling items in my Layouts using Layout.fillHeight
and Layout.fillWidth
. Unfortunately, I can find no way to properly define aspect ratios for my Rectangle
s. I know QML Image
can do it (through its fillMode
property) but I see no simple way of doing it nicely.
Any help or pointers in the right direction would be much appreciated!
Note I'm assuming QML Layouts is the way to go, but if there is a functional solution with just anchors or a plain Row
/Column
setup, I'm all for it!
Also note that I would prefer to keep the area of te two types of Rectangle
the same, as it seems while experimenting, this is not so trivial...
EDIT
An attempt of what I mean, minus the equal area constraint. The rectangles fill the width, but leave space in the height because they are constrained by their aspect ratio and the filled width. Same should go for the height, but I'm failing at combining the two.
Upvotes: 5
Views: 5340
Reputation: 3030
I did upvote the answer of @CharlesSALA (because it works!), but thought I would also offer an alternative answer based on layouts.
The AspectItem
is responsible for providing the correct margin to maintain the width, using the implicitWidth
. The Layout
is responsible for providing the correct margin to maintain the height, using the Layout.maximumHeight
.
The same will work in a GridLayout
in the place of the ColumnLayout
& RowLayout
. The result is slightly different, because the columns must stay aligned in all of the rows, but in both cases the aspect ratio of the rectangles is preserved as required.
AspectItem.qml
import QtQuick 2.11
Item {
id: container
property real aimedRatio: 3/4
property alias color: content.color
implicitWidth: height*container.aimedRatio
implicitHeight: width/container.aimedRatio
Rectangle {
id: content
anchors.horizontalCenter: container.horizontalCenter
height: container.height
implicitWidth: height*container.aimedRatio
}
}
main.qml
import QtQuick 2.11
import QtQuick.Controls 2.4
import QtQuick.Layouts 1.11
ApplicationWindow {
id: window
visible: true
width: 800
height: 800
y: 0
ColumnLayout {
anchors.fill: parent
RowLayout {
width: parent.width
AspectItem {
color: "darkseagreen"
aimedRatio: 1/2
Layout.fillWidth: true
Layout.fillHeight: true
Layout.maximumHeight: implicitHeight
}
AspectItem {
color: "seagreen"
aimedRatio: 2/1
Layout.fillWidth: true
Layout.fillHeight: true
Layout.maximumHeight: implicitHeight
}
AspectItem {
color: "lightseagreen"
aimedRatio: 1/2
Layout.fillWidth: true
Layout.fillHeight: true
Layout.maximumHeight: implicitHeight
}
}
RowLayout {
width: parent.width
AspectItem {
color: "darkcyan"
aimedRatio: 2/1
Layout.fillWidth: true
Layout.fillHeight: true
Layout.maximumHeight: implicitHeight
}
AspectItem {
color: "cyan"
aimedRatio: 1/2
Layout.fillWidth: true
Layout.fillHeight: true
Layout.maximumHeight: implicitHeight
}
AspectItem {
color: "lightcyan"
aimedRatio: 2/1
Layout.fillWidth: true
Layout.fillHeight: true
Layout.maximumHeight: implicitHeight
}
}
RowLayout {
width: parent.width
AspectItem {
color: "darksalmon"
aimedRatio: 1/2
Layout.fillWidth: true
Layout.fillHeight: true
Layout.maximumHeight: implicitHeight
}
AspectItem {
color: "salmon"
aimedRatio: 2/1
Layout.fillWidth: true
Layout.fillHeight: true
Layout.maximumHeight: implicitHeight
}
AspectItem {
color: "lightsalmon"
aimedRatio: 1/2
Layout.fillWidth: true
Layout.fillHeight: true
Layout.maximumHeight: implicitHeight
}
}
}
}
Result
At launch:
Stretched narrow:
Stretched wide:
Upvotes: 3
Reputation: 31
I have been struggling for few days on the proper way to do that. I could not found any working exemple so I wrote my own.
This rectangle will always respect its aimedRatio and will keeps its margins. The trick here is to treat to different cases : Either the parents ratio is larger that the aimed one or not. In one case you bind the width to parent and set height according to. In the other case you do it the other way.
Rectangle {
color : 'green'
// INPUTS
property double rightMargin : 20
property double bottomMargin : 20
property double leftMargin : 20
property double topMargin : 20
property double aimedRatio : 3/4
// SIZING
property double availableWidth : parent.width - rightMargin - leftMargin
property double availableHeight : parent.height - bottomMargin - topMargin
property bool parentIsLarge : parentRatio > aimedRatio
property double parentRatio : availableHeight / availableWidth
height : parentIsLarge ? width * aimedRatio : availableHeight
width : parentIsLarge ? availableWidth : height / aimedRatio
anchors.top : parent.top
anchors.topMargin : topMargin
anchors.left : parent.left
anchors.leftMargin : leftMargin
}
Hope it will help out people who arrive here with google search !
Upvotes: 3
Reputation: 2296
You can use property binding to bind the width
of the rectangle with height
using aspect ratio as follows,
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Layouts 1.0
Window {
id: root
visible: true
width: 640
height: 480
title: qsTr("Hello World")
property int minWidth: 150
property int maxWidth: 300
property int minHeight: 150
property int maxHeight: 250
property int rowWidth: root.width/3 //Change accordingly the width of each child item w.r.t. the width of the root.
Row {
id: layout
anchors.fill: parent
spacing: 6
Rectangle {
color: 'red'
// 4/3 is the aspect ratio of the first Rectangle
height: (3*width/4)<root.minHeight ? root.minHeight : ( (3*width/4)>root.maxHeight ? root.maxHeight : 3*width/4 )
width: (root.rowWidth) < root.minWidth ? root.minWidth : ( root.rowWidth > root.maxWidth ? root.maxWidth : root.rowWidth)
Text {
anchors.centerIn: parent
text: parent.width + 'x' + parent.height
}
}
Rectangle {
color: 'green'
// 3/4 is the aspect ratio of the second Rectangle
height: (4*width/3)<root.minHeight ? root.minHeight : ( (4*width/3)>root.maxHeight ? root.maxHeight : 4*width/3 )
width: (root.rowWidth) < root.minWidth ? root.minWidth : ( root.rowWidth > root.maxWidth ? root.maxWidth : root.rowWidth)
Text {
anchors.centerIn: parent
text: parent.width + 'x' + parent.height
}
}
}
}
Upvotes: 0