Sizing
Our rectangle will fill its parent, so the size of the rectangle depends entirely on the size of its parent. Walking up the QML hierarchy, the component that contains the rectangle is the StackView element back in MasterView:
StackView { id: contentFrame initialItem: Qt.resolvedUrl("qrc:/views/SplashView.qml") }
Often, QML components are clever enough to size themselves based on their children. Previously, we had set our rectangle to a fixed size of 400 x 200. The StackView could look at that and say “I need to contain a single Rectangle that is 400 x 200, so I’ll make myself 400 x 200 too. Easy!”. We can always overrule that and set it to some other size using its width and height properties, but it can work out what size it wanted to be.
Back in scratchpad, create a new SizingDemo.qml view and edit main.cpp to load it on startup, just like we did with AnchorsDemo. Edit SizingDemo as follows:
import QtQuick 2.9 import QtQuick.Window 2.2
Window { visible: true width: 1024 height: 768 title: qsTr("Scratchpad") color: "#ffffff" Column { id: columnWithText Text { id: text1 text: "Text 1" } Text { id: text2 text: "Text 2" width: 300 height: 20 } Text { id: text3 text: "Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3" } Text { id: text4 text: "Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4" width: 300 } Text { id: text5 text: "Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5" width: 300 wrapMode: Text.Wrap } } Column { id: columnWithRectangle Rectangle { id: rectangle anchors.fill: parent } } Component.onCompleted: { console.log("Text1 - implicitWidth:" + text1.implicitWidth + " implicitHeight:" + text1.implicitHeight + " width:" + text1.width + " height:" + text1.height) console.log("Text2 - implicitWidth:" + text2.implicitWidth + " implicitHeight:" + text2.implicitHeight + " width:" + text2.width + " height:" + text2.height) console.log("Text3 - implicitWidth:" + text3.implicitWidth + " implicitHeight:" + text3.implicitHeight + " width:" + text3.width + " height:" + text3.height) console.log("Text4 - implicitWidth:" + text4.implicitWidth + " implicitHeight:" + text4.implicitHeight + " width:" + text4.width + " height:" + text4.height) console.log("Text5 - implicitWidth:" + text5.implicitWidth + " implicitHeight:" + text5.implicitHeight + " width:" + text5.width + " height:" + text5.height) console.log("ColumnWithText - implicitWidth:" + columnWithText.implicitWidth + " implicitHeight:" + columnWithText.implicitHeight + " width:" + columnWithText.width + " height:" + columnWithText.height) console.log("Rectangle - implicitWidth:" + rectangle.implicitWidth + " implicitHeight:" + rectangle.implicitHeight + " width:" + rectangle.width + " height:" + rectangle.height) console.log("ColumnWithRectangle - implicitWidth:" + columnWithRectangle.implicitWidth + " implicitHeight:" + columnWithRectangle.implicitHeight + " width:" + columnWithRectangle.width + " height:" + columnWithRectangle.height) } }
Run this, and you’ll get another screen full of nonsense:
Of far more interest to us here is what is output to the console:
qml: Text1 - implicitWidth:30 implicitHeight:13 width:30 height:13
qml: Text2 - implicitWidth:30 implicitHeight:13 width:300 height:20
qml: Text3 - implicitWidth:1218 implicitHeight:13 width:1218 height:13
qml: Text4 - implicitWidth:1218 implicitHeight:13 width:300 height:13
qml: Text5 - implicitWidth:1218 implicitHeight:65 width:300 height:65
qml: ColumnWithText - implicitWidth:1218 implicitHeight:124 width:1218 height:124
qml: Rectangle - implicitWidth:0 implicitHeight:0 width:0 height:0
qml: ColumnWithRectangle - implicitWidth:0 implicitHeight:0 width:0 height:0
So, what’s going on? We’ve created two Column elements, which are invisible layout components that arrange their child elements vertically. We’ve stuffed the first column with various Text elements and added a single Rectangle to the second. At the bottom of the view is a JavaScript function that will execute when the Window component has completed (that is, finished loading). All the function does is write out the implicitWidth, implicitHeight, width, and height properties of various elements on the view.
Let’s walk through the elements and the corresponding console lines:
Text { id: text1 text: "Text 1" }
qml: Text1 - implicitWidth:30 implicitHeight:13 width:30 height:13
This Text element contains a short piece of text, and we have not specified any sizes. Its implicitWidth and implicitHeight properties are the sizes the element wants to be based on its content. Its width and height properties are the sizes the element actually is. In this case, it will size itself however it wants to, because we haven’t specified otherwise, so its width/height are the same as its implicitWidth/implicitHeight:
Text { id: text2 text: "Text 2" width: 300 height: 20 }
qml: Text2 - implicitWidth:30 implicitHeight:13 width:300 height:20
With text2, the implicit sizes are the same as text1 as the content is virtually identical. However, this time, we have explicitly told it to be 300 wide and 20 high. The console tells us that the element is doing as it’s told and is indeed that size:
Text { id: text3 text: "Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3 Text 3" }
qml: Text3 - implicitWidth:1218 implicitHeight:13 width:1218 height:13
This text3 takes the same hands-off approach as text1, but with a much longer piece of text as its content. This time, implicitWidth is much larger as that is the amount of space it needs to fit the long text in. Note that this is actually wider than the window and the text gets cut off. Again, we haven’t instructed it otherwise, so it sizes itself:
Text { id: text4 text: "Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4 Text 4" width: 300 }
qml: Text4 - implicitWidth:1218 implicitHeight:13 width:300 height:13
The text4 has the same lengthy block of text, but we’ve told it what width we want this time. You’ll notice on screen that even though the element is only 300 pixels wide, the text is visible all the way across the window. The content is overflowing the bounds of its container. You can set the clip property to true to prevent this, but we’re not too concerned with that here:
Text { id: text5 text: "Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text
5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5
Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text
5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5 Text 5" width: 300 wrapMode: Text.Wrap }
qml: Text5 - implicitWidth:1218 implicitHeight:65 width:300 height:65
The text5 repeats the same long block of text and constrains the width to 300, but this time, we bring a bit of order to proceedings by setting the wrapMode property to Text.Wrap. With this setting, the enabled behavior is much more like what you would expect from a block of text—it fills up the available width and then wraps onto the next line. The implicitHeight and, consequently, the height of the element has increased to accommodate the contents. Note, however, that the implicitHeight is still the same as earlier; this is still the width the control wants to be in order to fit all of its content in, given the constraints we have defined, and we have defined no height constraint.
We then print out the properties of the column containing all this text:
qml: ColumnWithText - implicitWidth:1218 implicitHeight:124 width:1218 height:124
The important thing to note is that the column is able to figure out how wide and high it needs to be to accommodate all of its children.
Next, we get to the issue we encountered back in SplashView:
Column { id: columnWithRectangle Rectangle { id: rectangle anchors.fill: parent } }
Here, we have a chicken and egg scenario. The Column tries to work out how large it needs to be to contain its children, so it takes a look at Rectangle. Rectangle has no explicit size information and no children of its own, it is just set to fill its parent, the Column. Neither element can figure out how big they are supposed to be, so they both default to 0x0, which renders them invisible.
qml: Rectangle - implicitWidth:0 implicitHeight:0 width:0 height:0
qml: ColumnWithRectangle - implicitWidth:0 implicitHeight:0 width:0 height:0
Armed with this knowledge, let’s head back to MasterView and fix our earlier problem.
Add anchors.fill: parent to the StackView component:
StackView { id: contentFrame anchors.fill: parent initialItem: Qt.resolvedUrl("qrc:/views/SplashView.qml") }
The StackView will now fill its parent Window, which we have explicitly given a fixed size of 1024 x 768. Run the app again, and you should now have a lovely orange-yellow SplashView that fills the screen and happily resizes itself if you resize the window: