How to use QTreeWidget() in PySide2

GOAL

To create tree widget in my GUI program with PySide2.

Environment

Windows 10
Python 3.8.7
PySide2 5.15.2

Related Classes

Reference: PySide.QtGui / Qt Widgets C++ Classes

Examples

I created sample window and 4 types of tree widgets and 2 functions. The below is the template.

import sys
from PySide2.QtWidgets import *

class MyMainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MyMainWindow, self).__init__(parent)
        self._generateUI()
        #self._simple_tree_widget()
        self._tree_widget1()
        
    def _generateUI(self):
        main_widget = QWidget()
        main_layout = QVBoxLayout()
        main_widget.setLayout(main_layout)
        self.setCentralWidget(main_widget)
        self.tree_widget = QTreeWidget()
        main_layout.addWidget(self.tree_widget)
    def _tree_widget1(self):
        ...
    def _tree_widget2(self):
        ...

def launch():
    app = QApplication.instance()
    if not app:
        app = QApplication(sys.argv)
    widget = MyMainWindow()
    widget.show()
    app.exec_()

launch()

Example 1. Simple tree widget

    def _tree_widget1(self):
        self.tree_widget.setHeaderLabels(["header"])
        tree_widget_item1 = QTreeWidgetItem(["item1"])
        tree_widget_item1.addChild(QTreeWidgetItem(["item1_2"]))
        tree_widget_item2 = QTreeWidgetItem(["item2"])
        tree_widget_item2.addChild(QTreeWidgetItem(["item2_2"]))
        self.tree_widget.addTopLevelItem(tree_widget_item1)
        self.tree_widget.addTopLevelItem(tree_widget_item2)

Example 2. Item with column

    def _tree_widget2(self):
        headers = ["header1", "header2", "header3"]
        self.tree_widget.setHeaderLabels(headers)
        tree_widget_item1 = QTreeWidgetItem(["items1_col1", "items1_col2", "items1_col3"])
        tree_widget_item1.addChild(QTreeWidgetItem(["items1_2_col1", "items1_2_col2", "items1_2_col3"]))
        self.tree_widget.addTopLevelItem(tree_widget_item1)

Example 3. Deep hierarchy tree with for loop

I used dict and for loop. Please let me know if you have any good implementation.

    def _tree_widget3(self):
        self.tree_widget.setHeaderHidden(True)
        # define items as dictionary
        children_level1 = ["child1", "child2", "child3"]
        children_level2 = {"child1":["child1_1", "child1_2"], "child2":["child2_1"], "child3":["child3_1", "child3_2", "child3_3"]}
        children_level3 = {"child1_2":["child1_2_1", "child1_2_3"], "child3_1":["child3_1_1"]}
        for child1 in children_level1:
            item1 = QTreeWidgetItem([child1])
            self.tree_widget.addTopLevelItem(item1)
            if child1 in children_level2:
                for child2 in children_level2[child1]:
                    item2 = QTreeWidgetItem([child2])
                    item1.addChild(item2)
                    if child2 in children_level3:
                        for child3 in children_level3[child2]:
                            item3 = QTreeWidgetItem([child3])
                            item2.addChild(item3)

Example 4. Use widget as item

I create custom widget to add a tree widget.

class MyItemWidget(QWidget):
    def __init__(self, id_str=0, parent=None):
        super(MyItemWidget, self).__init__(parent)
        main_layout = QVBoxLayout()
        self.setLayout(main_layout)
        label = QLabel("test_label" + id_str)
        button = QPushButton("test_button" + id_str)
        main_layout.addWidget(label)
        main_layout.addWidget(button)
        self.setAutoFillBackground(True)

Then set item and set widget to the item and column.

    def _tree_widget4(self):
        self.tree_widget.setHeaderHidden(True)
        tree_widget_item1 = QTreeWidgetItem(["parent"])
        tree_widget_item1_1 = QTreeWidgetItem(["child1"])
        tree_widget_item1_2 = QTreeWidgetItem(["child2"])
        tree_widget_item1.addChild(tree_widget_item1_1)
        tree_widget_item1.addChild(tree_widget_item1_2)
        self.tree_widget.addTopLevelItem(tree_widget_item1)

        child_widget1 = MyItemWidget(id_str='1')
        child_widget2 = MyItemWidget(id_str='1_1')
        child_widget3 = MyItemWidget(id_str='1_2')
        self.tree_widget.setItemWidget(tree_widget_item1, 0, child_widget1)
        self.tree_widget.setItemWidget(tree_widget_item1_1, 0, child_widget2)
        self.tree_widget.setItemWidget(tree_widget_item1_2, 0, child_widget3)

Example 5. Get the item currently selected

When item selected, call the function _display_selected()

self.tree_widget.itemPressed.connect(self._display_selected)

In the _display_selected(), get the selected items and display the names of them.

    def _display_selected(self):
        selected_items = self.tree_widget.selectedItems()
        print("selected items are ", [item.text(0) for item in selected_items])

If you’d like to allow multiple selection, set selection mode to the tree widget. See “SelectionMode” in PySide documentation for details about SelectionMode.
* You can use QAbstractItemView.SelectionMode from PySide2.QtWidgets in PySide2.

self.tree_widget.setSelectionMode(QAbstractItemView.MultiSelection)

Example 6. access all items with iterator

You can access item with iterator.

    def _iterate_all_items(self):
        it = QTreeWidgetItemIterator(self.tree_widget)
        while it.value():
            item = it.value()
            print(item.text(0))
            it.__next__()

Frequency used functions

To add header list

tree_widget.setHeaderLabels(["header_col1", "header_col2", ...])

To add top level item

tree_widget.addTopLevelItem(tree_widget_item)

To add child item to parent item

parent_tree_widget_item.addChild(child_tree_widget_item))

To get the list of children

tree_widget.children()

get and change the content of item

from PySide2.QtCore import Qt
item = self.tree_widget.findItems("item1", Qt.MatchExactly, column=0)[0]
item.setText(0, "changed_text")

To get items currently selected

self.tree_widget.selectedItems()

To hide header

self.tree_widget.setHeaderHidden(True)

Points

1. The argument of QTreeWidget should be the list of strings. If you pass single string as a string list, each character becomes the element of string list as below.

2. You can’t set child items to the same level at once. Even if you pass the list of strings as an argument of addChild(), the list item becomes one child item as below.

3. The number of items to display is defined by the number of header list. The number of items should be same as the the number of header labels or more.

4. If you use QWidget() as an item by using setItemWidget function, check the list of settings below.
Set PySide.QtGui.QWidget.autoFillBackground() property true, otherwise the widget’s background will be transparent, showing both the model data and the tree widget item.

Postscript

What is QTreeView?

QTreeView is one of the views used for model/view framework.
There are 2 types of model, QStandardItemModel (general dataset) and QFileSystemModel(path and directory structure), and QtreeView can display model as a tree.