QML Flickable Issues - qt

I need a horizontal controller consisting of a background and moving thumb-stick. It requires the following behaviours:
Initially centred, the thumb-stick can drag to the left or right within the background bounds.
When the drag is released, the thumb-stick re-centres itself.
If a part of the background is touched, the thumb-stick jumps to the touch.
If the touch is released, the thumb-stick re-centres itself.
If a drag is made following the touch, the thumb-stick will drag from the touched position.
Problems:
On touch, the thumb-stick jumps to the TouchPoint as required. However if a drag immediately follows the touch, the thumb-stick jumps back to the position it was in before the touch, before initiating the drag.
If the thumb-stick is dragged to the right and released, it immediately jumps back to centre as required. If it is dragged to the left boundary, there is a delay before it jumps back to centre.
Running the below code illustrates the controller working and the problems:
import QtQuick 2.0
Item {
id: horizontalController
width: 300
height: 100
Rectangle {
id: controllerBackground
width: (parent.width / 3) * 2
height: parent.height
anchors.centerIn: parent
color: "white"
}
Flickable
{
id: controllerFlick
width: parent.width / 3 * 2
height: parent.height
anchors.centerIn: parent
contentX: width / 4
contentWidth: bounds.width
contentHeight: bounds.height
boundsBehavior: Flickable.StopAtBounds
onMovementEnded: {
contentX = width / 4
}
MultiPointTouchArea{
id: controllerTouchArea
enabled: true
anchors.fill: bounds
touchPoints: TouchPoint {id: controllerTouchPoint }
onPressed: {
controllerFlick.contentX = Math.min(Math.max(controllerBackground.width - controllerTouchPoint.x,0),controllerBackground.width / 2)
}
onReleased: {
controllerFlick.contentX = controllerFlick.width / 4
}
}
Item{
id: bounds
width: controllerFlick.width * 1.5
height: controllerFlick.height
Rectangle {
id: image
width: parent.width / 3
height: parent.height
anchors.centerIn: parent
color: "red"
}
}
}
}

Related

QML FlickArea center content

I am attempting to make a PDF viewer inside of a Flickable in QML. To do this I use the Poppler library to render my PDFPages to images. When I zoom, I re-scale the size of the image, causing the content Height and Width to change.
My question is, when I zoom out to the point where the image width is less than the Flickable width, the image is shoved to the left. Similarly, if I flip the orientation and the height of the image becomes less than the FlickArea height, the image is locked to the top. Is there any good way to center the image in the FlickArea window?
For the purposes of making this example simpler I replaced my PDF image with a Rectangle.
//Flickable qml snippet
Flickable
{
id: flickArea
anchors.fill: parent
anchors.centerIn: parent
focus: true
contentWidth: testRect.width
contentHeight: testRect.height
clip: true
Rectangle
{
id: testRect
color: "red"
width: 2550 * zoom
height: 3300 * zoom
property double zoom: 1.0;
}
}
//zoom button snippet
Item
{
id: zoomContainer
width: 80
height: zoomColumn.childrenRect.height
z: 2
anchors
{
right: parent.right
bottom: parent.bottom
rightMargin: 10
bottomMargin: 10
}
Column
{
id: zoomColumn
width: parent.width
spacing: 5
anchors
{
right: parent.right
}
Button
{
id: zoomInButton
height: 75
width: parent.width
text: '+'
onClicked: {
testRect.zoom += 0.1
console.log(testRect.zoom)
}
}
Button
{
id: zoomOutButton
height: 75
width: parent.width
text: '-'
onClicked: {
testRect.zoom -= 0.1
console.log(testRect.zoom)
}
}
}
}
Try something like this:
Flickable
{
id: flickArea
anchors.fill: parent
// anchors.centerIn: parent // redundant code
focus: true
contentWidth: wrapper.width
contentHeight: wrapper.height
clip: true
Item
{
id: wrapper
width: Math.max(flickArea.width, testRect.width)
height: Math.max(flickArea.height, testRect.height)
Rectangle
{
id: testRect
color: "red"
anchors.centerIn: parent // centered in wrapper
width: 2550 * zoom
height: 3300 * zoom
property double zoom: 1.0;
}
}
}

QML: horizontal flickable visually lingers in StackView

Suppose you have a long horizontal content, so you put it in flickable for your user to swipe through. This might be a picture or a graph or something else. When the content is swiped right so that it's left side is hidden, and you pop the page from stack, a stack animation occurs where all the content is moved right. However, the before hidden part of flickable content then slides to the right also and becomes visible until the animation is over. I want to find a way to prevent this.
Here is the picture of a red rectangle lingering, carefully captured at 25 frames per second:
Here is the minimal example code to illustrate the problem:
import QtQuick 2.9
import QtQuick.Controls 2.2
ApplicationWindow {
id: window
visible: true
width: 640
height: 480
header: ToolBar {
contentHeight: toolButton.implicitHeight
ToolButton {
id: toolButton
text: "<"
onClicked: {
stackView.pop()
}
}
}
StackView {
id: stackView
initialItem: pageZero
anchors.fill: parent
}
Component {
id: pageZero
Column {
Label {
text: "Page zero"
}
Button {
text: "next"
onClicked: { stackView.push(pageOne) }
}
}
}
Component {
id: pageOne
Flickable {
height: 200
width: 200
contentHeight: 200
contentWidth: 300
Rectangle {
height: 200
width: 300
color: "red"
}
}
}
}
The question is, what handlers should i put to hide the flickable before the animation starts?
Alright, i found how, actually this solution wasn't that hard. (= What i need to do is to have my flickable hidden during the transition, and also shown after the transition has ended, so I add the two lines:
Flickable {
height: 200
width: 200
contentHeight: 200
contentWidth: 300
// watch this next line
StackView.onDeactivating: {rect.visible = false}
StackView.onActivating: {rect.visible = true}
Rectangle {
id: rect
height: 200
width: 300
color: "red"
}
}

QML: Problems with setting the size of the button in a layout

I have this app page in qml:
Image {
source: "file:///C:/Users/image.jpg"
fillMode: Image.PreserveAspectCrop
Rectangle {
width: parent.width/3
height: parent.height/3
anchors.centerIn: parent
radius: 5
ColumnLayout {
width: parent.width * 0.5
height: parent.height * 0.5
anchors.centerIn: parent
//some components here ...
Button {
//width: 100 nothing changes in the app
Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
style: ButtonStyle {
background: Rectangle {
color: "blue"
radius: 15
//width: 100 nothing changes in the app
}
label: Text {
text: qsTr("Button")
color: "white"
}
}
}
}
}
}
Now I'm trying to set the size (width and height) of the button, so that depends on the size of the parent (layout), something like width: parent * 0.4. I probably tried every possible position of the width statement in the code, but when I run the app the size of the button never changes. I also tried to set the size to a specific number, not to bind it to the parent, still nothing.
So what could be the problem here? Where and how should be the button size defined so it's binded to its parent layout size?
Have you tried the suggestion from #folibis? I'm guessing this is a similar issue to the question here. In that example, elements inside of a Layout were not responding to the width and height parameters. Setting Layout.preferredWidth and Layout.preferredHeight seemed to solve the issue. Please refer to the documentation provided in that answer.
You can still bind to the parent's properties, for example
Layout.preferredWidth: parent.width * 0.4

QML: Drag items get clipped when dragged outside of a ScrollView

I have a ScrollView which contains several draggable rectangles.
When I drag an item outside of that ScrollView, I want it to remain visible, but it gets clipped at the edge of the ScrollView.
I tried playing around with the z values, but it has absolutely no effect. Any idea on what else I could try?
You need to change the rectangles' parent to the parent of ScrollView when the rectangle been dragged.
And if you want the rectangle always stay out of ScrollView after drag, assign a new state after the mouse release instead of when: dragMe.drag.active.
Item{
id: root
width: 500
height: 500
ScrollView {
width: 200
height: 200
Item{
width: 500
height: 500
Rectangle{
id: rect
color: "red"
width: 50
height: 50
MouseArea{
id: dragMe
drag.target: parent
anchors.fill: parent
}
states: State {
when: dragMe.drag.active
ParentChange { target: rect; parent: root }
}
}
}
}
}

Wrong width and position of non-attached horizontal QML ScrollBar (and ScrollIndicator) when I resize parent element from RTL

The problem is in position and width of the horizontal scrollbar and position of the content that has been scrolled when I resize the width of the window (parent) element in RTL direction.
When I do these steps:
Resize the width of window in LTR direction.
Everything is working fine.
Change scrollbar position to any other position that is different from 0.0, (for example move it all the way to the right side)
Resize the width of window in opposite (RTL) direction
Scrollbar starts to behave odd and scrollable content is in the wrong position
I get this situation:
Width of scrollbar's contentItem (aka scrollbar's handle) is wrongly calculated.
Scrollbar's position is also wrongly calculated
The content is not scrolled to the right place (property "x" of scrollable content is wrongly calculated )
What I want is that:
the width of scrollbar's contentItem (aka scrollbar's handle) increases proportionately as the width of the window increases
the content (which was in the position that its right side was completely visible) should stay in that position. And with the expansion of the window, on the left side, the other part of the content that was not visible until then, should start to show up.
The same things are happening if I try to use non-attached QML ScrollIndicator.
This seams to be the bug in QML, and I have reported it, but I need the solution now... If anyone could help, it would be great. Thanks!
import QtQuick 2.7
import QtQuick.Window 2.2
import QtQuick.Controls 2.3
Window
{
id: main
width: 400
height: 200
Rectangle
{
id: frame
clip: true
anchors.fill: parent
color: "purple"
Text
{
id: content
text: "ABCDE"
font.pixelSize: 160
x: -hbar.position * width
}
ScrollBar
{
id: hbar
hoverEnabled: true
active: true
policy: ScrollBar.AlwaysOn
visible: size < 1
orientation: Qt.Horizontal
size: frame.width / content.width
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
background: Rectangle
{
color: "black"
}
}
}
}
scrollbar behavior
You should consider using a Flickable instead of setting the position of your text manually:
Flickable {
anchors.fill: parent
contentWidth: content.paintedWidth
boundsBehavior: Flickable.StopAtBounds
ScrollBar.horizontal: ScrollBar {
hoverEnabled: true
active: true
policy: ScrollBar.AlwaysOn
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
background: Rectangle {
color: "black"
}
}
Rectangle {
id: frame
clip: true
anchors.fill: parent
color: "purple"
Text {
id: content
text: "ABCDE"
font.pixelSize: 160
}
}
}
Edit:
If you really need the ScrollBar to be attached to a Rectangle, you can add bounds to your Text position:
x: Math.min(0, Math.max(-hbar.position * width, frame.width - content.width))
with
ScrollBar {
visible: frame.width < content.width
// ...
}

Resources