Search code examples
qtqmlqt-quickqtquickcontrols

QML TextArea scroll events


Is there a way to know when TextArea scroll has reached the top or bottom? I want to implement dynamic text loading in a chat client: when the user scrolls to the top, more text is added to the document. Something like this (pseudo-code):

import QtQuick 2.4
import QtQuick.Controls 1.2

TextArea {
      id: chat
      onScrolledToTop: text = loadMoreText() + text
}

Solution

  • Textarea inherits from ScrollView which has a Flickable item to control the visible area. Such an item is available as the (readonly) property flickableItem. Among the other properties Flickable provides the contentY:

    These properties hold the surface coordinate currently at the top-left corner of the Flickable. For example, if you flick an image up 100 pixels, contentY will be 100.

    Hence you can check this property change and, once a certain threshold is reached, update your text. Mind that you should adjust the contentY after setting the text, to simulate the addition. Otherwise the text shown will be exactly the one just added. A nice approach, as proposed by the OP, would be to save the original contentHeight and set the contentY to the difference between the updated contentHeight and the saved one - also considering the applied threshold.

    import QtQuick 2.4
    import QtQuick.Window 2.2
    import QtQuick.Controls 1.3
    
    Window {
        visible: true
        width: 400
        height: 200
    
        TextArea {
            id: chat
            anchors.fill: parent
            property int threshold: 10
    
            text: "Current\ntext\n\\to\nmove\ndown\ndown\ndown
                   \ndown\ndown\ndown\ndown\ndown\ndown\ndown"
            Component.onCompleted: cursorPosition = text.length
    
    
            flickableItem.onContentYChanged: {
                if(flickableItem.contentY <= threshold) {
                    var oldHeight = flickableItem.contentHeight
                    text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit,
                                sed do eiusmod tempor incididunt ut labore et dolore magna
                                aliqua." + text
                    flickableItem.contentY = threshold + flickableItem.contentHeight - oldHeight  // leave flickable in old position
                }
            }
        }
    }