PyQt5. QListView менеджер файлов картинок. Как заменить иконки на миниатюры изображений png?

Создал класс с моделью QFileSystemModel. Проблема - нужно чтобы вместо иконок отображались миниатюры (как в обычном файловом менеджере Windows).

class MyFileManager(QListView):
    def __init__(self):
        super().__init__()
        self.mdl = QFileSystemModel()
        self.mdl.setRootPath(QDir.rootPath())
        self.setModel(self.mdl)

        self.setWindowTitle('менеджер файлов')
        self.setRootIndex(self.mdl.index(QDir.currentPath()))
        self.setAcceptDrops(True)

        self.setDropIndicatorShown(True)

        self.setDragEnabled(True)
        self.setViewMode(QListView.IconMode)
        self.setMovement(QListView.Free)
        self.setGridSize(QSize(100, 100))
        self.setIconSize(QSize(80, 80))

Пробовал создать дополнительный класс, его средствами получается поменять иконки на миниатюры. Но тогда пропадает возможность Drag & Drop.

class MyListModel(QAbstractListModel):
    def __init__(self, datain, parent=None, *args):
        """ datain: a list where each item is a row
        """
        QAbstractListModel.__init__(self, parent, *args)
        self.listdata = datain

    def rowCount(self, parent=QModelIndex()):
        return len(self.listdata)

    def data(self, index, role):
        if index.isValid() and role == Qt.DecorationRole:
            return QIcon(QPixmap(self.listdata[index.row()]))
        if index.isValid() and role == Qt.DisplayRole:
            return QVariant(path.splitext(path.split(self.listdata[index.row()])[-1])[0])
        else:
            return QVariant()

Что можно сделать, чтобы сохранить драг-дроп и заменить иконки на миниатюры? Предпочтительно с моделью QFileSystemModel.


Ответы (2 шт):

Автор решения: Павел

Решено! Необходимо использовать собственный класс MyIconProvider(QFileIconProvider) и установить setIconProvider(MyIconProvider())

class MyIconProvider(QFileIconProvider):
def __init__(self):
    super().__init__()

def icon(self, type):

    get_path = type.filePath() # получаем путь к файлу

    if get_path.endswith(".png"): # отфильтровываем для каких будут миниатюры
        tmp_pxmp = QPixmap(QSize(64,64))
        tmp_pxmp.load(get_path) # загружаем картинку
        return QIcon(tmp_pxmp) # и возвращаем в виде иконки
    else:
        return super().icon(type)

В своей структуре добавляем строку назначения провайдера:

self.mdl.setIconProvider(MyIconProvider())

В итоге мой рабочий код выглядит так:

class MyIconProvider(QFileIconProvider):
def __init__(self):
    super().__init__()

def icon(self, type: 'QFileIconProvider.IconType'):

    get_path = type.filePath()

    if get_path.endswith(".png"):
        tmp_pxmp = QPixmap(QSize(64,64))
        tmp_pxmp.load(get_path)
        return QIcon(tmp_pxmp)
    else:
        return super().icon(type)

class MyFileManager(QListView):
def __init__(self):
    super().__init__()

    self.mdl = QFileSystemModel()
    self.mdl.setRootPath(QDir.rootPath())
    self.mdl.setIconProvider(MyIconProvider()) # <--------------

    self.setWindowTitle('менеджер файлов')
    self.setModel(self.mdl)
    self.setRootIndex(self.mdl.index(QDir.currentPath()))

    self.setViewMode(QListView.IconMode)
    self.setMovement(QListView.Snap)
    self.setGridSize(QSize(100, 100))
    self.setIconSize(QSize(80, 80))
→ Ссылка
Автор решения: S. Nick

Да, то что вы предложили работает. А беда в том, что есть битые изображения.

bool QPixmap::load(const QString &fileName, const char *format = nullptr, Qt::ImageConversionFlags flags = Qt::AutoColor)

Загружает растровое изображение из файла с данным fileName. \

  • Возвращает истину, если растровое изображение было успешно загружено;
  • в противном случае делает растровое изображение недействительным и возвращает false.

import sys
from PyQt5.Qt import *


class MyIconProvider(QFileIconProvider):
    def __init__(self):
        super().__init__()

    def icon(self, _type: 'QFileIconProvider.IconType'):
        get_path = _type.filePath()

        if get_path.endswith(".png") or \
            get_path.endswith(".jpg") or\
            get_path.endswith(".gif"):
            
            tmp_pxmp = QPixmap(QSize(64, 64))
            
            pix = tmp_pxmp.load(get_path)                                      # +++ = pix
            
            if pix:                                                            # +++
                return QIcon(tmp_pxmp)                                         # +++
            else:
                print(f'Это изображение битое !!! -> {pix} -> {get_path}')     # +++ !!!
                return super().icon(_type)                                     # +++
            
        else:
            return super().icon(_type)


class MyFileManager(QListView):
    def __init__(self):
        super().__init__()

        self.mdl = QFileSystemModel()
        self.mdl.setRootPath(QDir.rootPath())
        
        self.mdl.setIconProvider(MyIconProvider())  # <---

        self.setWindowTitle('менеджер файлов')
        self.setModel(self.mdl)
        self.setRootIndex(self.mdl.index(QDir.currentPath()))
        self.setViewMode(QListView.IconMode)
        self.setMovement(QListView.Snap)
        self.setGridSize(QSize(100, 100))
        self.setIconSize(QSize(80, 80))
        
        
if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MyFileManager()
    window.show()
    sys.exit(app.exec_())

введите сюда описание изображения

→ Ссылка