10. Tree Widgets

Tree widgets are designed to represent hierarchical data structures, such as file systems or organizational charts, where items can have parent-child relationships.

  • QTreeWidget is a convenience class with built-in item management, allowing you to create and manipulate tree nodes directly.

  • QTreeView follows Qt’s model-view architecture and works with a separate model. This enables dynamic updates and efficient handling of large datasets.

  • QColumnView displays a model using multiple QListViews, one for each level of the hierarchy.

Common features include expandable and collapsible nodes, drag-and-drop support, item editing, checkable items, and multi-column display for detailed item properties.

10.1 QTreeWidget

QTreeWidget is a convenience class that provides a standard tree widget with a classic item-based interface.1 It automatically creates and manages its own built-in model behind the scenes and uses QTreeWidgetItems as its tree nodes. Each QTreeWidgetItem represents a node in the tree. For top-level items, parent is the widget itself.

An icon of a clipboard-list1

Your application needs to display a set of configuration options grouped into categories such as General and Notifications.

To present hierarchical configuration settings using a QTreeWidget:

  1. Create a QTreeWidget object and set its column count. The default is 1 column, but for name-value pairs you need 2 columns. The data is stored in a nested Python tuple where each node follows the pattern (name, value, children):

    • name - a string label.
    • value - the setting’s value (string, bool, etc.)
    • children - a list of child tuples in the same format, or [] for leaf nodes. The root node is ‘Application Settings’, which contains two category children (‘General’ and ‘Notifications’), each with leaf nodes representing the actual settings.
  2. Populate the tree using a recursive build_tree() helper method. This method takes a parent (either the tree widget itself or a QTreeWidgetItem) and the node data as parameters. It unpacks the tuple, creates a QTreeWidgetItem, and recursively adds any children. Qt item flags are used to make only the leaf nodes editable.

  3. Save the changes to the configuration. When the user edits a value, the itemChanged() signal is emitted. Connect it to a slot that saves the updates configuration (here simulated).

When you run the application, you see an editable tree widget displaying the configuration hierarchy.

10.2 QTreeView

A QTreeView implements a tree representation of items from a model as part of Qt’s model-view architecture. Unlike QTreeWidget it does not manage its own model so you need to supply one explicitly.2

An icon of a clipboard-list1

You need to display a table of countries grouped by continent, with column for population and capital.

To show a list of countries grouped by continent using a QTreeView:

  1. Create and populate the model. Use a QStandardItemModel with QStandardItem objects as tree nodes. Because the data has only two levels (continent and country) you can build the model directly in the main window __init__() without recursion. QStandardItemModel provides an invisible root item (accessed via invisibleRootItem()) that serves as the parent for top-level items. Add continent items to the invisible root, then add country items to their respective continent parents.

  2. Create the QTreeView.

  3. Set the model on the view with setModel().

QStandardItemModel sits halfway between the fully hidden default tree model of QTreeWidget and a fully custom QAbstractItemModel subclas (covered in chapters 22 - 26):

  • QTreeWidget - model is completely hidden and you work only with QTreeWidgetItem objects.

  • QStandardItemModel - model is explicit and you own it, but it is still item-based (QStandardItem objects), so you don’t need to implement the model interface yourself.

  • QAbstractItemModel - you implement the model from scratch, mapping directly to your own data structures.

QStandardItemModel gives you the flexibility of the model-view split without the overhead of subclassing QAbstractItemModel. The tradeoff is that it stores data in QStandardItem objects internally, which can bel less efficient than a custom model.

10.3 Lazy-loading Trees

Lazy loading is a technique used to defer initialization of an object until it is needed3. In Qt’s model-view architecture it is useful for fetching and displaying large lists, tables or trees with large or deep hierarchies, such as file systems: instead of loading every subdirectory at startup, child nodes are populated only when the user expands a parent node. This keeps the application responsive and reduces initial memory and CPU usage.

An icon of a clipboard-list1

In your application, you need to let users browse the file system (for example, to select backup folders or view log directories) without freezing the UI. You implement lazy loading in a QTreeView so that subdirectories of the home folder are populated only on demand when the user expands a parent node.

To implement lazy loading with a QTreeView:

  1. Create a QTreeView and a QStandardItemModel. Add a single top-level item representing the home directory (Path.home()). Attach a single placeholder child row to this item. The placeholder ensures the expand arrow is visible even though the real children have not yet been loaded.

  2. Connect the expanded() signal of the tree view to a slot. This signal is emitted every time the user clicks the expand arrow on a node.

  3. In the get_subdirectories() slot, check if the expanded item still contains the placeholder. If it does, remove the placeholder, read the real subdirectories from the filesystem using Path.iterdir(), and create a new QStandardItem for each subdirectory. Each new item also receives its own placeholder child so that it can be expanded later. Finally, add the new items to the parent.

When you run the application, you see a tree view that initially shows only the home folder. As you expand each directory, its subdirectories are loaded on demand.


  1. If you don’t implement __init__() in your class at all, the parent class gets initalized automatically.↩︎

  2. https://doc.qt.io/qtforpython-6/↩︎

  3. https://doc.qt.io/↩︎