How to notify QtQuick2 TableView that its contentHeight has changed to update its scroll bars?

Viewed 271

I have a TableView where each cell is represented by a Label delegate. This Label component has wrapMode set to Text.Wrap meaning that its height can change when the TableView is resized.

However, the TableView doesn't seem to be aware that its contentHeight has changed because of the wrapping, hence the scroll bars do not update. This is shown below:

scroll bar not updating after content height has changed

How to notify TableView that its contentHeight has changed so that the scroll bars update accordingly as the view is being resized?

QML code to create table shown above:

import QtQuick 2.12
import QtQuick.Controls 2.13
import QtQuick.Window 2.12
import Qt.labs.qmlmodels 1.0

Window {
    width: 640
    height: 220
    visible: true
    title: qsTr("Hello World")

    TableView {
        id: view
        anchors.fill: parent
        columnWidthProvider: () => width/2
        onWidthChanged: forceLayout()
        onHeightChanged: forceLayout()

        model: TableModel {
            TableModelColumn {display: "key"}
            TableModelColumn {display: "value"}
            rows: [
                {key: "first name", value: "Freida"},
                {key: "last name", value: "Vandervort"},
                {key: "date of birth", value: "03/05/1989"},
                {key: "street address", value: "977 Kuvalis Mountain"},
                {key: "city", value: "Lynchville"},
                {key: "country", value: "Dominican Republic"},
            ]
        }

        delegate: Label {
            padding: 10
            text: model.display
            wrapMode: Text.Wrap
            background: Rectangle {border.color: "black"}
        }

        ScrollBar.vertical: ScrollBar {policy: ScrollBar.AlwaysOn}
    }
}
1 Answers

Solution is to store the heights of the delegates in an array and use this to calculate the contentHeight. This array needs to be updated whenever the delegate changes its size.

TableView {
    //store delegate heights
    property var delegateHeights: Array(model.rowCount).fill(0)

    //use stored delegate heights to calculate content height
    contentHeight: delegateHeights.reduce((total, height) => total + height, 0)

    delegate: Label {
        //update stored delegate heights when delegate size changes
        onHeightChanged: view.delegateHeights = view.delegateHeights.map((el, index) => index === row ? height : el)

        ...
    }

    ...
}
Related