Jacob Krieg
Jacob Krieg

Reputation: 3174

How to programatically scroll a ScrollView to the bottom?

I've been trying to create a function that programmatically scrolls to bottom a ScrollView using Qt Quick Controls 2. I've tried various options, but much of the support I found online refers to Qt Quick Controls 1, not 2. This is what I've tried:

import QtQuick 2.8
import QtQuick.Controls 2.4

ScrollView {
    id: chatView

    anchors.top: parent.top
    anchors.left: parent.left
    anchors.right: parent.right
    anchors.bottom: inputTextAreaContainer.top

    function scrollToBottom() {
        // Try #1
//      chatView.contentItem.contentY = chatBox.height - chatView.contentItem.height
//      console.log(chatView.contentItem.contentY)

        // Try #2
//      flickableItem.contentY = flickableItem.contentHeight / 2 - height / 2
//      flickableItem.contentX = flickableItem.contentWidth / 2 - width / 2

        // Try #3
        chatView.ScrollBar.position = 0.0 // Tried also with 1.0
    }

    TextArea {
        id: chatBox
        anchors.fill: parent
        textFormat: TextArea.RichText
        onTextChanged: {
            // Here I need to scroll
            chatView.scrollToBottom()
        }
    }
}

Does anyone know how this can be achieved using Qt Quick Controls 2? If no, does anyone have any alternatives to this approach?

Upvotes: 3

Views: 1865

Answers (1)

scopchanov
scopchanov

Reputation: 8399

Cause

You are trying to set the ScrollBar's position to 1.0:

chatView.ScrollBar.position = 0.0 // Tried also with 1.0

however, you do not consider its size.

Solution

Take into account the size of the ScrollBar when you set its position like this:

chatView.ScrollBar.vertical.position = 1.0 - chatView.ScrollBar.vertical.size

How I came up with this solution?

I was curious of how Qt itself solves this problem, so I took a look at how QQuickScrollBar::increase() is implemented and I saw this line:

setPosition(qMin<qreal>(1.0 - d->size, d->position + step));

Then I took the first argument of qMin, i.e. 1.0 - d->size, and the solution was clear.

Example

Since you did not provide a MCE, I wrote one myself. I hope you can adapt it for your particullar case. Here it is:

import QtQuick 2.8
import QtQuick.Controls 2.4
import QtQuick.Layouts 1.12

ApplicationWindow {
    width: 480
    height: 640
    visible: true
    title: qsTr("Scroll To Bottom")

    ColumnLayout {
        anchors.fill: parent

        ScrollView {
            id: scrollView

            Layout.fillWidth: true
            Layout.fillHeight: true

            function scrollToBottom() {
                ScrollBar.vertical.position = 1.0 - ScrollBar.vertical.size
            }

            contentWidth: children.implicitWidth
            contentHeight: children.implicitHeight
            ScrollBar.vertical.policy: ScrollBar.AlwaysOn
            clip: true

            ColumnLayout {

                Layout.fillWidth: true
                Layout.fillHeight: true

                Repeater {
                    model: 50

                    Label {
                        text: "Message: " + index
                    }
                }
            }
        }

        TextField {
            Layout.fillWidth: true
        }
    }

    Component.onCompleted: {
        scrollView.scrollToBottom()
    }
}

Result

The example produces the following result:

Window with a list, scrolled to the bottom

Upvotes: 7

Related Questions