PDA

View Full Version : QStyledItemDelegate ignores StyleSheet?



chouqud
30th January 2014, 15:05
I've subclassed a QStyledItemDelegate with the goal to draw a pixmap in the centre of a QTableView’s cell. Our pixmap does get rendered correctly but we lose all style defined in the stylesheet. Removing the delegate restores the style.

I would like to understand how to use a QStyledItemDelegate while maintaining the existing style. Here’s a PySide delegate that I thought would simply render the cell as is. Applying this delegate removes the style.


class MyStyleDelegate(QtGui.QStyledItemDelegate):
def __init__(self, parent=None):
super(MyStyleDelegate, self).__init__(parent)

def paint(self, painter, option, index):
super(MyStyleDelegate, self).paint(painter, option, index)

modelIndex = index
model = index.model()
if isinstance(model, QtGui.QAbstractProxyModel):
modelIndex = model.mapToSource(index)

options = QtGui.QStyleOptionViewItemV4(option)
self.initStyleOption(options, index)
style = options.widget.style() if options.widget else QtGui.QApplication.style()
style.drawControl(style.CE_ItemViewItem, options, painter, options.widget)
QtGui.QStyledItemDelegate.paint(self, painter, option, modelIndex)


When I step through this code, our widget is always None. That seems to contradict all the examples that I've found.

We're also differing from the examples and using a QTableView with a proxymodel but from what I've read that should not affect the style.

Any help would be welcomed.

(This has been cross-posted from a colleague's post on http://qt-project.org/forums/viewthread/37757/. We have yet to decide which is the best resource for our PySide questions.)

ChrisW67
30th January 2014, 22:56
What style are you expecting to see? An item view cell is typically rendered using style information derived from the model's various roles (in initStyleOption()) for the relevant index.

chouqud
5th February 2014, 02:19
What style are you expecting to see? An item view cell is typically rendered using style information derived from the model's various roles (in initStyleOption()) for the relevant index.

I need help understanding what you are saying, in my stylesheet I have:


QWidget:item:hover
{
background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #ffffff, stop: 1 #000000);
color: #000000;
}
My style is set in my QMainWindow and when I hover over an item in the QTableView without the QStyledItemDelegate enabled, I get the expected black and white gradient. When I enable the QStyledItemDelegate, the hover style does not appear. My expectations is that since my QStyledItemDelegate is not explicitly manipulating the hover case, the hover should remain as a black and white gradient.

ChrisW67
5th February 2014, 03:17
At line six you render the item in its default form.
The remaining lines render the same thing two more times over the top of that after going out of its way to get a model index for the wrong model.

In spite of that your code works here when the style sheet typo (line 43) is fixed:


import sys
from PyQt4 import QtGui

class MyStyleDelegate(QtGui.QStyledItemDelegate):
def __init__(self, parent=None):
super(MyStyleDelegate, self).__init__(parent)

def paint(self, painter, option, index):
super(MyStyleDelegate, self).paint(painter, option, index)

modelIndex = index
model = index.model()
if isinstance(model, QtGui.QAbstractProxyModel):
modelIndex = model.mapToSource(index)

options = QtGui.QStyleOptionViewItemV4(option)
self.initStyleOption(options, index)
style = options.widget.style() if options.widget else QtGui.QApplication.style()
style.drawControl(style.CE_ItemViewItem, options, painter, options.widget)
QtGui.QStyledItemDelegate.paint(self, painter, option, modelIndex)

def main():
app = QtGui.QApplication(sys.argv)

model = QtGui.QStandardItemModel(5, 5)
for r in range(5):
for c in range(5):
item = QtGui.QStandardItem("R%s C%s" % (r ,c))
model.setItem(r, c, item)

proxy = QtGui.QSortFilterProxyModel()
proxy.setSourceModel(model)

w = QtGui.QTableView()
w.setModel(proxy)
w.setSortingEnabled(True)
w.show()

delegate = MyStyleDelegate()
w.setItemDelegate(delegate)

w.setStyleSheet('''
QWidget::item:hover {
background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #ffffff, stop: 1 #000000);
color: #000000; }
''')


sys.exit(app.exec_())

if __name__ == '__main__':
main()

You can remove lines 9 to 15 and 20 with the same result

I have used PyQt4.

Edit: PySide 1.1.2 (Linux) does not render the hover gradient at all even with a base QStyledItemDelegate. This is a bug, probably one/both of these:
https://bugreports.qt-project.org/browse/PYSIDE-152
https://bugreports.qt-project.org/browse/PYSIDE-115

chouqud
5th February 2014, 14:17
This is unfortunate as I am using PySide.

My goal of this was to render a pixmap centred in the cell. If the QStyledItemDelegate does not work for me, could you suggest an alternative?