6

私は と を持ってQListViewQFileSystemModelます。での選択に基づいてQTreeViewQListViewフォルダの内容が表示されます。
ここで、条件に応じてファイル名の色を変更する必要があります。
最初のアイデアは、QListView 内のアイテムを反復処理し、条件が満たされているかどうかに応じて各アイテムの色を設定することです。ただし、これは不可能のようです。setData()メソッドはQFileSystemModelへの変更のみを受け入れ、次のEditRoleようなものを無視するためです [これを参照]

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

これはここでも指摘されて おり、後者の提案はQItemDelegate、QListView の項目を色付けする目的でサブクラス化することでした。

したがって、条件が満たされた場合にファイル名を緑色で表示するメソッドをサブクラス化QStyledItemDelegateして再実装しました-これは正常に機能します。paint()しかし、今は見栄えが悪いです。ファイル アイコンが失われ、"mouse_over" 効果が機能しなくなりました。

このサブクラス化はとにかく厄介な回避策ですが、私のトップレベルの質問は

  • 条件に基づいてQListView接続されたアイテムに色を付ける方法はありますか?QFileSystemModel

これが当てはまらない可能性があり、QItemDelegate のサブクラス化に固執する場合、

  • 素敵な選択とアイコンを元の動作に戻す方法はありますか?
  • QListView で QFileSystemModel に最初に使用された ItemDelegate とその使用方法を知っている人はいますか?
  • ソースコードを入手して、そこから paint メソッドをコピーすることは可能ですか?

以下は、サブクラス化を使用し、記述された動作を示す最小限のコードです。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 をサブクラス化した場合としない場合の比較です。

ここに画像の説明を入力

言及しておくと、このコードのもう 1 つの問題は、条件が変更されると、マウスを QFileView に移動して再描画を開始する必要があることです。LineEdit.textChange信号に直接接続するためにどのスロットを使用できるのだろうか。

4

1 に答える 1

4

item-delegate は必要ありません。dataのメソッドを再実装することで、はるかに簡単に実現できます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)
于 2016-11-06T22:02:15.957 に答える