QitemDelegate 如何在多个代理模型堆叠的情况下使用?

How to use QitemDelegate with multiple proxy models stacked?

这个问题与上一个问题相关:

我一直在尝试堆叠多个代理模型以将二维数据数组显示到 qtableview 中。 @eyllanesc 为我的问题提供了一个非常酷的解决方案,但它似乎与 qitemdelegate 不兼容。当我将它添加到他的示例中时,委托不会按预期显示。没有 proxy3 它确实显示正确。

import random
import math
from PyQt4 import QtCore, QtGui


class TableModel(QtCore.QAbstractTableModel):
    def __init__(self, data, columns, parent=None):
        super(TableModel, self).__init__(parent)
        self._columns = columns
        self._data = data[:]

    def rowCount(self, parent=QtCore.QModelIndex()): 
        if parent.isValid() or self._columns == 0:
            return 0
        return math.ceil(len(self._data )*1.0/self._columns)

    def columnCount(self, parent=QtCore.QModelIndex()): 
        if parent.isValid():
            return 0
        return self._columns

    def data(self, index, role=QtCore.Qt.DisplayRole):
        if not index.isValid(): 
            return
        if role == QtCore.Qt.DisplayRole: 
            try:
                value = self._data[ index.row() * self._columns + index.column() ]
                return value
            except:
                pass

class Table2ListProxyModel(QtGui.QIdentityProxyModel):
    def columnCount(self, parent=QtCore.QModelIndex()):
        return 1

    def rowCount(self, parent=QtCore.QModelIndex()):
        if parent.isValid():
            return 0
        return self.sourceModel().rowCount() * self.sourceModel().columnCount()

    def mapFromSource(self, sourceIndex):
        if sourceIndex.isValid() and sourceIndex.column() == 0 \
                and sourceIndex.row() < self.rowCount():
            r = sourceIndex.row()
            c = sourceIndex.column()
            row = c * sourceIndex.model().columnCount() + r
            return self.index(row, 0)
        return QtCore.QModelIndex()

    def mapToSource(self, proxyIndex):
        r = proxyIndex.row() / self.sourceModel().columnCount()
        c = proxyIndex.row() % self.sourceModel().columnCount()
        return self.sourceModel().index(r, c)

    def index(self, row, column, parent=QtCore.QModelIndex()):
        return self.createIndex(row, column)


class ListFilterProxyModel(QtGui.QSortFilterProxyModel):
    def setThreshold(self, value):
        setattr(self, "threshold", value)
        self.invalidateFilter()

    def filterAcceptsRow(self, row, parent):
        if hasattr(self, "threshold"):
            ix = self.sourceModel().index(row, 0)
            val = ix.data()
            if val is None:
                return False
            return int(val.toString()) < getattr(self, "threshold")
        return True


class List2TableProxyModel(QtGui.QIdentityProxyModel):
    def __init__(self, columns=1, parent=None):
        super(List2TableProxyModel, self).__init__(parent)
        self._columns = columns

    def columnCount(self, parent=QtCore.QModelIndex()):
        return self._columns

    def rowCount(self, parent=QtCore.QModelIndex()):
        if parent.isValid():
            return 0
        return math.ceil(self.sourceModel().rowCount()/self._columns)

    def index(self, row, column, parent=QtCore.QModelIndex()):
        return self.createIndex(row, column)

    def data(self, index, role=QtCore.Qt.DisplayRole):
        r = index.row()
        c = index.column()
        row = r * self.columnCount() + c
        if row < self.sourceModel().rowCount():
            return super(List2TableProxyModel, self).data(index, role)

    def mapFromSource(self, sourceIndex):
        r = math.ceil(sourceIndex.row() / self.columnCount())
        c = sourceIndex.row() % self.columnCount()
        return self.index(r, c)

    def mapToSource(self, proxyIndex):
        if proxyIndex.isValid():
            r = proxyIndex.row()
            c = proxyIndex.column()
            row = r * self.columnCount() + c
            return self.sourceModel().index(row, 0)
        return QtCore.QModelIndex()




class Delegate(QtGui.QItemDelegate):
    def __init__(self, parent = None):
        QtGui.QItemDelegate.__init__(self, parent)

    def paint(self, painter, option, index):
        number = str(index.data(QtCore.Qt.DisplayRole).toString())
        widget  = QtGui.QWidget()
        layout = QtGui.QVBoxLayout()
        widget.setLayout( layout )
        title = QtGui.QLabel("<font color='red'>"+number+"</font>")
        layout.addWidget( title )

        if not self.parent().tvf.indexWidget(index):
            self.parent().tvf.setIndexWidget(
                index, 
                widget
            )
        
        QtGui.QItemDelegate.paint(self, painter, option, index)



class Widget(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        data = [random.choice(range(10)) for i in range(20)]

        l = QtGui.QHBoxLayout(self)
        splitter = QtGui.QSplitter()
        l.addWidget(splitter)

        tv = QtGui.QTableView()
        lv = QtGui.QListView()
        lvf = QtGui.QListView()
        self.tvf = QtGui.QTableView()

        delegate = Delegate(self)
        self.tvf.setItemDelegate(delegate)

        model = TableModel(data, 3, self)
        proxy1 = Table2ListProxyModel(self)
        proxy1.setSourceModel(model)
        proxy2 = ListFilterProxyModel(self)
        proxy2.setSourceModel(proxy1)
        proxy2.setThreshold(5)
        proxy3 = List2TableProxyModel(3, self)
        proxy3.setSourceModel(proxy2)

        tv.setModel(model)
        lv.setModel(proxy1)
        lvf.setModel(proxy2)
        self.tvf.setModel(proxy3)

        splitter.addWidget(tv)
        splitter.addWidget(lv)
        splitter.addWidget(lvf)
        splitter.addWidget(self.tvf )


if __name__=="__main__":
    import sys
    a=QtGui.QApplication(sys.argv)
    w=Widget()
    w.show()
    sys.exit(a.exec_())

这是我正在寻找的预期结果:

这就是我绕过代理模型时的样子(数字是红色的)。 更换: self.tvf.setModel(代理3) 到 self.tvf.setModel(型号)

您错误地使用了有时有效有时无效的委托。 delegate 和 IndexWidget 的概念有两种选择,第一种是低级绘画但成本低,第二种是将小部件嵌入到项目任务中,简单但昂贵,因为小部件不仅仅是简单的绘画,还有一个逻辑。

在这种情况下,解决方案是使用 QStyledItemDelegate 并通过修改调色板覆盖 initStyleOption() 方法。

class Delegate(QtGui.QStyledItemDelegate):
    def initStyleOption(self, option, index):
        super(Delegate, self).initStyleOption(option, index)
        option.palette.setBrush(QtGui.QPalette.Text, QtGui.QColor("red"))

注:注:可以不用写

def __init__(self, parent = None):
    QtGui.QItemDelegate.__init__(self, parent)

因为没有修改。