Reputation: 586
I'm making a terminal widget. I want the Flickable
to scroll down to the latest input when TextArea.text
is updated. My code looks like as follows.
ColumnLayout {
anchors.fill: parent
Flickable {
id: scroller
clip: true
contentY: contentHeight - height
onContentYChanged: {
console.log("contentY:", contentY)
}
TextArea.flickable: TextArea {
id: textArea
Layout.fillWidth: true
}
Layout.fillWidth: true
Layout.fillHeight: true
}
RowLayout {
id: prompt
Label {
text: " > $ "
}
TextField {
id: textInput
Layout.fillWidth: true
}
}
}
When I run this, I see that contentY
is being overwritten right after it's set by my binding:
qml: contentY: 1498
qml: contentY: 0
qml: contentY: 1517
qml: contentY: 0
I checked to make sure my binding is not setting it to 0. I tried to debug the binding loop using export QT_LOGGING_RULES="qt.qml.binding.removal.info=true"
, that came out clean. I had a look at the source for Flickable
and I don't think any of the methods there are the culprit.
Is binding contentY
the right way to do what I want? Why is my binding is not being respected?
Upvotes: 1
Views: 1730
Reputation: 17246
The issue is that contentY
is going to be overwritten constantly by the Flickable as the content inside of it moves around. You can't place a binding on it because as you can see, it will be immediately overwritten with a static value that updates as the user interacts with the flickable.
What you need to do instead is something like
onContentHeightChanged: Qt.callLater(() => contentY = contentHeight - height)
Now, whenever the text area grows, it will jump the contentY via an immediate assignment instead of trying to rely on a binding. The callLater ensures that it happens after the flickable resets contentY to 0 on its own due to the height change.
Upvotes: 3