I have some experience with Qt Widgets, but only recently started to use QML.
The problem I face is that I'd like some layouts defined in QML to automatically adjust to fit their contents. This works, but not dynamically, i.e. if the content changes the layout does not adapt. With the old-style (non-QML) Layout/Widget approach, this happened automatically.
Here is an example (my code looks different and consists of different files, but I pasted this MWE together to demonstrate the problem):
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 1.0
import QtQuick.Layouts 1.2
Window {
id: root
visible: true
width: 640
height: 480
property var nbx: 3
Column {
RowLayout {
Repeater {
model: 3
Rectangle {
width: childrenRect.width
height: childrenRect.height
color: "green"
ColumnLayout {
Rectangle {
height: 10
}
RowLayout {
Repeater {
model: root.nbx
Rectangle {
width: 20
height: 20
color: "orange"
}
}
}
}
}
}
}
Button {
text: "5 boxes"
onClicked: root.nbx= 5;
}
Button {
text: "2 boxes"
onClicked: root.nbx = 2;
}
}
}
How can I achieve the same with QML?
You can make it work by setting the implicit size of the green Rectangle to the implicit size of the child ColumnLayout. I'm not exactly sure why, it seems the childrenRect properties are not propertly updated.
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 1.0
import QtQuick.Layouts 1.2
Window {
id: root
visible: true
width: 640
height: 480
property var nbx: 3
ColumnLayout {
RowLayout {
Repeater {
model: 3
Rectangle {
implicitHeight: col1.implicitHeight // <--- here is the change
implicitWidth: col1.implicitWidth
color: "green"
ColumnLayout {
id: col1
Rectangle {
height: 10
}
RowLayout {
Repeater {
model: root.nbx
Rectangle {
width: 20
height: 20
color: "orange"
}
}
}
}
}
}
}
Button {
text: "5 boxes"
onClicked: root.nbx= 5;
}
Button {
text: "2 boxes"
onClicked: root.nbx = 2;
}
}
}
Related
I would like to know if it is possible to replace/redefine a parent's inline component. There are ways to do so with a 'classic' component; for example, I can assign the component to a property and re-define the property:
Super.qml
import QtQuick 2.0
import QtQuick.Controls 2.12
Rectangle {
property Component classicComponent: Text { text: "Hello" }
width: 60
height: 30
border.color: "blue"
border.width: 2
Loader {
id: loader
sourceComponent: classicComponent
}
}
main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
Window {
width: 80
height: 90
visible: true
title: qsTr("Hello World")
Column {
x: 10; y: 10
spacing: 10
Super { }
Super {
classicComponent: Label {
text: "World"
background: Rectangle { color: "#30DD0000" }
}
}
}
}
I would like to know if it is possible to do something conceptually similar, but with an inline component. I have not found any way to combine an inline component with a property, and if I try something like:
InlineParent.qml
Rectangle {
component Foo: Text { text: "Hello" }
Foo {}
}
and
Child.qml
InlineParent {
component Foo: Label {
text: "World"
background: Rectangle { color: "#30DD0000" }
}
}
Both will print "Hello". Obviously, there are better ways to add a red background to an Item (such as Text); the concept I am interested in is in having the subclass redefine a component declared in the superclass/parent class.
After getting some sleep, I found that it IS possible to place an inline component in a property, allowing a subclass to redefine it or expand it.
Super.qml
import QtQuick 2.0
import QtQuick.Controls 2.12
Rectangle {
property Component inlineComponent: Foo {}
component Foo: Text { text: "Hello" }
width: 60
height: 30
border.color: "blue"
border.width: 2
Loader {
id: loader
sourceComponent: inlineComponent
}
}
main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
Window {
width: 80
height: 130
visible: true
title: qsTr("Hello World")
Column {
x: 10; y: 10
spacing: 10
Super { }
Super {
inlineComponent: Label {
text: "World"
background: Rectangle { color: "#30dd0000" }
}
}
Super {
inlineComponent: Super.Foo {
text: "World"
Rectangle {
color: "#30dd0000"
anchors.fill: parent
}
}
}
}
}
It solved my problem, allowing me to replace or extend Foo.
I have a QML code like this:
MyItem.qml:
import QtQuick 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.3
Item {
id: root
width: parent.width
height: grid.height
Rectangle {
anchors.fill: root
color: "blue"
z: -1
}
Flow {
id: grid
width: parent.width
spacing: 5
Button {
text: qsTr("Button 1")
}
Button {
text: qsTr("Button 2")
}
Button {
text: qsTr("Button 3")
}
}
}
main.qml:
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.3
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
ColumnLayout {
anchors.fill: parent
Button {
Layout.fillWidth: true
Layout.fillHeight: true
text: "hello"
}
MyItem {
Layout.fillWidth: true
}
}
}
If the Flow is wide enough for all three buttons to be at the same line (as with RowLayout) there is an extra empty space at the bottom of the Flow (approximately Button.height * 2). Looks like the Flow height is always calculated as the sum of all its element heights.
What is the logic behind this behavior? How to make the Flow fit its content height?
EDIT1: It is not Flow, but 'root' item has the wrong height.
EDIT2: Download the sample app
The problem with your code is that the root element the expressions:
anchors.fill: parent
height: grid.height
are competing, in the first expression you indicate that the dimensions of the root will take the size of the window and this implies the height but in the next expression you are indicating that the height will no longer be from the window but from the grid, so that generates an indefinite behavior. The only solution is to establish that the width of the root item is that of the window.
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Item {
id: root
height: grid.height
width: parent.width
Rectangle {
anchors.fill: root
color: "blue"
}
Flow {
id: grid
width: parent.width
spacing: 5
Button {
text: qsTr("Button 1")
}
Button {
text: qsTr("Button 2")
}
Button {
text: qsTr("Button 3")
}
}
}
}
Update:
It seems that you do not know how they work (read https://doc.qt.io/qt-5/qml-qtquick-layouts-layout.html#details), by default the height that is taken is the implicitHeight.
Also if you use layout you should not set anchors in the items that are directly affected by the layouts, in your case the CommandsTab is affected by the Layout so you should not use width: parent.width, is unnecesary.
CommandsTab.qml
import QtQuick 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.3
Item {
id: root
implicitHeight: grid.height
Rectangle {
anchors.fill: root
color: "blue"
z: -1
}
Flow {
id: grid
width: parent.width
spacing: 5
Button {
text: qsTr("Button 1")
}
Button {
text: qsTr("Button 2")
}
Button {
text: qsTr("Button 3")
}
}
}
main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.3
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
ColumnLayout {
anchors.fill: parent
Button {
Layout.fillWidth: true
Layout.fillHeight: true
text: "hello"
}
CommandsTab {
Layout.fillWidth: true
}
}
}
I am trying to create a grid, consisting of squares. It is a 6X4 grid. The code which I am using to make the grid is below
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Layouts 1.3
import QtQuick.Controls 1.4
import QtQuick.Window 2.3
Window {
visible: true
width: 640
height: 480
title: qsTr("Mini Keno")
ColumnLayout {
spacing: 1
Item {
Row {
spacing: 1
Repeater {
id: mmm
model: 5
Rectangle {
id: imgl
width: 50
height: 50
color: "#4286f4"
property string src: ""
MouseArea {
anchors.fill: parent
onClicked: {
parent.color = "4286f4"
parent.color = "#2345F6"
}
}
}
}
}
}
Item {
Row {
spacing: 1
Repeater {
id: mm2
model: 5
Rectangle {
id: img2
width: 50
height: 50
color: "#4286f4"
property string src: ""
MouseArea {
anchors.fill: parent
onClicked: {
parent.color = "4286f4"
parent.color = "#2345F6"
}
}
}
}
}
}
}
}
This code is I am trying to create two lines of the grid, but the other line is not visible. So how to solve this problem of the grid where the squares are clickable. Also, how can I place the grid in the middle of the window?
height and width properties missing for Item, so Item has zero height, width. So the second row is overlapped with the first row.
Use anchors to make the layout in center, i.e anchors.centerIn: parent
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Layouts 1.3
import QtQuick.Controls 1.4
import QtQuick.Window 2.3
Window {
visible: true
width: 640
height: 480
title: qsTr("Mini Keno")
ColumnLayout {
anchors.centerIn: parent // place layout in center
spacing: 1
height: 100
Item {
width: 300 // widht of item
height: 50 // height of item
Row {
spacing: 1
Repeater {
id: mmm
model: 5
Rectangle {
id: imgl
width: 50
height: 50
color: "#4286f4"
property string src: ""
MouseArea {
anchors.fill: parent
onClicked: {
parent.color = "4286f4"
parent.color = "#2345F6"
}
}
}
}
}
}
Item {
width: 300 // widht of item
height: 50 // height of item
Row {
spacing: 1
Repeater {
id: mm2
model: 5
Rectangle {
id: img2
width: 50
height: 50
color: "#4286f4"
property string src: ""
MouseArea {
anchors.fill: parent
onClicked: {
parent.color = "4286f4"
parent.color = "#2345F6"
}
}
}
}
}
}
}
}
I am attempting a simple RowLayout of Rectangles. (See code below.) When I attempt to compile/run this in Qt Creator, I get:
qrc:/main.qml:31 Do not create objects of type Layout
when I attempt to use either Layout.minimumWidth:200 or Layout { minimumWidth:200 }
The Qt documentation for RowLayout shows the first form working. What am I missing?
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
ApplicationWindow {
id: window
title: "RB3Jay"
width:1280; height:960
minimumWidth:600; minimumHeight:300
visible: true
Rectangle {
id: pseudocontent
height: parent.height - (header.height + footer.height)
color:'orange'
anchors {
top:header.bottom
bottom:footer.top
left:parent.left
right:parent.right
}
}
header: RowLayout {
id: header
spacing: 0
height: 100
width: parent.width
Rectangle {
color:'red'
Layout {
minimumWidth:200; maximumWidth:200; preferredWidth:200
fillHeight:true
}
}
Rectangle {
color:'green'
Layout {
minimumWidth: 200
preferredWidth: parent.width*0.7
fillWidth:true; fillHeight:true
}
}
Rectangle {
color:'blue'
Layout {
minimumWidth: 200
preferredWidth: parent.width*0.3
fillWidth:true; fillHeight:true
}
}
}
footer: Inspector {
id: footer
height:100
}
}
While the foo { bar: 1; baz: 2 } -syntax works for grouped properties, Foo { } is reserved for creating an instance of QML type Foo. For attached properties, you must use the Foo.bar: 1 -syntax.
Layout is not a creatable type, it only provides attached properties. Therefore you must use the Foo.bar: 1 -syntax.
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
ApplicationWindow {
id: window
title: "RB3Jay"
width:1280; height:960
minimumWidth:600; minimumHeight:300
visible: true
Rectangle {
id: pseudocontent
height: parent.height - (header.height + footer.height)
color:'orange'
anchors {
top:header.bottom
bottom:footer.top
left:parent.left
right:parent.right
}
}
header: RowLayout {
id: header
spacing: 0
height: 100
width: parent.width
Rectangle {
color:'red'
Layout.minimumWidth:200
Layout.maximumWidth:200
Layout.preferredWidth:200
Layout.fillHeight:true
}
Rectangle {
color:'green'
Layout.minimumWidth: 200
Layout.preferredWidth: parent.width*0.7
Layout.fillWidth:true; Layout.fillHeight:true
}
Rectangle {
color:'blue'
Layout.minimumWidth: 200
Layout.preferredWidth: parent.width*0.3
Layout.fillWidth:true; Layout.fillHeight:true
}
}
footer: Inspector {
id: footer
height:100
}
}
I have to put component X inside of a ScrollView. Component X has to handle mouse wheel event, but ScrollView handles it. So, following example (simplified) doesn't work.
How to let Rectangle's mouse area handle OnWheel event?
import QtQuick 2.1
import QtQuick.Controls 1.0
import QtQuick.Window 2.0
import QtQuick.Layouts 1.0
ApplicationWindow {
width: 640
height: 480
ScrollView {
height: 100
width: 100
ColumnLayout{
Rectangle {
color: "red"
width: 50
height: 50
MouseArea {
anchors.fill: parent
onWheel: {
console.log("onWheel"); // it doesn't work
}
onClicked: {
console.log("onClicked"); // it works
}
}
}
}
}
}
This as actually a bug in Qt:
https://bugreports.qt.io/browse/QTBUG-38083
This is being resolved in:
https://codereview.qt-project.org/#change,82572
https://codereview.qt-project.org/#change,82576
I find a way to solve it, but I can't properly explain it. :(
This document illustrates the concept of visual parent and object parent, but it dosen't tell how they affect the event propagation.
Hope someone would give a clear explaination.
ApplicationWindow {
width: 640
height: 480
ScrollView {
id: scroll // add an id
height: 100
width: 100
ColumnLayout{
Rectangle {
id: rect // add an id
color: "red"
width: 50
height: 50
MouseArea {
parent: scroll // specify the `visual parent`
anchors.fill: rect // fill `object parent`
onWheel: {
console.log("onWheel"); // now it works
}
onClicked: {
console.log("onClicked"); // it works
}
}
}
Repeater {
model: 30
Text{ text: index }
}
}
}
}