Search code examples
pythonqtreeviewpyside6

QTreeView not displaying file icons (PySide6)


I recently built an app in PyQt5, and I was using a QTreeView to display all the items inside a folder. Today a switched to PySide6 and for some reason the TreeView is not showing the icons of the files/folders. I am going to toss in some images as examples.

This was using PyQt5 (also works with PySide2)

This is using PySide6

Did something change between the two releases? I tried looking for something online but nothing pops up. This is the code I am using (I don't know if it helps)

from PySide6 import QtWidgets as qtw
from PySide6 import QtCore as qtc
from PySide6 import QtGui as qtg
import sys
import logic


class MainWindow(qtw.QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # Init UI
        self.width = 540
        self.height = 380
        self.setGeometry(
            qtw.QStyle.alignedRect(
                qtc.Qt.LeftToRight,
                qtc.Qt.AlignCenter,
                self.size(),
                qtg.QGuiApplication.primaryScreen().availableGeometry(),
            ),
        )
        self.tree = qtw.QTreeView()
        self.model = qtw.QFileSystemModel()

        # Items
        self.path_input = qtw.QLineEdit()
        path_label = qtw.QLabel("Enter a path to begin: ")
        check_btn = qtw.QPushButton("Check")  # To display the items
        clear_btn = qtw.QPushButton("Clear")  # To clear the TreeView
        self.start_btn = qtw.QPushButton("Start")  # To start the process
        self.start_btn.setEnabled(False)

        # Layouts
        top_h_layout = qtw.QHBoxLayout()
        top_h_layout.addWidget(path_label)
        top_h_layout.addWidget(self.path_input)
        top_h_layout.addWidget(check_btn)
        bot_h_layout = qtw.QHBoxLayout()
        bot_h_layout.addWidget(clear_btn)
        bot_h_layout.addWidget(self.start_btn)
        main_v_layout = qtw.QVBoxLayout()
        main_v_layout.addLayout(top_h_layout)
        main_v_layout.addWidget(self.tree)
        main_v_layout.addLayout(bot_h_layout)
        self.setLayout(main_v_layout)

        check_btn.clicked.connect(self.init_model)
        clear_btn.clicked.connect(self.clear_model)
        self.start_btn.clicked.connect(self.start)

        self.show()

    def init_model(self):
        if logic.check(self.path_input.text()):
            self.model.setRootPath(self.path_input.text())
            self.tree.setModel(self.model)
            self.tree.setRootIndex(self.model.index(self.path_input.text()))
            self.tree.setColumnWidth(0, 205)
            self.tree.setAlternatingRowColors(True)
            self.path_input.clear()
            self.start_btn.setEnabled(True)
        else:
            qtw.QMessageBox.warning(self, "Error", "Path not found.")
            self.path_input.clear()

    def clear_model(self):
        self.tree.setModel(None)
        self.path_input.clear()

    def start(self):
        logic.start(self.path_input.text())
        qtw.QMessageBox.information(self, "Done", "Process completed")


if __name__ == "__main__":
    app = qtw.QApplication(sys.argv)
    w = MainWindow()
    sys.exit(app.exec_())

This is the logic.py file:

import os
import shutil


def check(path):
    if os.path.isdir(path):
        return True
    else:
        return False


def start(path):
    os.chdir(path)
    for root, dirs, files in os.walk(path):
        for filename in files:
            movie_name = filename
            strip_name = filename[:-4]
            print(f"Creating directory for {movie_name}")
            os.mkdir(strip_name)
            print("Moving item to new directory.")
            shutil.move(f"{path}\\{movie_name}", f"{path}\\{strip_name}\\{movie_name}")
            print("\n")
    print("Done.")


# For testing
if __name__ == "__main__":
    usr_input = input("Path: ")

Solution

  • It seems a bug: the icons are invalid (maybe a plugin is missing, or is not correctly installed or does not have all its dependencies).

    A workaround is to implement a custom QFileIconProvider:

    class FileIconProvider(qtw.QFileIconProvider):
        def icon(self, _input):
            if isinstance(_input, qtc.QFileInfo):
                if _input.isDir():
                    return qtw.QApplication.style().standardIcon(qtw.QStyle.SP_DirIcon)
                elif _input.isFile():
                    return qtw.QApplication.style().standardIcon(qtw.QStyle.SP_FileIcon)
            else:
                if _input == qtg.QAbstractFileIconProvider.Folder:
                    return qtw.QApplication.style().standardIcon(qtw.QStyle.SP_DirIcon)
                elif _input == qtg.QAbstractFileIconProvider.File:
                    return qtw.QApplication.style().standardIcon(qtw.QStyle.SP_FileIcon)
            return super().icon(_input)
    
    self.model.setIconProvider(FileIconProvider())