Как использовать QitemDelegate с несколькими стекированными моделями прокси? - PullRequest
0 голосов
/ 28 сентября 2018

Этот вопрос связан с предыдущим вопросом: как использовать QSortFilterProxyModel для фильтрации 2d-массива?

Я пытался составить несколько прокси-моделей для отображения 2d-массива данныхв qtableview.@eyllanesc предоставил действительно классное решение моего вопроса, но, похоже, он не совместим с qitemdelegate.Когда я добавляю это к его примеру, делегат не отображается как ожидалось.Без прокси-сервера он показывает корректно.

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_())

Вот ожидаемый результат, который я ищу:

enter image description here

и этоэто то, на что это похоже, когда я обхожу модель прокси (числа красные).замена: self.tvf.setModel (proxy3) на self.tvf.setModel (модель) enter image description here

1 Ответ

0 голосов
/ 28 сентября 2018

Вы неправильно используете делегата, который иногда работает, а иногда нет.Концепции делегата и IndexWidget представляют собой 2 альтернативы: первая представляет собой низкоуровневое рисование, но также имеет низкую стоимость, а второй вместо этого виджет встроен в задачу элемента, простой, но дорогой, поскольку виджет гораздо больше, чем просто окрашенный, также имеетлогика.

В этом случае решение состоит в том, чтобы использовать 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"))

enter image description here

Примечание. Примечание. Не обязательно писать

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

, поскольку оно не изменено.

...