Реализация пользовательского файлового браузера на PySide6
Я хотел бы реализовать файловый браузер на PySide6, и мои цели:
- Отображать файлы и папки всегда вверху (независимо от сортировки), чтобы пользователь мог дважды щелкнуть по ним и подняться на один уровень.
- После я хотел бы отображать папки, а затем файлы (как это делает проводник Windows) независимо от сортировки.
- Иметь альтернативный режим отображения, в котором отображается определенный набор файлов (они могут находиться на разных дисках, в разных папках и т. Д.).
В настоящее время я использую следующий код для инициализации модели и представления:
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()
вызов.
Итак, мои конкретные вопросы:
- Могу ли я использовать QSortFilterProxyModel для решения всех проблем, упомянутых выше? Если да, предоставьте образец реализации.
- Если вы считаете, что есть лучший подход к решению этой проблемы, опишите его.
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)