ImaginativeThinking.ca


A developers blog

How to use Qt Quick’s TreeView

By: Brad

On July 1st Qt release version 5.5 which included a number of improvements and new additions to the framework. One of the new arrivals in this version is the much sought after TreeView QML type. In this tutorial I’m going to show you how to use the new TreeView to present data which is organized in a tree.

TreeModelPig

You may be asking wait Qt’s had a tree view for a while now, that is you’d be saying that if you’ve never played with Qt Quick. In Qt Widgets you have QListView, QTableView, and QTreeView however in Qt Quick you only have ListView and TableView (where the TableView is really under the hood multiple ListViews (one for each column) wrapped in a nice API to make it look like a table) but no TreeView… until today.

Explanation of Qt Quick Views

First let me quickly explain the existing two views which are among the most commonly used views in Qt Quick.

ListView

The ListView is used to present data stored in a model in the form of a list and can use either the ListModel QML type, which stores data in the form of a list as its name implies, or a derivative of the QAbstractItemModel.

So if you create a model which stores its data like so:
ListModelSchematic

Then define a ListView as follows you’ll get the following on screen when you run your application:

ListView {
       anchors.fill: parent
       model: myModel
       delegate: Rectangle {
           color: ( index % 2 == 0 ) ? "white" : "lightblue"
           anchors {left: parent.left; right: parent.right; }
           height: 20

           Text {
               anchors.verticalCenter: parent.verticalCenter
               anchors.left: parent.left
               text: display // display is the name of the role which holds the data we want to show here.
           }
       }
   }

TreeView_Tutorial_ListView

Note here that each entry shown in the view is of a data entry and since each data entry can have N number of roles the view has access to each one since its working on the entry as a whole. The roles are accessable through their role names which are strings that map to an actual role enum within the model (see QAbstractItemModel::roleNames() for more info).

TableView

The TableView is used to present data stored in a model in the form of a table, well sort of; in reality its better to think of the TableView QML type as a view used to present a list of Rows where each row can contain N number of data points you wish to show. This is a little different then the QTableView which is used in Qt Widgets which actually presents the data stored in a model in the form of a table.

My meaning here is that when using Qt Widgets and the QTableView the model you provide it stores its data in a row/column table so that each cell shows the same role but for a different entry within the model based on a row/column index.

TableModelSchematic

Putting this model into a QTableView would mean that each cell in the table will show the Display Role but for a different row/column entry.

TreeView_Tutorial_TableView

In order to achieve the same thing in Qt Quick instead of storing all your information under the same role instead think of your model as a list of Rows and place the data you want to show in each column all within the same row entry but under different roles.

TableModelSchematic_QtQuick

Here is the code for the TableView:

TableView {
       anchors.fill: parent
       model: myModel
       itemDelegate: Rectangle {
           color: ( styleData.row % 2 == 0 ) ? "white" : "lightblue"
           anchors {left: parent.left; right: parent.right; }
           height: 20

           Text {
               anchors.verticalCenter: parent.verticalCenter
               anchors.left: parent.left
               text: styleData.value // this points to the role we defined in the TableViewColumn below; which one depends on which column this delegate is instantiated for.
           }
       }

       TableViewColumn {
           width: 100
           title: "Name"
           role: "display"
       }
       TableViewColumn {
           width: 100
           title: "Description"
           role: "description"
       }
   }

*Note the TableView has a default itemDelegate so we didn’t have to provide one but since the ListView does not have a default delegate I’m providing one to keep the views looking similar

So the QTableView (QWidgets) will show a different data entry for each cell where as the TableView (Qt Quick) will show a different role data for the given row entry in each cell.

Note here that unlike the ListView each cell delegate is NOT acting on a data entry but rather acting on a role. Because of this each cell delegate does NOT have access to any of the roles for the given data entry and only has access to the single role; this can be a source of pain requiring work a rounds in some cases so keep it in mind. The role data is accessed via the styleData attached property (see TableView::delegate property for more info).

Commercial break...


The New TreeView

Now for the new TreeView; So where as the above two views really worked on a list of data the TreeView actually works on a collection of data organized in a, wait for it, tree structure!

TreeModelSchematic

Now because the data needs to be organized in a tree structure we can no longer use the ListModel QML type to feed the TreeView but instead are limited to a derivative of the QAbstractItemModel. As you can see above we have a list of branches off the root where each branch in turn can have one or more leafs (in the above we only show one leaf). What roles we populate on each branch and leaf is completely up to us; in the diagram we show that we only set the Display role but we could have set the Display role on the branches and a custom Description role on the leafs if we so wanted to.

The TreeView itself is written out much the same way as the TableView; that is we define each column with the TableViewColumn QML type like we did in the TableView above. Yup TableViewColumn, we’re reusing code here, an alias might have been nice so we could write TreeViewColumn but hay at least we’re not copy-paste-modifying here 😉 .

TreeView {
        anchors.fill: parent
        model: theModel
        itemDelegate: Rectangle {
           color: ( styleData.row % 2 == 0 ) ? "white" : "lightblue"
           height: 20

           Text {
               anchors.verticalCenter: parent.verticalCenter
               anchors.left: parent.left // by default x is set to 0 so this had no effect
               text: styleData.value
           }
       }

        TableViewColumn {
            role: "name_role"
            title: "Name"
        }
        TableViewColumn {
            role: "description_role"
            title: "Description"
        }
    }

*Note like the TableView the TreeView has a default itemDelegate so we didn’t have to provide one but since the ListView does not have a default delegate I’m providing one to keep the views looking similar. Also note that the itemDelegate is applied to both the branches and the leafs; this is because a TreeView can present data N levels deep so it can’t provide N number of different item delegates. If you want to provide a different look to branches then you do leafs then you’ll have to implement that logic within your itemDelegate using either the styleData.depth, styleData.isExpanded, styleData.hasChildren, or styleData.hasSibling attached properties

The above code will render the following when run:

TreeView_Tutorial_TreeView

Note here that like the TableView each cell delegate is acting on a role and NOT a data entry. Because of this each cell delegate does NOT have access to any of the roles for the given data entry and only has access to the single role; this can be a source of pain requiring work a rounds in some cases so keep it in mind. The role data is accessed via the styleData attached property (see TreeView::delegate property for more info).

There you have it, that is the quick and dirty on how to use the new TreeView to present your tree structured data.

You can find a sample application here on my GitHub

Thank you I hope you have enjoyed and found this tutorial helpful. Feel free to leave any comments or questions you might have below and I’ll try to answer them as time permits.

Until next time think imaginatively and design creatively

Brad

My interest in computer programming started back in high school and Software Development has remained a hobby of mine ever since. I graduated as a Computer Engineering Technologist and have been working as a Software Developer for many years. I believe that software is crafted; understanding that how it is done is as important as getting it done. I enjoy the aesthetics in crafting elegant solutions to complex problems and revel in the knowledge that my code is maintainable and thus, will have longevity. I hold the designation Certified Technician (C.Tech.) with the Ontario Association of Computer Engineering Technicians and Technologists (OACETT), have been certified as a Professional Scrum Master level 1 (PSM I) and as a Professional Scrum Developer level 1 (PSD I) by Scrum.org as well as designated as an Officially Certified Qt Developer by the Qt Company. For more on my story check out the about page here

Feel free to write a reply or comment.