Conditionally change the color of files in QListView connected to QFileSystemModel

I have a QListView with a QFileSystemModel . Based on the selection in QTreeView , QListView shows the contents of the folder.
Now I need to change the color of the file names depending on some conditions.
The initial idea would be to iterate over the elements in a QListView and set the color for each element depending on whether the condition is met. However, this seems impossible, since the setData() QFileSystemModel only accepts changes to EditRole , ignoring something like [see this ]

 self.FileModel.setData(index, QtGui.QBrush(QtCore.Qt.red), role=QtCore.Qt.ForegroundRole) 

It is also indicated here and the sentence in the latter was a subclass of QItemDelegate for the purpose of coloring elements in a QListView.

Therefore, I subclassed QStyledItemDelegate and redefined its paint() method to show the file name in green, if the condition is met, this works fine. However, now it looks pretty ugly: file icons are lost and the mouse_over effect no longer works.

Although this subclassing works randomly anyway, my top level question will be

  • Is there a way to colorize elements in a QListView related to a condition-based QFileSystemModel ?

Now provided that this may not be the case, and stick with the QItemDelegate subclass,

  • Is there a way to bring back the original behavior with good choices and icons?
  • Does anyone know which ItemDelegate is initially used for QFileSystemModel in a QListView and how to use it?
  • Is it possible to get the source code and copy the drawing method from there?

Below is the minimal code that uses subclassification and shows user behavior. It uses QLineEdit , where you can enter a line, so that all files containing this line are highlighted in green.

 import sys from PyQt4 import QtGui, QtCore class MyFileViewDelegate(QtGui.QStyledItemDelegate ): def __init__(self, parent=None, *args, **kwargs): QtGui.QItemDelegate.__init__(self, parent, *args) self.condition = None self.isMatch = False self.brush_active = QtGui.QBrush(QtGui.QColor("#79b9ed")) self.brush_active_matched = QtGui.QBrush(QtGui.QColor("#58cd1c")) self.pen = QtGui.QPen(QtGui.QColor("#414141") ) self.pen_matched = QtGui.QPen(QtGui.QColor("#39c819") ) self.pen_active = QtGui.QPen(QtGui.QColor("#eef2fd") ) self.pen_active_matched = QtGui.QPen(QtGui.QColor("#e7fade") ) def paint(self, painter, option, index): text = index.data(QtCore.Qt.DisplayRole) self.matchText(text) painter.save() ######## set background painter.setPen(QtGui.QPen(QtCore.Qt.NoPen)) if option.state & QtGui.QStyle.State_Selected: if self.isMatch: painter.setBrush(self.brush_active_matched) else: painter.setBrush(self.brush_active) painter.drawRect(option.rect) ######## set font color if option.state & QtGui.QStyle.State_Selected: if self.isMatch: painter.setPen(self.pen_active_matched) else: painter.setPen(self.pen_active) else: if self.isMatch: painter.setPen(self.pen_matched) else: painter.setPen(self.pen) painter.drawText(option.rect, QtCore.Qt.AlignLeft, text) painter.restore() def matchText(self, filename): # testing condition. In the real case this is much more complicated if (self.condition != None) and (self.condition != "") and (self.condition in filename): self.isMatch = True else: self.isMatch = False def setCondition(self, condition): self.condition = condition class MainWidget(QtGui.QWidget): def __init__(self, parent=None, useDelegate = False): super(MainWidget, self).__init__(parent) self.setLayout(QtGui.QVBoxLayout()) self.FolderModel = QtGui.QFileSystemModel() self.FolderModel.setFilter(QtCore.QDir.NoDotAndDotDot | QtCore.QDir.AllDirs) self.FolderModel.setRootPath("") self.FolderView = QtGui.QTreeView(parent=self) self.FolderView.setModel(self.FolderModel) self.FolderView.setHeaderHidden(True) self.FolderView.hideColumn(1) self.FolderView.hideColumn(2) self.FolderView.hideColumn(3) self.FolderView.expanded.connect(self.FolderView.scrollTo) self.FolderView.clicked[QtCore.QModelIndex].connect(self.browserClicked) self.FileModel = QtGui.QFileSystemModel() self.FileModel.setFilter(QtCore.QDir.NoDotAndDotDot | QtCore.QDir.Files) self.FileView = QtGui.QListView(parent=self) self.FileView.setModel(self.FileModel) self.FileViewDelegate = None if useDelegate: self.FileViewDelegate = MyFileViewDelegate() self.FileView.setItemDelegate(self.FileViewDelegate) self.FileView.setSelectionMode( QtGui.QAbstractItemView.ExtendedSelection ) self.LineEdit = QtGui.QLineEdit() self.LineEdit.textChanged.connect(self.changeCondition) # Add Widgets to layout self.layout().addWidget(self.FolderView) self.layout().addWidget(self.FileView) self.layout().addWidget(self.LineEdit) def changeCondition(self, text): if self.FileViewDelegate: self.FileViewDelegate.setCondition(text) def browserClicked(self, index): # the signal passes the index of the clicked item # set the FileView root_index to the clicked index dir_path = self.FileModel.filePath(index) root_index = self.FileModel.setRootPath(dir_path) self.FileView.setRootIndex(root_index) class App(QtGui.QMainWindow): def __init__(self, parent=None, useDelegate=False): super(App, self).__init__(parent) self.central = MainWidget(parent =self, useDelegate=useDelegate) self.setCentralWidget(self.central) if __name__=='__main__': app = QtGui.QApplication(sys.argv) thisapp = App(None, True) # set False to view App without custom FileViewDelegate thisapp.show() sys.exit(app.exec_()) 

This is a comparison of how it looks with and without a subclass of QItemDelegate:

enter image description here

just to mention, another problem with this code is that after changing the condition, you need to move the mouse in QFileView to start the redraw. I wonder which slot I can use to connect to the LineEdit.textChange signal to do this directly.

+6
source share
1 answer

No need to delete item. This can be achieved much more easily by overriding the data method QFileSystemModel :

 class FileSystemModel(QtGui.QFileSystemModel): def __init__(self, *args, **kwargs): super(FileSystemModel, self).__init__(*args, **kwargs) self.condition = None def setCondition(self, condition): self.condition = condition self.dataChanged.emit(QtCore.QModelIndex(), QtCore.QModelIndex()) def data(self, index, role=QtCore.Qt.DisplayRole): if self.condition and role == QtCore.Qt.TextColorRole: text = index.data(QtCore.Qt.DisplayRole) if self.condition in text: return QtGui.QColor("#58cd1c") return super(FileSystemModel, self).data(index, role) class MainWidget(QtGui.QWidget): def __init__(self, parent=None, useDelegate = False): super(MainWidget, self).__init__(parent) ... self.FileModel = FileSystemModel(self) ... def changeCondition(self, text): self.FileModel.setCondition(text) 
+3
source

Source: https://habr.com/ru/post/1011878/


All Articles