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.
Related
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.
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
}
}
}
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.
I would like to get the real width & height of a Text element. If I use the paintedWidth & paintedHeight properties, I don't get it. For example:
Rectangle {
color: "green"
width: a_text.paintedWidth
height: a_text.paintedHeight
Text {
id: a_text
text: "r"
color: "white"
anchors.centerIn: parent
}
}
If I run that code, I see some green space on the left of the "r" on top of the "r" and below the "r". So I'm not getting the real width & height of the Text. I mean, the width & height of the white pixels.
Any way to do it?
P.S. Also I would need the relative position of the real top-left corner of the text, I mean, the x & y of the top-left white pixel relative to the "official" top-left pixel of the Text.
The solution is to use the new TextMetrics element (requires QtQuick 2.5), and its tightBoundingRect property, to get the real width & heigth of the foreground text:
import QtQuick 2.5 // required!
Rectangle {
color: "green"
width: t_metrics.tightBoundingRect.width
height: t_metrics.tightBoundingRect.height
Text {
id: a_text
text: "r"
color: "white"
anchors.centerIn: parent
}
TextMetrics {
id: t_metrics
font: a_text.font
text: a_text.text
}
}
"your_text_object.paintedHeight" or "your_text_object.paintedWidth": is what you need to get the height of the text, including height past the height which is covered due to there being more text than fits in the set height.
Text QML Element paintedHeight
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.