screen larger, fixed margins for QML buttons and images - qt

currently I have a qml application with specific sets of margins for each image. They look perfectly on a specific width of a screen. However if the screen enlarges, it will get all messed up and scattered around. Because the margins are set to a specific number. What is a better solution to this problem in qml ? I tried to set position: relative but that did not work.
for example:
we have two buttons
Button1 {
anchors {
right: parent.right
rightMargin: 175
bottom: parent.bottom
bottomMargin: 95
}
}
Button2 {
iconNext: true
anchors {
right: parent.right
rightMargin: 53
bottom: parent.bottom
bottomMargin: 95
}
}
These two buttons look superb on my screen. Terrible on a larger screen as they get parted away from each other.
What is a solution

You should be anchoring the buttons to each other, not both anchored to the parent, if you want them to maintain a certain distance from each other. Example:
Button1 {
anchors {
right: button2.left
rightMargin: 50
bottom: button2.bottom
}
}
Button2 {
id: button2
iconNext: true
anchors {
right: parent.right
rightMargin: 53
bottom: parent.bottom
bottomMargin: 95
}
}
That will make the spacing between the two buttons consistent (in pixels), even if the buttons themselves get bigger or smaller.
Then if you want the spacing to be relative (that is, relative to the size of the buttons or the size of the screen) rather than fixed in pixels, you could do something more like this:
Button1 {
id: button1
anchors {
right: button2.left
rightMargin: width
bottom: button2.bottom
}
}
Button2 {
id: button2
iconNext: true
anchors {
right: parent.right
rightMargin: width
bottom: parent.bottom
bottomMargin: height*2
}
}
This will maintain the relative spacing of the buttons. As they get bigger or smaller, their spacing scales to match. You can use this general idea of relative spacing in other ways. For example, instead of basing the spacing on the buttons size, it can be based on the size of the enclosing item (e.g. rightMargin: parent.width/10), or the entire screen, etc.

Related

QML Rectangle: Binding loop detected for property "width" / "height"

I'm trying to size a Rectangle to the size of its content:
ListView {
anchors.fill: parent
model: ["a", "b", "c"]
delegate: Rectangle {
color: "gray"
property int margin: 20
width: childrenRect.width + 2 * margin
height: childrenRect.height + 2 * margin
Text {
text: modelData
anchors.centerIn: parent
}
}
}
It seems to work visually, but the QML engine gives a lot of these errors:
qrc:/main.qml:13:19: QML Rectangle: Binding loop detected for property "width"
qrc:/main.qml:13:19: QML Rectangle: Binding loop detected for property "height"
Where is the binding loop and how to fix it?
The error comes from the item Rectangle: its size is based on its content (by using childrenRect). But, your Text is placed according to the size of its parent (by using centerIn).
The position of Textis based on the size of its parent (centered in the Rectangle). childrenRect holds the collective geometry of the children (such as bounding rect property). When Rectangle is resized, the position of Text changes also. Then, the childrenRect will change too to map the new position of Text.
So, you will create a loop if you map the size of Rectangle on the children rect property and you center Text in Rectangle.
A quick example to add a background to a text centered in a list view:
ListView {
id: list
anchors.fill: parent
model: ["a", "b", "c"]
delegate: Item {
property int margin: 20
anchors.left: parent.left // Take all the width
anchors.right: parent.right
height: 40 // The height is 0 by default
Rectangle { // Background under the text only. Will not fill the whole row
color: "gray"
anchors.centerIn: parent
width: text.width
height: text.height
}
Text {
id: text
text: modelData
anchors.centerIn: parent
}
}
}
It is not usual to bind delegate's width to its content (childrenRect). In most cases you need parent's width and fixed (or in rare cases dynamic) height. Check out this example - I use anchorsto adjust width and fixed heightof 80:
anchors {
left: parent.left
right: parent.right
}
height: 80
You may also be interested in Label positioning inside this component.

QML: how to anchor taking care of existing margins

Qt 5.10.1 under Windows 7. I'm trying to anchor some Components inside an Item with margins defined. I mean, I want to anchor taking in account for margins.
My code:
Item {
width: parent.width
anchors.margins: 100
Rectangle {
width: 50
height: 50
anchors.right: parent.right
}
}
I would expect the Rectangle will be positioned on the right side but 100 px from the edge. Instead it's placed just to the edge.
Of course I can add:
anchors.rightMargin: 100
but I have to do this manually for each children of the main Item. I wonder if there's a way to anchor taking care of existing margins.
If I understand well, your problem is not the position of the Rectangle but the position of the parent Item.
Since you define the width of the Item instead of using explicit anchors, the margins has no effect.
Try to position the Item using anchors instead of width:
Item {
anchors.fill: parent
anchors.margins: 100
Rectangle {
width: 50
height: 50
anchors.right: parent.right
}
}
The Item will be correctly positionned 100px from its parent and the Rectangle will be positionned at the edge of the Item.
Note that there is no "CSS padding - like" behavior in QML: you have to explicitely define in each child component how it fills the parent.
Edit (following your comment):
If using inside a Row or Column, as far as I know the only solution is to specify a rightMargin in every child.
About padding:
Padding does not exist in QML (except for Qt Quick Controls 2 components): declaring an item as a child of another item does not mean that it is visually located inside its parent. Thus the only way to position an element is by using anchors on every child.
If you want to simulate a padding in the parent item you can define it as a property and use it in every child:
Item {
readonly property int padding: 100
width: parent.width
height: parent.height
Rectangle {
width: 50
height: 50
anchors {
right: parent.right
margins: parent.padding
}
}
}
Or wrap the children in another Item:
Item {
width: parent.width
height: parent.height
Item {
anchors.fill: parent
anchors.rightMargin: 100
Rectangle {
width: 50
height: 50
anchors.right: parent.right
}
}
}

Qml Flickable overwrite content

I tried to enable scrolling of the content in my application using a Flickable.
Now content is scrollable, but content hides the top content.
Code:
Flickable {
anchors.top: pageMessagesHeader.bottom
anchors.topMargin: 20
boundsBehavior: Flickable.DragOverBounds
contentHeight: contentItem.childrenRect.height
contentWidth: contentItem.childrenRect.width
height: 500
width: 400
ScrollBar.vertical: ScrollBar {}
Rectangle {
color: "white"
height: 1000
width: 400
id: listMessages
}
}
Here you can find a sentence:
Flickable does not automatically clip its contents. If it is not used as a full-screen item, you should consider setting the clip property to true.
Which is the solution.
Just add
clip: true
to your code, and you'll be good.
Clipping has some perfomance disavantages which can greatly affect the application as it grows. Hence, its usage, especially outside the views scenario, should be evaluated carefully.

How to make ScrollView clip only vertically?

ScrollView clips all its contents to its size. Is it possible to make it work only for top and bottom but allow children to go out of parent's frame on the right and on the left?
If what you want is to only scroll in one direction, then just set the width/height of the content item to the width/height of the ScrollView, using property bindings (because items inside ScrollView are reparented to ScrollView.contentItem). The below example will scroll only vertically. I've tested it, if you need confirmation that it actually works.
Item {
ScrollView {
id: scrollview1
anchors.fill: parent
anchors.margins: 20
clip: true
ColumnLayout {
width: scrollview1.width
}
}
}
I can only imagine one reason, why you don't set the ScrollView's width to a higher value (the contentItem's width).
To be able to do so, while not constraining the ScrollView in it's width, you can use a simple trick:
Item {
id: limitedWidthItemToAnchorTo
width: 200 // the width the ScrollView was supposed to have
height: 400
ScrollView {
width: contentItem.width + __verticalScrollBar.width// Don't limit the width.
height: 400 // Limit only the height.
horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff // You don't need them.
contentItem: Rectangle {
width: 700 // This will set the ScrollViews width.
height: 600 // The height will be clipped by the ScrollView.
// You can scroll though.
gradient: Gradient {
GradientStop { position: 0; color: 'red' }
GradientStop { position: 1; color: 'blue' }
}
border.width: 10
}
}
}
You'll wrap it in the Item, anchor to this, and you'll be good.
Alternatively you could use masks, but this would be... more complicated.
Per se it is not possible to clip only horizontal or vertical, as the clipping is done using the Item's bounding box.

Scrollbars of ScrollView do not change when the picture is scaled in QML

In this code, when I click zoomIn rectangle, the picture does zoom in, but the default scrollbars of ScrollView do not change accordingly. They remain the same. Therefore I cannot scroll the zoomed picture.
Please point out the fault.
Rectangle {
id: zoomIn
height: 50; width: 50; color: "blue"
Text { text: qsTr("Zoom In") }
MouseArea {
anchors.fill: parent
onClicked: {
currentPicture.scale += 0.5
}
}
}
ScrollView {
id: head
anchors.top: buttons.bottom
anchors.topMargin: 30
height: 300; width: 300
frameVisible: true
Image {
id: currentPicture
height: head.height; width: head.width
source: folderModel1.hh
z:0
}
}
The scale property doesn't affect the width and height of the item that it's applied to:
A scale of less than 1.0 causes the item to be rendered at a smaller size, and a scale greater than 1.0 renders the item at a larger size.
ScrollView depends on the width and height of the contentItem:
The width and height of the child item will be used to define the size of the content area.
Since you're upscaling the image anyway, you can probably just increase the width and height instead of the scale.
Why is the scale property there if we can bypass it without any side effects?
They have different purposes. One example that I can think of is animations in a grid. Take, for example, the inventory grid in a game. The items fit within the grid, and the grid expects them to all be the same width and height. If you want to animate a mouse-over effect that makes an item larger as it's hovered by the mouse, you can use the scale so that you don't affect the actual width and height. So, layouting could be one reason.

Resources