Search code examples
qtqmlscrollview

Why is ScrollView not scrolling?


I need to create a long form using QML. The form will not fit inside the window, so I need for it to be scrollable. However, I can't get the scroll view to work. Here is a minimum working example of my problem:

import QtQuick.Window 2.2
import QtQuick 2.9
import QtQuick.Controls 2.3

Window {
    visible: true
    width: 1280
    height: 720
    title: qsTr("Hello World")

    Rectangle{
        anchors.centerIn: parent
        width: parent.width*0.8;
        height: parent.height*0.7;

        ScrollView {
            anchors.fill: parent
            clip: true
            contentHeight: parent.height

            Rectangle{
                id: rect1
                width: parent.width
                height: 200
                color: "#ffff00"
                anchors.horizontalCenter: parent.horizontalCenter
            }

            Rectangle{
                id: rect2
                width: parent.width
                height: 500
                color: "#ff00ff"
                anchors.top: rect1.bottom
                anchors.horizontalCenter: parent.horizontalCenter
            }

            Rectangle{
                id: rect3
                width: parent.width
                height: 500
                color: "#00ffff"
                anchors.top: rect2.bottom
                anchors.horizontalCenter: parent.horizontalCenter
            }
        }
    }
}

As I understand it, this should allow me to scroll in order to see the 3 rectangles. However, I only see the first one and the upper half of the second one, and I can't scroll.


Solution

  • Because your ScrollView contains multiple items you need to take care of sizing yourself and set contentHeight explicitly to the combined height of all the items.

    For testing, you can set vertical scrollbar always on to see how content height affects the scrollbar.

    I commented out horizontal center anchoring because it is not needed (width of your rectangles is scrollview width).

    ScrollView {
        anchors.fill: parent
        clip: true
        ScrollBar.vertical.policy: ScrollBar.AlwaysOn
        contentHeight: rect1.height+rect2.height+rect3.height
    
        Rectangle{
            id: rect1
            width: parent.width
            height: 200
            color: "#ffff00"
            //anchors.horizontalCenter: parent.horizontalCenter
        }
    
        Rectangle{
            id: rect2
            width: parent.width
            height: 500
            color: "#ff00ff"
            anchors.top: rect1.bottom
            //anchors.horizontalCenter: parent.horizontalCenter
        }
    
    
        Rectangle{
            id: rect3
            width: parent.width
            height: 500
            color: "#00ffff"
            anchors.top: rect2.bottom
            //anchors.horizontalCenter: parent.horizontalCenter
        }
    
    }
    

    If you wrap your rectangles with an item and set item implicitHeight to its height ScrollView detects the contentHeight correctly.

    ScrollView {
        anchors.fill: parent
        clip: true
        ScrollBar.vertical.policy: ScrollBar.AlwaysOn
        Item {
            width: parent.width
            height: rect1.height+rect2.height+rect3.height
            implicitHeight: height
            Rectangle{
                id: rect1
                width: parent.width
                height: 200
                color: "#ffff00"
            }
            Rectangle{
                id: rect2
                width: parent.width
                height: 500
                color: "#ff00ff"
                anchors.top: rect1.bottom
            }
            Rectangle{
                id: rect3
                width: parent.width
                height: 500
                color: "#00ffff"
                anchors.top: rect2.bottom
            }
        }
    }
    

    The default implicit size for most items is 0x0, that's why you have to set implicit height for the item explicitly. However some items have an inherent implicit size, e.g. Image and Text. This means that if you place e.g. TextArea into your ScrollView it will automatically become scrollable if text is long enough.

    ScrollView {
        anchors.fill: parent
        clip: true
        TextArea {
            readOnly: true
            text: online ? provider.loadedText : "Offline"
            wrapMode: Text.WordWrap
        }
    }