I’m happy to announce that in Qt 5.12, a new TableView item will be available in the QtQuick module. TableView is similar to the existing ListView, but with additional support for showing multiple columns.

Like with ListView, you can assign data models of any kind to TableView, like ListModels or plain Javascript arrays. But to create models with more than one column, you currently need to subclass QAbstractItemModel in C++. A QML TableModel is also in the works, but will come later.

TableView inherits Flickable. This means that while a table can have any number of rows and columns, only a subsection of them will usually be visible inside the viewport. As soon as you flick, new rows and columns enter the viewport, while old ones move out. A difference to ListView is that TableView will reuse the delegate items that are flicked out to build the rows and columns that are flicked in. This will of course greatly improve performance, especially when using a delegate that has lots of child items.

The fact that TableView reuses delegate items is not meant to be transparent to the developer. When a delegate item is reused, context properties like index, row, column, and model roles, will be updated. But other properties will not. Storing a state inside a delegate item is a bad idea in the first place, but if you do, you have to reset that state manually. If, for example, a child rectangle changes color after construction, you need to set it back when the delegate item is reused. Two attached signals are available for this purpose: TableView.onPooled and TableView.onReused. The former will notify the delegate item when it is no longer a part of the table and has been moved to the reuse pool. This can be a good time to pause ongoing animations or timers for example. The latter signal will be emitted when the delegate item has been moved back into the view. At this point you can restore the color. It might be tempting to use Component.onCompleted for such things as well, but that signal is only emitted when the delegate item is created, and not when it’s reused.

The following snippet shows how to use the attached signals to temporarily pause an animation while a delegate item is pooled:

TableView {
    anchors.fill: parent
    clip: true

columnSpacing: 1 rowSpacing: 1 model: myQAbstractTableModel

delegate: Rectangle { implicitWidth: 100 implicitHeight: 50

TableView.onPooled: rotationAnimation.pause() TableView.onReused: rotationAnimation.resume()

Rectangle { id: rect anchors.centerIn: parent width: 40 height: 5 color: "green"

RotationAnimation { id: rotationAnimation target: rect duration: (Math.random() * 2000) + 200 from: 0 to: 359 running: true loops: Animation.Infinite } } } }

For simple cases, TableView will determine the width of a column by reading the implicitWidth of the delegate items inside it. For this strategy to be consistent, all delegate items in the same column should have the same implicitWidth. For more advanced cases, you can instead assign a callback function to TableView that returns the width of any given column. That way the application is in full control of the widths, whether they are calculated or stored, rather than TableView trying to solve this efficiently for models with potentially thousands of rows and columns.

TableView {
    anchors.fill: parent
    clip: true
    model: myQAbstractTableModel
    delegate: Rectangle {}

columnWidthProvider: function (column) { return column % 2 ? 100 : 200 } rowHeightProvider: function (row) { return row % 2 ? 100 : 200 } }

Other than this, the API for the first release of TableView is kept pretty small and strict. More will be implemented later, such as using custom transitions when adding or removing rows and columns. We're also working on a TableHeader, TableModel, as well as a DelegateChooser. The latter lets you assign several delegates to a TableView, and e.g use a different one for each column. The latter will already be available in Qt 5.12 as a labs import (Qt.labs.qmlmodels 1.0).

Blog Topics: