Items not correctly spread across GridLayout - qt

I have the following custom QML Item, which will represent a pin code entry GUI element:
import QtQuick 2.0
import QtQuick.Layouts 1.2
import QtQuick.Controls 1.3
import "../items"
Item
{
id: ueKeypad
width: 512
height: 512
Rectangle
{
id: ueKeypadWrapper
antialiasing: true
anchors.fill: parent
ColumnLayout
{
id: ueKeypadLayoutMain
antialiasing: true
layoutDirection: Qt.LeftToRight
spacing: 8
anchors.fill: parent
ColumnLayout
{
id: ueKeypadTitleLayout
layoutDirection: Qt.LeftToRight
Layout.fillWidth: true
Layout.minimumHeight: 24
Layout.preferredHeight: 24
Layout.maximumHeight: 24
Text
{
Layout.fillWidth: true
Layout.fillHeight: true
text: qsTr("PIN ENTRY")
clip: true
font.bold: true
font.pointSize: 24
textFormat: Text.RichText
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
} // Text
} // ColumnLayout
GridLayout
{
id: ueKeypadNumbersLayout
Layout.fillWidth: true
Layout.fillHeight: true
Layout.alignment: Qt.AlignHCenter|Qt.AlignVCenter
layoutDirection: Qt.LeftToRight
columnSpacing: 8
rowSpacing: 8
flow: GridLayout.LeftToRight
columns: 3
UeButton
{
id: ueKeypadButton1
Layout.minimumHeight: 32
Layout.preferredHeight: 32
Layout.maximumHeight: 32
ueText: qsTr("1")
}
UeButton
{
id: ueKeypadButton2
Layout.minimumHeight: 32
Layout.preferredHeight: 32
Layout.maximumHeight: 32
ueText: qsTr("2")
}
UeButton
{
id: ueKeypadButton3
Layout.minimumHeight: 32
Layout.preferredHeight: 32
Layout.maximumHeight: 32
ueText: qsTr("3")
}
UeButton
{
id: ueKeypadButton4
Layout.minimumHeight: 32
Layout.preferredHeight: 32
Layout.maximumHeight: 32
ueText: qsTr("4")
}
UeButton
{
id: ueKeypadButton5
Layout.minimumHeight: 32
Layout.preferredHeight: 32
Layout.maximumHeight: 32
ueText: qsTr("5")
}
UeButton
{
id: ueKeypadButton6
Layout.minimumHeight: 32
Layout.preferredHeight: 32
Layout.maximumHeight: 32
ueText: qsTr("6")
}
UeButton
{
id: ueKeypadButton7
Layout.minimumHeight: 32
Layout.preferredHeight: 32
Layout.maximumHeight: 32
ueText: qsTr("7")
}
UeButton
{
id: ueKeypadButton8
Layout.minimumHeight: 32
Layout.preferredHeight: 32
Layout.maximumHeight: 32
ueText: qsTr("8")
}
UeButton
{
id: ueKeypadButton9
Layout.minimumHeight: 32
Layout.preferredHeight: 32
Layout.maximumHeight: 32
ueText: qsTr("9")
}
} // GridLayout
RowLayout
{
id: ueKeypadActionLayout
Layout.fillWidth: true
Layout.fillHeight: true
Layout.alignment: Qt.AlignHCenter|Qt.AlignVCenter
layoutDirection: Qt.LeftToRight
spacing: 8
UeButton
{
id: ueKeypadButtonOk
ueText: qsTr("Ok")
} // UeButton
UeButton
{
id: ueKeypadButton0
ueText: qsTr("0")
Layout.minimumHeight: 32
Layout.preferredHeight: 32
Layout.maximumHeight: 32
} // UeButton
UeButton
{
id: ueKeypadButtonCancel
ueText: qsTr("Cancel")
} // UeButton
} // RowLayout
} // ColumnLayout
} // Rectangle
} // Item
It uses custom QML Button, named UeButton:
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtQuick 2.5
Button
{
property string ueText
id: ueButton
text: ueText
style: ButtonStyle
{
background: Rectangle
{
antialiasing: true
smooth: true
gradient: Gradient
{
GradientStop
{
position: 0
color: "#ffffff"
} // GradientStop
GradientStop
{
position: 0.418
color: "#000000"
} // GradientStop
} // Gradient
border.color: "steelblue"
border.width: control.activeFocus?2:1
radius: 4
} // background
label: Text
{
color: "#ffffff"
font.bold: true
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
font.pointSize: 16
text: control.text
} // label
} // ButtonStyle
} // ueButton
If I view first code in QtCreator's Designer Tool, I get the following situation:
Why are Buttons not spread across GridLayout? Same goes to lower RowLayout, whose Items (three Items of type UeButton) are not centered and aligned across whole RowLayout?

The attached properties of a Layout ensures that the Items contained are correctly sized w.r.t. the given constraints.
Items can be stretched to fill the available space (fillWidth/fillHeight), forced to not shrink under a certain value (minimumWidth/minimumHeight) or not enlarge over a certain other value (maximumWidth/maximumHeight). You can also force an Item to occupy more than one row/column (rowSpan/columnSpan) and to assume a specific size (preferredWidth/preferredHeight which implies minimum == maximum).
The precedence is:
preferred <minimum/maximum < width/height
Setting a property to the left automatically discard any to the right. You can easily understand the reasoning behind this. This scheme can be somewhat "broken" by implicitWidth/implicitHeight since the size of any Item cannot shrink under these values. fill properties ensure that the Item fills the available space, according to the constrains above: if fill is not defined an Item cannot grow or shrink according to its constrains.
Now, if you want the Buttons to maintain they aspect and still stretch the grid, you can use an intermediate Item. While applying Layout attached properties to the external Item, the Buttons can be centerIn it and be unaffected.
Sample code:
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.4
Window {
width: 200; height: 200; minimumHeight: 100; visible: true
GridLayout {
anchors.fill: parent
rows: 3
columns: 3
Repeater {
model: 9
Item {
Layout.fillWidth: true
Layout.fillHeight: true
Button { anchors.centerIn: parent; width: 32; height: 32; text: index + 1 }
}
}
}
}
Instead if you want the Buttons to fill the available space, just specify fillWidth/fillHeight. Since no other layout constraints are set (e.g. minimum*, maximum*) the Buttons correctly occupy all the available space. Here is the code above revisited. As expected, width and height are simply discarded:
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.4
Window {
width: 200; height: 200; minimumHeight: 100; visible: true
GridLayout {
anchors.fill: parent
rows: 3
columns: 3
Repeater {
model: 9
Button {width: 32; height: 32; text: index + 1; // 32? NOPE!
Layout.fillWidth: true; Layout.fillHeight: true
}
}
}
}

Related

How to evenly shrink items in layout to make space for more items

Initially, I have four items with a specific size. Once a 5th item gets added, I would like to shrink the size of all items to make space inside the layout.
Window {
width: 640
height: 480
visible: true
id: root
Item {
id: col
width: 300
height: 200
anchors.centerIn: parent
RowLayout {
id: row
spacing: 10
anchors.centerIn: parent
Rectangle {
Layout.minimumWidth: 30
Layout.preferredWidth: 60
Layout.preferredHeight: 20
Layout.fillWidth: true
color: "red"
}
Rectangle {
Layout.minimumWidth: 30
Layout.preferredWidth: 60
Layout.preferredHeight: 20
color: "blue"
Layout.fillWidth: true
}
Rectangle {
Layout.minimumWidth: 30
Layout.preferredWidth: 60
Layout.preferredHeight: 20
color: "green"
Layout.fillWidth: true
}
Rectangle {
Layout.minimumWidth: 30
Layout.preferredWidth: 60
Layout.preferredHeight: 20
color: "green"
Layout.fillWidth: true
}
Rectangle {
Layout.minimumWidth: 30
Layout.preferredWidth: 60
Layout.preferredHeight: 20
color: "blue"
}
}
}
// for visualization
Rectangle {
width: col.width
height: col.height
x: col.x
y: col.y
color: "black"
opacity: 0.3
}
}
The items should have a size of 60 if there's space to fit all items, or scale down to 30 if there isn't. Any ideas how I would accomplish that?
You were almost there: Set Layout.maximumWidth instead of Layout.preferredWidth and make sure all the elements have Layout.fillWidth set to true. Also, the layout element itself must have the correct size for fillWidth to work. So replace centerIn with fill in this case.
Here is your snippet; corrected and rewritten to make it easier to try out different numbers of elements.
import QtQuick 2.14
import QtQuick.Layouts 1.14
import QtQuick.Controls 2.14
import QtQuick.Window 2.14
Window {
width: 640
height: 480
visible: true
id: root
Item {
id: col
width: 300
height: 200
anchors.centerIn: parent
RowLayout {
id: row
spacing: 10
anchors.fill: parent
Repeater {
model: spinBox.value
delegate: Rectangle {
Layout.minimumWidth: 30
Layout.maximumWidth: 60
Layout.preferredHeight: 20
Layout.fillWidth: true
color: ["red", "blue", "green", "green", "blue"][index % 5]
}
}
}
}
// for visualization
Rectangle {
width: col.width
height: col.height
x: col.x
y: col.y
color: "black"
opacity: 0.3
}
SpinBox {
id: spinBox
from: 1; to: 10
value: 5
}
}

How to load and display QML file

I have two QML pages main.qml and Kos.qml,
what i want is when a button in main.qml clicked it load Kos.qml in the screen.
i did try using loader, but it is not working
import QtQuick 2.5
import QtQuick.Controls 2.5
ApplicationWindow {
id: applicationWindow
width: 640
height: 480
color: "#fc4343"
title: qsTr("Tabs")
visible: true
// HALAMAN UTAMA
Page {
anchors.centerIn: parent
anchors.fill: parent
id: page
enabled: true
Loader{
id: kos
active: true
anchors.fill: parent
}
Button {
id: button
x: 198
width: 87
height: 30
text: qsTr("Search")
font.bold: true
anchors.top: borderImage.bottom
anchors.topMargin: 198
anchors.right: toolSeparator.left
anchors.rightMargin: 28
MouseArea{
anchors.fill: parent
onClicked:{
kos.source = "Kos.qml";
}
}
background: Rectangle {
id: background
color: "#ef3644"
}
contentItem: Text {
id: textItem
font: control.font
opacity: enabled ? 1.0 : 0.3
color: "white"
text: "Search"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
}
}
}
Kos.qml i use PageBackground as a background
import QtQuick 2.4
PageBackground {
id: kos
width: 640
height: 480
Text {
id: element
x: 6
y: 20
width: 24
height: 32
color: "#ffffff"
text: qsTr("<")
font.strikeout: false
styleColor: "#ffffff"
font.underline: false
font.italic: false
font.bold: true
font.pixelSize: 25
MouseArea {
id: mouseArea
anchors.rightMargin: 0
anchors.bottomMargin: 0
anchors.leftMargin: 0
anchors.topMargin: 0
anchors.fill: parent
}
}
}
did i messed up somewhere?
I tried to run your code. Since I am not aware of what your PageBackground is, I changed that to Rectangle. That works for me. Try to start from the minimal code then add your styles and functions on top of it. Try with below minimal code. Keep both main.qml & Kos.qml in the same directory and ensure both files added to qml resources.
main.qml
import QtQuick 2.9
import QtQuick.Controls 2.2
ApplicationWindow {
id: applicationWindow
width: 640
height: 480
visible: true
Text {
anchors.centerIn: parent
text: "App window"
}
Loader {
id: loaderId
anchors.fill: parent
source: ""
}
Button {
text: "click me!!"
width: parent.width
anchors.bottom: parent.bottom
onClicked: {
if(loaderId.source == "")
loaderId.source = "Kos.qml"
else
loaderId.source = ""
}
}
}
Kos.qml
import QtQuick 2.9
Rectangle {
id: kos
width: 640
height: 480
color: "grey"
Text {
anchors.centerIn: parent
text: "<b>Loaded Item</b>"
color: "white"
}
}

Centering a group of QML widgets without changing their relative alignment

The short version
I'd like to horizontally and/or vertically center groups of QML widgets without being forced to align them in a structured layout.
The long version
I made the following design:
My QML code so far is as follows. (I know the hardcoded X/Y coordinates are sloppy, it's just a mockup.)
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Shapes 1.11
import QtQuick.Controls 2.3
import QtQuick.Layouts 1.0
Window {
id: window
visible: true
width: 640
height: 480
color: "#f0eded"
title: qsTr("Hello World")
Image {
id: image
x: 215
y: 96
sourceSize.height: 210
sourceSize.width: 210
source: "lock.svg"
}
Text {
id: element
y: 364
anchors.horizontalCenter: parent.horizontalCenter
color: "#646464"
text: qsTr("Unlock your rclone configuration to continue.")
anchors.horizontalCenterOffset: 0
styleColor: "#00000000"
horizontalAlignment: Text.AlignHCenter
font.pixelSize: 12
}
TextField {
id: txtPassword
x: 193
y: 312
focus: true
font.pointSize: 22
horizontalAlignment: Text.AlignHCenter
echoMode: TextInput.Password
}
Button {
id: btnContinue
x: 399
y: 312
width: txtPassword.height
height: txtPassword.height
text: qsTr("»")
background: Rectangle {
border.color: btnContinueMouse.containsMouse ? "#cdcdcd" : "#ccc"
color: btnContinueMouse.containsMouse ? "#eee" : "#ddd"
}
MouseArea {
id: btnContinueMouse
anchors.fill: parent
hoverEnabled: true
}
}
}
What I'd like to do is to horizontally and vertically center this group of widgets so that its alignment still makes sense if a user increases the size of the window. I know I can put widgets into a row/column/grid layout for such purposes, but then I lose a lot of control over the space between the widgets.
What approach would you recommend to turn this mockup into clean QML code while staying true to the original design?
Two ways:
Wrap it in an Item, then
Use anchors to position your content relative to the screen like this:
Item {
anchors.fill: parent
Image {
id: image
anchors.left: parent.left
anchors.right: parent.right
sourceSize.height: 210
sourceSize.width: 210
source: "lock.svg"
}
Text {
id: element
anchors.top: txtPassword.bottom
anchors.left: txtPassword.left
anchors.right: btnContinue.right
color: "#646464"
text: qsTr("Unlock your rclone configuration to continue.")
styleColor: "#00000000"
horizontalAlignment: Text.AlignHCenter
font.pixelSize: 12
}
OR
Create separate components out of the different parts then place them as a whole into a layout. Do this by moving your elements into a separate file then referencing that file using its name:
example:
LockElement { anchors.centerIn: parent }
will load LockElement.qml which will have your Item, Image, TextBox etc all in one file.
This will make the coordinates relative to their own coordinate space.
LockElement.qml
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Shapes 1.11
import QtQuick.Controls 2.3
import QtQuick.Layouts 1.0
Item {
width: 640
height: 480
Image {
id: image
x: 215
y: 96
sourceSize.height: 210
sourceSize.width: 210
source: "lock.svg"
}
Text {
id: element
y: 364
anchors.horizontalCenter: parent.horizontalCenter
color: "#646464"
text: qsTr("Unlock your rclone configuration to continue.")
anchors.horizontalCenterOffset: 0
styleColor: "#00000000"
horizontalAlignment: Text.AlignHCenter
font.pixelSize: 12
}
TextField {
id: txtPassword
x: 193
y: 312
focus: true
font.pointSize: 22
horizontalAlignment: Text.AlignHCenter
echoMode: TextInput.Password
}
Button {
id: btnContinue
x: 399
y: 312
width: txtPassword.height
height: txtPassword.height
text: qsTr("»")
background: Rectangle {
border.color: btnContinueMouse.containsMouse ? "#cdcdcd" : "#ccc"
color: btnContinueMouse.containsMouse ? "#eee" : "#ddd"
}
MouseArea {
id: btnContinueMouse
anchors.fill: parent
hoverEnabled: true
}
}
}
// etc..

Qt ColumnLayout full screen

Qt: 5.11.1
OS: Windows 10 64bit
This is Qt Quick application. when the window is in full screen mode. The layout becomes strange. I think it's an afterimage of the previous size.
startup
full screen
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Layouts 1.3
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
ColumnLayout{
spacing: 2
anchors.fill: parent
Rectangle {
Layout.alignment: Qt.AlignCenter
color: "red"
Layout.preferredWidth: 40
Layout.preferredHeight: 40
}
Rectangle {
Layout.alignment: Qt.AlignRight
color: "green"
Layout.preferredWidth: 40
Layout.preferredHeight: 70
}
Rectangle {
Layout.alignment: Qt.AlignBottom
Layout.fillHeight: true
color: "blue"
Layout.preferredWidth: 70
Layout.preferredHeight: 40
}
Rectangle {
Layout.alignment: Qt.AlignBottom
Layout.fillHeight: true
color: "orange"
Layout.preferredWidth: 70
Layout.preferredHeight: 40
}
}
}
Not an answer, but a simplification of the problem
import QtQuick 2.11
import QtQuick.Window 2.11
Window {
visible: true
width: 640
height: 480
// Works with any Item
Rectangle {
anchors.centerIn: parent
color: "red"
width: 40
height: 40
}
}
How to reproduce
On Windows 10, click on the window's maximize button
Previous frame is not cleared
Could be related to https://bugreports.qt.io/browse/QTBUG-54451
New bug created https://bugreports.qt.io/browse/QTBUG-70570

QML/QtQuick: make Image occupy only available height in ColumnLayout

I'm developing a mobile app with QML/QtQuick and Qt 5.9.x (Qt 5.10+ is not an option because it doesn't support iOS 8 and 9).
In my vertical layout I'd like to make Image be automatically resized to available height, but I can't figure out how to achieve this: it's always shown in full height. My QML file:
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
ApplicationWindow {
id: window
visible: true
// simulate iPhone 6
width: 375
height: 667
ColumnLayout {
anchors.fill: parent
spacing: 0
Text {
text: qsTr("multiline text multiline text multiline text multiline text")
textFormat: Text.PlainText
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
font { weight: Font.Normal; pointSize: 18 }
Layout.fillWidth: true
Layout.topMargin: 20
}
Text {
text: qsTr("title1")
textFormat: Text.PlainText
font { weight: Font.DemiBold; pointSize: 50 }
Layout.alignment: Qt.AlignHCenter
Layout.topMargin: 30
}
Text {
text: qsTr("title2")
textFormat: Text.PlainText
font { weight: Font.DemiBold; pointSize: 25 }
Layout.alignment: Qt.AlignHCenter
}
Image {
source: "qrc:/Painting.jpg"
verticalAlignment: Image.AlignTop
fillMode: Image.PreserveAspectCrop
// Layout.preferredHeight: 200 // that's how I obtained the second screenshot, but using a constant is not an option of course
Layout.alignment: Qt.AlignHCenter
Layout.topMargin: 20
}
Text {
text: qsTr("multiline text multiline text multiline text multiline text")
textFormat: Text.PlainText
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
font { weight: Font.Normal; pointSize: 17 }
Layout.fillWidth: true
Layout.topMargin: 20
}
GridLayout {
Layout.maximumWidth: 300
Layout.alignment: Qt.AlignHCenter
Layout.topMargin: 20
Layout.bottomMargin: 30
rows: 3
columns: 3
rowSpacing: 10
columnSpacing: 10
Rectangle {
color: "blue"
Layout.row: 0
Layout.column: 0
Layout.columnSpan: 3
Layout.fillWidth: true
Layout.preferredHeight: 25
}
Rectangle {
color: "blue"
Layout.row: 1
Layout.column: 0
Layout.fillWidth: true
Layout.preferredHeight: 25
}
Rectangle {
color: "blue"
Layout.row: 1
Layout.column: 1
Layout.columnSpan: 2
Layout.fillWidth: true
Layout.preferredHeight: 25
}
Rectangle {
color: "blue"
Layout.row: 2
Layout.column: 0
Layout.fillWidth: true
Layout.preferredHeight: 25
}
Rectangle {
color: "blue"
Layout.row: 2
Layout.column: 1
Layout.fillWidth: true
Layout.preferredHeight: 25
}
Rectangle {
color: "blue"
Layout.row: 2
Layout.column: 2
Layout.fillWidth: true
Layout.preferredHeight: 25
}
}
}
}
First image is how it's shown now, second one is how I want it to be: (screenshots are from desktop, but on mobile the result is the same)
I know how to achieve the desired behavior on iOS through AutoLayout (play with image's hugging priority and/or compression resistance), but I can't find anything similar in QML/QtQuick.
Using Layout.fillHeight will automatically resize the Image to the available height:
Image {
// ...
fillMode: Image.PreserveAspectCrop
Layout.fillHeight: true
}

Resources