我有QListView
和QFileSystemModel
。根據QTreeView
中的選擇,QListView
顯示該文件夾的內容。
現在我需要根據某些條件更改文件名的顏色。
最初的想法是遍歷QListView中的項目,並根據條件是否滿足來設置每個項目的顏色。然而,這似乎是不可能的,因爲QFileSystemModel
的setData()
方法只接受更改EditRole
,忽略像[見this]有條件地更改連接到QFileSystemModel的QListView中的文件的顏色
self.FileModel.setData(index, QtGui.QBrush(QtCore.Qt.red), role=QtCore.Qt.ForegroundRole)
這也被指出here ,並在後者的建議是,子類QItemDelegate
,用於對QListView中的項目進行着色。
因此,我將子類別QStyledItemDelegate
並重新實現了它的paint()
方法,以綠色顯示文件名,如果條件滿足 - 哪些工作正常。然而它現在看起來很醜陋:文件圖標丟失,「mouse_over」效果不再有效。
雖然這個子類反正是一個混亂的變通辦法,我頂層的問題是
- 有沒有辦法上色根據條件在連接到一個
QFileSystemModel
項目QListView
?
現在提供的,這可能並非如此,堅持QItemDelegate的子類,
- 有沒有辦法讓漂亮的選擇和圖標回到原來的行爲?
- 有誰知道哪個ItemDelegate最初用於QListView中的QFileSystemModel以及如何使用它?
- 是否有可能獲得它的源代碼並從那裏複製繪畫方法?
這是一個最小的代碼,它使用了子類並顯示了descibed行爲。它使用一個可以輸入字符串的QLineEdit
,這樣所有包含該字符串的文件都會以綠色突出顯示。
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's 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_())
這是它的外觀與不繼承QItemDelegate比較:
只提,這個代碼是,一旦條件發生變化,需要另一個問題將鼠標移動到QFileView中以啓動重新繪製。我想知道我可以使用哪個插槽連接信號來直接完成此操作。
這完美的作品。我想知道爲什麼在尋找解決方案時找不到這種模型的子類。這通常沒有完成,還是有任何缺點? – ImportanceOfBeingErnest
@ImportanceOfBeingErnest。 Qt似乎不遵循Python的[TOOWTDI](http://wiki.python.org/moin/TOOWTDI)方法 - 它通常提供幾種不同的方法來解決某些問題。子類化可能是最常用的方法,但它顯然取決於感興趣的方法是否可以有效地重新實現(即它們是否是虛擬方法)。 – ekhumoro