Реализация пользовательского файлового браузера на PySide6

Я хотел бы реализовать файловый браузер на PySide6, и мои цели:

  1. Отображать файлы и папки всегда вверху (независимо от сортировки), чтобы пользователь мог дважды щелкнуть по ним и подняться на один уровень.
  2. После я хотел бы отображать папки, а затем файлы (как это делает проводник Windows) независимо от сортировки.
  3. Иметь альтернативный режим отображения, в котором отображается определенный набор файлов (они могут находиться на разных дисках, в разных папках и т. Д.).

В настоящее время я использую следующий код для инициализации модели и представления:

      self.model = QFileSystemModel()
self.model.setRootPath(path)
self.model.setFilter(QDir.NoDot | QDir.AllEntries)
self.model.sort(0,Qt.SortOrder.AscendingOrder)
self.ui.treeView.setModel(self.model)
self.ui.treeView.setRootIndex(self.model.index(path))
self.ui.treeView.header().setSortIndicator(0, Qt.AscendingOrder)
self.ui.treeView.setSortingEnabled(True)

Вместо QFileSystemModel() я использую свою настроенную модель QFileSystemModel с дополнительным столбцом.

Я испытываю следующие проблемы:

  • сортируется вместе с другим содержимым и не отображается вверху
  • каталоги не остаются вверху после сортировки

Я не понимаю, как лучше всего решать проблемы, которые я решаю.

Я вижу следующие варианты:

  • используйте QSortFilterProxyModel и каким-то образом заставьте всегда быть сверху, независимо от сортировки (не уверен, возможно ли это), а также сначала сохраните каталоги (есть связанный вопрос ), я также потенциально мог бы использовать его для пункта 3 выше, чтобы отображать файлы по определенным критериям
  • используйте совершенно другой подход, возможно, QFileSystemWatcher или QTreeWidget, которые я заполню вручную (постоянное отображение наверху в любом случае вызывает проблемы).
  • как-то добавить .. вверху QTreeView после его загрузки или сортировки

Я попытался реализовать QSortFilterProxyModel, но столкнулся с другой проблемой: я не понимаю, как мне изменить treeView.setRootIndex() вызов.

Итак, мои конкретные вопросы:

  1. Могу ли я использовать QSortFilterProxyModel для решения всех проблем, упомянутых выше? Если да, предоставьте образец реализации.
  2. Если вы считаете, что есть лучший подход к решению этой проблемы, опишите его.

2 ответа

          import PySide2
    from PySide2 import QtWidgets
    from PySide2.QtWidgets import QFileSystemModel
    from PySide2.QtWidgets import QMainWindow, QWidget
    from PySide2.QtWidgets import QTreeView
    from PySide2.QtWidgets import QVBoxLayout
    from PySide2.QtCore import QDir
    from PySide2.QtCore import QSortFilterProxyModel
    from PySide2.QtCore import Qt

    class View(QMainWindow):
        def __init__(self):
            super().__init__()

            self._w_main = QWidget()
            self.setCentralWidget(self._w_main)
            self.tree_view = QTreeView(self._w_main)

            self._layout = QVBoxLayout()
            self._layout.addWidget(self.tree_view)
            self._w_main.setLayout(self._layout)

    class SortingModel(QSortFilterProxyModel):
        def lessThan(
                self,
                source_left: PySide2.QtCore.QModelIndex,
                source_right: PySide2.QtCore.QModelIndex
        ):
            file_info1 = self.sourceModel().fileInfo(source_left)
            file_info2 = self.sourceModel().fileInfo(source_right)

            if file_info1.isDir() and file_info2.isDir():
                return super().lessThan(source_left, source_right)
            return file_info1.isDir()

    app = QtWidgets.QApplication([])
    view = View()
    model = QFileSystemModel()
    model.setRootPath('.')
    model.setFilter(QDir.NoDot | QDir.AllEntries)
    model.sort(0, Qt.SortOrder.AscendingOrder)
    sorting_model = SortingModel()
    sorting_model.setSourceModel(model)
    view.tree_view.setModel(sorting_model)
    view.tree_view.setRootIndex(sorting_model.mapFromSource(model.index('.')))
    view.tree_view.header().setSortIndicator(0, Qt.AscendingOrder)
    view.tree_view.setSortingEnabled(True)
    view.showMaximized()
    return sys.exit(app.exec_())

QSortFilterProxyModel ставит .. вверху списка по умолчанию в PySide2 5.14.1 на моей машине.

mapFromSource используется для отображения индекса для setRootIndex

Следующее решение работает:

      class SortingModel(QSortFilterProxyModel):
    def lessThan(self, source_left: QModelIndex, source_right: QModelIndex):
        file_info1 = self.sourceModel().fileInfo(source_left)
        file_info2 = self.sourceModel().fileInfo(source_right)       
        
        if file_info1.fileName() == "..":
            return self.sortOrder() == Qt.SortOrder.AscendingOrder

        if file_info2.fileName() == "..":
            return self.sortOrder() == Qt.SortOrder.DescendingOrder
                
        if (file_info1.isDir() and file_info2.isDir()) or (file_info1.isFile() and file_info2.isFile()):
            return super().lessThan(source_left, source_right)

        return file_info1.isDir() and self.sortOrder() == Qt.SortOrder.AscendingOrder

Код для инициализации представления и модели такой же, как в ответе @bartolo-otrit:

          model = QFileSystemModel()
    model.setRootPath('.')
    model.setFilter(QDir.NoDot | QDir.AllEntries)
    model.sort(0, Qt.SortOrder.AscendingOrder)
    sorting_model = SortingModel()
    sorting_model.setSourceModel(model)
    view.tree_view.setModel(sorting_model)
    view.tree_view.setRootIndex(sorting_model.mapFromSource(model.index('.')))
    view.tree_view.header().setSortIndicator(0, Qt.AscendingOrder)
    view.tree_view.setSortingEnabled(True)
Другие вопросы по тегам