Item Views in Qt Quick

Introduction

A substantial amount of work has gone into improving TableView and TreeView in Qt 6.3 and 6.4, and more is also in the works. In this post I’ll give a quick overview over what has been done so far.

TreeView

TreeView was finally added to Qt Quick in Qt 6.3, after a short stay in Marketplace which caused some negative buzz. Understandably, most see it as an essential item view that naturally belongs together with the others, such as ListView, TableView and GridView. If nothing else, that delay gave us some time to revise the API, before the final version landed in Qt Quick.

And the API changed quite a bit. While TreeView in Marketplace is an independent component with its own styling API, the version in Qt Quick is integrated with the styling API in Qt Quick Controls. It’s therefore split in two: the TreeView itself, which lives in Qt Quick together with the other item views, and a TreeViewDelegate, which lives in Qt Quick Controls. TreeView contains the API and the logic, but the drawing is outsourced to the TreeViewDelegate (or your own custom delegate, if you wish), and follows the application style.

TreeView inherits TableView. This means that anything you can do with a TableView, you can do with a TreeView (including e.g selection support and cell navigation - more on that below).
TreeView basically flattens the tree model into a table model internally, and offers an API that lets you map between table cells and tree model indices, or expand and collapse nodes. In Qt 6.4, support for expanding and collapsing nodes recursively has also been added.

Selection support

One of the long-missing features in TableView, that got implemented in Qt 6.3, was support for selecting cells. This means that you can now assign an ItemSelectionModel to TableView, which contains an API for creating and manipulating selections programmatically. Quick Controls has a styled SelectionRectangle, which lets you do standard mouse-drag selection, or alternatively, press-and-hold with selection handles on touch-based platforms. As of Qt 6.4, you can also set the selectionBehavior, to control whether the user should select individual cells, rows or columns.

New in Qt 6.4 is also the possibility to move the currentIndex around, and select cells with the keyboard. A couple of new properties have been added, keyNavigationEnabled and pointerNavigationEnabled, in case your application needs to disable or override the default navigation behavior from QML.

The rendering of a selection, as well as showing a cell as current, is left to the delegate. To know if a delegate is selected or current, you can simply add the properties selected and current to it, which TableView will then keep in sync with the ItemSelectionModel. Putting it all together, a QML snippet that lets you select cells could end up like this:

TableView {
    id: tableView
    selectionBehavior: TableView.SelectRows
    delegate: Rectangle {
        required property bool selected
        required property bool current
        color: selected || current ? “lightblue” : “white”
        Text { text: row + “, “ + column }
    }
}

SelectionRectangle { target: tableView }

Several other selection-related properties have also been added in Qt 6.4, like currentRow, currentColumn, and alternatingRows.

Positioning

TableView has a function positionViewAtCell(point cell, PositionMode mode, point offset, rect subRect). It flicks the content item so that a specific cell becomes visible, based on the bounding rectangle of the whole cell. New in Qt 6.4 is that you can now also specify a fourth argument: subRect. This rect can be used to describe an area inside the cell that should be used, rather than its bounding rectangle. This is useful if you operate with really large cells, where a cell might be larger than the view itself, and you want to make sure that a specific part of the cell is shown inside the view. In PdfMultiPageView, for example, a page in the document gets rendered into a single cell in a TableView. And when you jump to a specific heading in the document, a subRect is used to make sure that the heading, rather than the whole page, ends up being aligned to the top of the view.

tableview

In addition to the fourth argument, two new enum values have been added to PositionMode: Visible and Contain. Those can be used to flick the content item so that the cell ends up fully inside the view, if the cell is not considered to be inside already. The difference is when they consider a cell to be inside. With Visible, it’s enough that just a pixel of the cell is visible in the viewport. With Contain, the whole bounding rectangle must overlap. And only if the cell is not considered to be inside, will the content item be flicked.

If you also specify a subRect, that rectangle will be used instead of the bounding rectangle, both to decide whether the cell is inside, and to flick so that only the sub rectangle will end up fully visible, and not necessarily the whole cell.

Further work

There is still quite some work left with item views in QML, to reach feature parity with widgets and completeness for desktop-centric UIs. The next task that we hope to have ready for Qt 6.5 is to implement support for resizing and reordering rows and columns by dragging on the cells in a HeaderView. We also hope to implement improved support for editing table cells, by offering an edit delegate property in TableView. And lastly, we aim to fix some minor issues in DelegateChooser, and move it out of Qt.labs into QtQuick.


Blog Topics:

Comments