Search code examples
qtqmlscrollbarqtquickcontrols2

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:

  1. Resize the width of window in LTR direction.
  2. Everything is working fine.
  3. Change scrollbar position to any other position that is different from 0.0, (for example move it all the way to the right side)
  4. Resize the width of window in opposite (RTL) direction
  5. 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


Solution

  • 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
        // ...
    }