Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Remember scroll position in QML element

I have some qml that acts as the output from the application (kind of like a read-only console). However, it's annoying to use because as it prints information it scrolls back to the top.

For example, lets say I print a line to my TextArea every second, after a minute or so, I'll have enough lines that I now have a scroll bar. I scroll to the bottom, a second later, a line of text is printed causing it to scroll back to the top.

The desired functionality I would like is to automatically scroll to the bottom (much like how a console is when it prints stuff out) unless the user overrides this by scrolling up, then the text should stay put. I hope that made sense, here is some code:

        ScrollArea {
            id: helpTextScrollArea
            anchors.left: parent.left
            anchors.right: parent.right
            anchors.top: myButton.bottom
            anchors.topMargin: 5
            anchors.bottom: parent.bottom
            visible: false
            horizontalScrollBar.visible: false

            onVisibleChanged: {
                helpText.visible = visible
            }

            HelpTextArea {
                id: helpText
                width: parent.parent.width - helpTextScrollArea.verticalScrollBar.width
                text: "Oops, no documentation."

                onVisibleChanged: {
                    if(helpTextScrollArea.visible != visible) {
                        helpTextScrollArea.visible = visible
                    }
                }
            }
        }

        Flickable
        {
            id: flick

            anchors.left: parent.left
            anchors.right: parent.right
            anchors.top: runStopButton.bottom
            anchors.bottom: parent.bottom
            anchors.topMargin: 5


            TextArea{

                id: messageArea
                anchors.fill: parent

                focus: true

                readOnly: true

                visible: !helpTextScrollArea.visible

                wrapMode: TextEdit.Wrap

                function addText(newText) {
                    text += newText + "\n"
                }
            }
        }

Note: I don't think my Flickable does anything, it was part of my experimenting to fix the problem. Also, I use the function addText to print to the text area. I hardly know anything about qml and most of this code was written by someone else and I'm trying to work with it. Thank you!

like image 496
user869525 Avatar asked Jun 06 '12 12:06

user869525


2 Answers

You can bind contentY property of Flickable to an expression that will calculate proper position.

Flickable {
    id: flick
    states: State {
        name: "autoscroll"
        PropertyChanges {
            target: flick
            contentY: messageArea.height - height
        }
    }
    onMovementEnded: {
        if (contentY === messageArea.height - height) {
            state = "autoscroll"
        }
        else {
            state = ""  // default state
        }
    }
    // ...
}
like image 98
sergk Avatar answered Oct 25 '22 20:10

sergk


Flickable has got 4 readonly properties in called visibleArea.* (you can read their meaning in the QML documentation) :

  • visibleArea.xPosition : xPosition = contentX / contentWidth
  • visibleArea.yPosition : yPosition = contentY / contentHeight
  • visibleArea.widthRatio : widthRatio = width / contentWidth
  • visibleArea.heightRatio : heightRatio = height / contentHeight
like image 37
air-dex Avatar answered Oct 25 '22 21:10

air-dex