Richard Moe Gustavsen

TableView

Published Wednesday August 29th, 2018
35 Comments on TableView
Posted in Dev Loop, Itemviews, Qt Quick 2, Qt Quick Controls

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).

Do you like this? Share it
Share on LinkedInGoogle+Share on FacebookTweet about this on Twitter

Posted in Dev Loop, Itemviews, Qt Quick 2, Qt Quick Controls

35 comments

Jakub Narolewski says:

Awesome : D

Jon says:

Any chances to get pagination support like this one datatables https://datatables.net/examples/styling/bootstrap ? But only fetch the data as needed rather than retrieve all dataset source and save them in memory ( which would be memory overhead)

Richard Moe Gustavsen Richard Moe Gustavsen says:

TableView will show whatever the model contains. But it will only ask the model for the rows that are visible inside the viewport. So either you could just lazy load data from the model according to what TableView asks, or implement a (proxy)model that only feeds the TableView with a fixed number of rows at a time (if you want like a pagination control kind of interface).

Luis says:

Are there plans to bring the optimizations mentioned here to to tree views and list views?

Richard Moe Gustavsen Richard Moe Gustavsen says:

Not in the near future. But lets see how the solution in TableView works out, and iron out any issues there first. Reusing items the way TableView does it means that the delegate needs to be written with reuse in mind. Since this have never been the case for ListView, the potential for regressions is high. Reusing items in ListView would at least need to be off by default.

rdh says:

I’ve implemented this stuff but for the QTableview from QWidget and using QSqlDatabase , btw you can chime in my dummy implementation here https://github.com/rdhafidh/NomorHp/blob/master/tableview/formtableview.cpp

BartekBl says:

I don’t think that pagination is a good idea.

First of all I hat it when application shows a small number of rows and takes up a little space on my screen. Unused screen estate is a wasted screen estate. A scrollable item has an inherent support for resizing and filling users screen while pagination would have to be made in a way as to show appropriate number of items per page.

Second: when items are sorted it is more natural for me to scroll through than click through pages.

Louis says:

Great news! Where can we find the documentation to perform some tests?

Richard Moe Gustavsen Richard Moe Gustavsen says:

The documentation is currently being written (https://codereview.qt-project.org/#/c/237301/2)

Alexander says:

Is it me or is QML just gaining features that have been in Qt since like 1.0?
I’m amazed how QML is marketed as the future of Qt and GUI while lacking basic stuff like this.
Qt Widgets is supposedly “finished” or even abandoned, but how am I expected to write a modern complex desktop application (say, Photoshop or Visual Studio) with this? Or even anything that is not your basic weather/media-player app?

Jakub says:

Yeah, it’s not only you. I mean I love Qt and QML but it lacks basic features for the ages now. IMO QtQuick.Controls 1.0 should already have TableView, TreeView and all other ‘Widgets’. Also if you develop Android/iOS/Embedded application and you want it to be fully customized then you’re screwed, because you need to develop your own: DatePicker, FileDialog, MessageBox and others. Basically every QML developer needs to create his own package with custom controls to work efficiently.

Richard, good job with a TableView! It’s better ever than never. I hope that we will get all of the essential components some time.

JKSH says:

> IMO QtQuick.Controls 1.0 should already have TableView, TreeView

It does:

* http://doc.qt.io/qt-5/qml-qtquick-controls-tableview.html (since Qt 5.1)
* https://doc.qt.io/qt-5/qml-qtquick-controls-treeview.html (since Qt 5.5)

This new TableView that Richard announced will replace the old one, as a vastly improved version.

RajaRaviVarma says:

I too wonder, why the Qt ecosystem is does not have open-source projects like the front-end JavaScript ecosystem. For example, there are very well maintained and widely used component libraries written on top of ReactJS and VueJS. But QML developers have to develop them individually.

Is this because of the lack of standardized package management system like npm? I stumbled upon something called `qbs`, but then it is not standard, but slightly widely used.

Danny says:

QtQuick isn’t intended for developers familiar with traditional Qt widgets.

It’s intended for vehicle dashboards, televisions, heads up displays and other embedded applications where the ‘front end’ is just a thin layer over existing business logic written in some other mature language.

These GUI’s don’t use traditional widgets; they use dials, meters and menus which are always created from scratch for that particular application.

That’s why QtQuick doesn’t have dialogs, messageboxes, filepickers and other ‘legacy desktop’ components.

Vladyslav Stelmakhovskyi says:

It does. I cant understand why some just cant google
TableView/TreeView was really missing part of QQC2 but its already exists in QQC1

Will says:

QtWidgets being “finished” doesn’t mean it stopped working. It’s just a pretty mature part of Qt that doesn’t need as much attention as the less mature, more unfinished parts. If you want to write a widgetty app for Desktop environments, why would you specifically insist that you want to use an unfinished API?

Vladimir Kraus says:

QtWidgets are still perfect for desktop app usage. They are mature, unlike QtQuick and QML and their performance is excellent. There are some bugs though which should be addressed. However these are very subtle and majority of users will not ever notice these.

MN says:

The lack of clear upgrade path will hurt Qt in the long run. Right now the situation is similar to what MS did with WindowsForms, then WPF, then Store Apps, then UWP – “pretty”, “new”, “easy” but weak APIs which can’t cover professional needs and/or come at a performance cost, as a result Win32 is pushing 30, live and well. Compare that to Cocoa vs Carbon – the path was clear and sustainable and the platform is one of the best.

Thomas Gulbrandsen says:

Hi!
This is great news, have been waiting for this.

Is there a plan for a new TreeView in the QtQuick module too, or is this put on hold?

Richard Moe Gustavsen Richard Moe Gustavsen says:

TreeView is definitely on our list of things that we want to do. But I cannot give out any dates or promises here.

Philip S says:

Finally! Thank you for implementing this.

KaoN says:

Is/Will it possible to create a pivot table similar like this simpley?
https://jsfiddle.net/nicolaskruchten/kn381h7s/

Richard Moe Gustavsen Richard Moe Gustavsen says:

TableView will only display the table. Support for table headers will come later as a separate HeaderView. For now you need to implement the headers yourself, but for more complex things, like in your example, it will take more work. But possible.

Salvatore says:

What about TreeView?

jon says:

what about column elided text ? something like “very long string long string long string” becomes “very long str…” ..

Richard Moe Gustavsen Richard Moe Gustavsen says:

You normally specify the width of a column by setting implicitWidth on the delegate. For items that has that property specified as readonly (Text item), you either need to wrap it inside another item, or set a custom columnWidthProvider. Eliding the text itself is just a matter of setting the elide property on the Text item.

slickqt says:

cause qml lack tableview and treeview, we have switch to web for it(datatables and fancytree)

Vladyslav Stelmakhovskyi says:

use web instead of QQC1 or custom ListView? smart move. go on

Firat says:

That looks awesome. I have a couple of questions.

1- Is there any quick way to mark the whole row or column?
2- Is there any way to implement http equivalent of rowSpan or colSpan?
3- Is there any way to implement row width like in pattern Luquid – Fixed – Fixed? I was thinking that may be TableView itself could like 750px. When we give a fixed width for last 2 columns, lets say 100px and 150px, TableView could set first column 500px automatically. Is that possible?

Jakub Narolewski says:

About 3.

Seeing as this new TableView can also be fed with QAbstractItemModel I believe you will be able to implement selection functionality with QItemSelectionModel.
Typically, when I roll my own TableViews based on ListViews, I have something similar to:

cpp side:
Class MyCustomListViewImpl
-> member QAbstractItemModel
-> member QItemSelectionModel

QML side:
Component MyCustomListView based on MyCustomListViewImpl

Where MyCustomListViewImpl provides a thin interface between QML component and the functions related to model and selection model [selection of indexes, deselection of indexes, etc].

Jakub Narolewski says:

Of course I meant ‘About 1’ 😛

Richard Moe Gustavsen Richard Moe Gustavsen says:

1. TableView itself does not (yet) contain any selection support. For now, you would need to store which rows/columns/items that are selected in a your own data structure (or e.g add a model role “selected” to you data model). Then bind that information/role to a selected state (e.g bgcolor) inside the delegate to show it as selected.
2. rowSpan and colSpan are not available in this first release.
3. Even if TableView itself has a fixed width of e.g 750px, the content view inside it that you flick around, can be of any size. And it’s always resized to fit the size of the table. So (normally) there will be no extra left-over space at the end that the last column could fill. But it might still make sense for tables that are smaller than the TableView size itself, or if you set a custom contentWidth. I’ll make a note.

Andrew says:

ZOMGZOMGZOMG SO EXCITED!!!!

Commenting closed.

Get started today with Qt Download now