How to refresh a QTreeView in PyQt?

Updating the displayed directory in a QTreeView with QFileSystemModel
Heads up! You've already completed this tutorial.

If you're building a file explorer panel with QTreeView and QFileSystemModel, you might run into a common question: how do you update the view when the directory changes? Maybe your users can configure the root directory through a settings file, and you want the tree to reflect that new path without restarting the application.

The good news is that QFileSystemModel already watches the filesystem for changes within the current root directory — new files appearing, deletions, renames, and so on are handled automatically. But if you want to change which directory the tree is pointing at, you need to explicitly tell both the model and the view about the new path.

Setting the root path and root index

When you first set up your QTreeView with a QFileSystemModel, you typically do something like this:

python
self.model = QFileSystemModel()
root_index = self.model.setRootPath("/some/default/path")
self.treeView.setModel(self.model)
self.treeView.setRootIndex(root_index)

The call to setRootPath() tells the model which directory to watch. It returns a QModelIndex pointing to that directory. You then pass that index to setRootIndex() on the tree view, which tells the view to display that directory as the top-level item.

To "refresh" the view — meaning, to point it at a different directory — you just do both of these steps again with the new path:

python
def refresh_view(self, new_path):
    root_index = self.model.setRootPath(new_path)
    self.treeView.setRootIndex(root_index)

That's it. Calling setRootPath() updates the model's internal file watcher to monitor the new directory, and setRootIndex() updates the view to display it. The tree will immediately show the contents of the new path.

Why do you need both calls?

It might seem like calling setRootPath() alone should be enough, but the model and view have separate responsibilities:

  • setRootPath() on the model controls which part of the filesystem the model monitors. It returns a QModelIndex for that path.
  • setRootIndex() on the view controls which node in the model is displayed as the root of the tree.

If you only call setRootPath() without updating the root index on the view, the model knows about the new path, but the view is still pointing at the old index. The tree won't visually change.

A complete working example

Here's a small self-contained application that demonstrates this. It shows a QTreeView displaying the contents of your home directory, with a button that lets you pick a new folder. When you select a folder, the tree updates immediately.

python
import sys
from PyQt6.QtWidgets import (
    QApplication, QMainWindow, QTreeView,
    QVBoxLayout, QWidget, QPushButton, QFileDialog
)
from PyQt6.QtCore import QDir
from PyQt6.QtWidgets import QFileSystemModel


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("QTreeView Refresh Example")
        self.resize(600, 400)

        # Set up the model
        self.model = QFileSystemModel()
        self.current_path = QDir.homePath()
        root_index = self.model.setRootPath(self.current_path)

        # Set up the tree view
        self.tree = QTreeView()
        self.tree.setModel(self.model)
        self.tree.setRootIndex(root_index)

        # Hide the size, type, and date columns to keep it simple
        self.tree.hideColumn(1)
        self.tree.hideColumn(2)
        self.tree.hideColumn(3)

        # Button to change the directory
        self.button = QPushButton("Change Directory...")
        self.button.clicked.connect(self.change_directory)

        # Layout
        layout = QVBoxLayout()
        layout.addWidget(self.tree)
        layout.addWidget(self.button)

        container = QWidget()
        container.setLayout(layout)
        self.setCentralWidget(container)

    def change_directory(self):
        new_path = QFileDialog.getExistingDirectory(
            self, "Select Directory", self.current_path
        )
        if new_path:
            self.current_path = new_path
            self.refresh_view(new_path)

    def refresh_view(self, new_path):
        """Update the tree view to show a different directory."""
        root_index = self.model.setRootPath(new_path)
        self.tree.setRootIndex(root_index)


app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()

Click the Change Directory... button, pick a folder, and the tree updates to show its contents. The refresh_view method is the same two-line pattern described above — call setRootPath() on the model, then setRootIndex() on the view.

If you're reading the new path from a config file instead of a file dialog, you can call refresh_view() at whatever point your application detects the config has changed — after a button press, a menu action, a timer, or any other trigger that makes sense for your workflow.

Well done, you've finished this tutorial! Mark As Complete
[[ user.completed.length ]] completed [[ user.streak+1 ]] day streak

Bring Your PyQt/PySide Application to Market

Stuck in development hell? I'll help you get your project focused, finished and released. Benefit from years of practical experience releasing software with Python.

Find out More

Martin Fitzpatrick

How to refresh a QTreeView in PyQt? was written by Martin Fitzpatrick.

Martin Fitzpatrick has been developing Python/Qt apps for 8 years. Building desktop applications to make data-analysis tools more user-friendly, Python was the obvious choice. Starting with Tk, later moving to wxWidgets and finally adopting PyQt. Martin founded PythonGUIs to provide easy to follow GUI programming tutorials to the Python community. He has written a number of popular Python books on the subject.