На път да реша проблемите, които посочих в предишни въпроси (въпрос 1, въпрос 2) сам, успях да внедря персонализиран QStyledItemDelegate
, който отговаря на изискванията ми. Ето минимален работещ пример, илюстриращ текущото състояние:
import sys
import PySide.QtCore as core
import PySide.QtGui as gui
class DataRef(object):
def __init__(self, i):
self.i = i
def upperLabel(self):
return u'upperLabel {0}'.format(self.i)
def lowerLabel(self):
return u'lowerLabel {0}'.format(self.i)
def pixmap(self):
return gui.QPixmap(90, 90)
class MyListModel(core.QAbstractListModel):
def __init__(self, parent=None):
super(MyListModel, self).__init__(parent)
self._items = [DataRef(i) for i in range(20)]
def rowCount(self, parent=core.QModelIndex()):
return len(self._items)
def data(self, index, role=core.Qt.DisplayRole):
if not index.isValid():
return None
if role == core.Qt.DisplayRole:
return self._items[index.row()]
return
class MyListDelegate(gui.QStyledItemDelegate):
w = 300
imSize = 90
pad = 5
h = imSize + 2*pad
sepX = 10
def __init__(self, parent=None):
super(MyListDelegate, self).__init__(parent)
def paint(self, painter, option, index):
mouseOver = option.state in [73985, 73729]
if option.state & gui.QStyle.State_Selected:
painter.fillRect(option.rect, painter.brush())
pen = painter.pen()
painter.save()
x,y = (option.rect.x(), option.rect.y())
dataRef = index.data()
pixmap = dataRef.pixmap()
upperLabel = dataRef.upperLabel()
lowerLabel = dataRef.lowerLabel()
if mouseOver:
newPen = gui.QPen(core.Qt.green, 1, core.Qt.SolidLine)
painter.setPen(newPen)
else:
painter.setPen(pen)
painter.drawRect(x, y, self.w, self.h)
painter.setPen(pen)
x += self.pad
y += self.pad
painter.drawPixmap(x, y, pixmap)
font = painter.font()
textHeight = gui.QFontMetrics(font).height()
sX = self.imSize + self.sepX
sY = textHeight/2
font.setBold(True)
painter.setFont(font)
painter.drawText(x+sX, y-sY,
self.w-self.imSize-self.sepX, self.imSize,
core.Qt.AlignVCenter,
upperLabel)
font.setBold(False)
font.setItalic(True)
painter.setFont(font)
painter.drawText(x+sX, y+sY,
self.w-self.imSize-self.sepX, self.imSize,
core.Qt.AlignVCenter,
lowerLabel)
painter.restore()
def sizeHint(self, option, index):
return core.QSize(self.w, self.imSize+2*self.pad)
def editorEvent(self, event, model, option, index):
if event.type() == core.QEvent.MouseButtonRelease:
print 'Clicked on Item', index.row()
if event.type() == core.QEvent.MouseButtonDblClick:
print 'Double-Clicked on Item', index.row()
return True
if __name__ == '__main__':
app = gui.QApplication(sys.argv)
app.setStyleSheet('QListView::item:hover {background: none;}')
mw = gui.QMainWindow()
model = MyListModel()
view = gui.QListView()
view.setItemDelegate(MyListDelegate(parent=view))
view.setSpacing(5)
view.setModel(model)
mw.setCentralWidget(view)
mw.show()
sys.exit(app.exec_())
Използвах фиктивен клас DataRef
, който връща фиктивните етикети и пикселна карта за делегата. Делегатът е просто правоъгълен контур с пикселна карта отляво и 2 реда форматиран текст отдясно. „EditorEvent“ ми позволява да откривам щраквания и двойни щраквания.
проблеми
Функцията MyListDelegate.paint()
получава option.state
стойности, които ми се струват странни. Те не отговарят на QStyle.State
, което знам. Така че сега използвам тези големи int числа, които получих от простото отпечатване на int(option.state)
. Както и да е: не работи много добре! Долната граница на рамката не променя цвета си и понякога се случват странни неща.
Може ли някой да ми покаже по-добър начин да направя това? Оптимално е използването на цветове от QStyle за промяна на контура и цвета на фона, така че да може да се персонализира с помощта на StyleSheet?
Всички съвети или обяснения са високо оценени.