Как использовать QitemDelegate с несколькими моделями прокси в стеке?
Этот вопрос связан с предыдущим вопросом: как использовать QSortFilterProxyModel для фильтрации 2d-массива?
Я пытался сложить несколько моделей прокси для отображения 2d массива данных в qtableview. @eyllanesc предоставил действительно классное решение моего вопроса, но, похоже, он не совместим с qitemdelegate. Когда я добавляю его в свой пример, делегат не отображается должным образом. Без прокси3 он показывает правильно.
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(proxy3) на self.tvf.setModel (модель)
1 ответ
Вы неправильно используете делегата, который иногда работает, а иногда нет. Концепции делегата и 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"))
Примечание: Примечание: не нужно писать
def __init__(self, parent = None):
QtGui.QItemDelegate.__init__(self, parent)
так как он не изменен.