Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using multiple QStyledItemDelegate with stylesheets

Tags:

qt4

pyqt4

I'm creating a styled QTreeView using double-dispatch to resolve specific delegate for data items, which is working great. I subclassed the delegates from QStyledItemDelegate to take advantage of stylesheets, enabling the designers to style the UI outside of the code.

Unfortunately, I have been unable to address different styles from the CSS. How do I select and use the item sub-control style specified in the stylesheet?

The CSS I'm testing with:

QTreeView::item:selected {
    background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #dddddd, stop: 1 #888888);
}
QTreeView::item:selected[role="title"] {
    background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #fde7ef, stop: 1 #f1cbda);
}
QTreeView::item:selected[role="entry"] {
    background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #e7effd, stop: 1 #cbdaf1);
}

My delegate rendering classes:

class VisitingDelegate(QtGui.QAbstractItemDelegate):
    def __init__(self, parent=None):
        super(VisitingDelegate,self).__init__(parent)
        roles = {}
        self.renderRoles = roles

        d = TitleDelegate(parent)
        d.setProperty("role", "title")
        roles['title'] = d

        d = EntryDelegate(parent)
        d.setProperty("role", "entry")
        roles['entry'] = d

    def delegateForIndex(self, mi):
        role = mi.model().data(mi, "renderRole")
        return self.renderRoles[role]

    def paint(self, painter, option, mi):
        dg = self.delegateForIndex(mi)
        return dg.paint(painter, option, mi)
    def sizeHint(self, option, mi):
        dg = self.delegateForIndex(mi)
        return dg.sizeHint(option, mi)

class TextDocumentDelegate(QtGui.QStyledItemDelegate):
    fmt = "<font color='%(color)s'>%(text)s</font)>"
    def paint(self, painter, option, mi):
        painter.save()

        opt = QtGui.QStyleOptionViewItemV4(option)
        self.initStyleOption(opt, mi)
        opt.text = ''

        style = opt.widget.style()
        style.drawControl(style.CE_ItemViewItem, opt, painter, opt.widget)

        textRect = style.subElementRect(style.SE_ItemViewItemText, opt, opt.widget);
        doc = self.asTextDoc(option, mi)
        painter.translate(textRect.topLeft())
        doc.drawContents(painter)

        painter.restore()

    def sizeHint(self, option, mi):
        doc = self.asTextDoc(option, mi)
        sz = doc.size()
        sz = QtCore.QSize(sz.width(), sz.height())
        return sz

    def asTextDoc(self, option, mi):
        info = {}
        info['text'] = mi.model().data(mi, Qt.DisplayRole)

        doc = QtGui.QTextDocument()
        doc.setDefaultFont(option.font)
        pal = option.palette
        if option.state & QtGui.QStyle.State_Selected:
            color = pal.color(pal.HighlightedText)
        else: color = pal.color(pal.Text)
        info['color'] = color.name()

        doc.setHtml(self.fmt % info)
        return doc

class EntryDelegate(TextDocumentDelegate):
    pass
class TitleDelegate(TextDocumentDelegate):
    fmt = "<h3><font color='%(color)s'>%(text)s</font)></h3>"
like image 701
Shane Holloway Avatar asked Dec 30 '09 20:12

Shane Holloway


1 Answers

Different styles can't be selected that way. The properties for selecting the style sheet rule are taken from a QWidget (a QTreeView in this case), not a delegate. The delegate is not a widget, and there isn't a widget representing individual items. Your example can show this by adding a print where the style is obtained from the widget:

style = opt.widget.style()
print opt.widget

It will show that the widget for the style a QTreeView. Since the widget is the same for both delegates, it can't have a role setting that is two values.

Even though the style sheet is written so that it looks like the role is associated with an item, the rule selection is like it was written as:

QTreeView[role="title"]::item:selected
like image 113
baysmith Avatar answered Oct 15 '22 07:10

baysmith