0

This question is related to this previous question: how to use QSortFilterProxyModel for filter a 2d array?

i have been trying to stack several proxy model to display a 2d array of data into a qtableview. @eyllanesc provided a really cool solution to my question but it doesn't seem to be compatible with qitemdelegate. When i add it to his example the delegate doesnt display as expected. Without the proxy3 it does show correctly.

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

Here is the expected result I am looking for:

enter image description here

and this is what it look like when i bypass the proxy model (the numbers are red). replacing : self.tvf.setModel(proxy3) to self.tvf.setModel(model) enter image description here

Community
  • 1
  • 1
nicosalto
  • 33
  • 1
  • 6

1 Answers1

0

You are incorrectly using the delegate that works sometimes if and sometimes not. The concepts of delegate and IndexWidget are 2 alternatives, the first one is a low level painting but also low cost, the second instead a widget is embedded in the item task simple but expensive since a widget is much more than a simple painted , also has a logic.

In this case the solution is to use a QStyledItemDelegate and overwrite the initStyleOption() method by modifying the palette.

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

Note: Note: it is not necessary to write

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

since it is not modified.

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • Thanks @eyllanesc, you mean that using setIndexWidget is incorrect within the delegate and are not designed to be used together ? I need to add a widget within each of my cells. Here i simplified the example, but in my app i display images in every cells. – nicosalto Sep 28 '18 at 08:48
  • @nicosalto Exactly, there are 2 concepts that compete, you must not use them together, for example with your code you are creating the widget every time you call paint, and paint is called every time, and therefore the resources are wasting. the current problem is of delegates so I solved it for it, so if I help you do not forget to mark it as correct, and if you want to use widgets create another question and I will try to help you. – eyllanesc Sep 28 '18 at 08:55
  • @nicosalto I recommend you to use delegates, the program will be more efficient in memory and speed. – eyllanesc Sep 28 '18 at 09:02
  • i added the question here with a simplier example : https://stackoverflow.com/questions/52552680/how-to-add-widgets-in-every-a-qtableview-cell-with-a-mvc-design – nicosalto Sep 28 '18 at 09:51