Как использовать QStyledItemDelegate для рисования только фона, не закрывая текст?

Как мне изменить только цвет фона моего элемента дерева с помощью делегата?

Я не смог понять, как это сделать, не рисуя поверх текста. Другими словами, когда я использую приведенный ниже код, цвет рисуется поверх текста. Текст находится под фоном...

def paint(self, painter, option, index):
    MyDelegate.paint(self, painter, option, index)

    painter.save()

    # set background color
    painter.setPen(QPen(Qt.NoPen))
    if self.item.is_set and option.state & QStyle.State_Selected:
        painter.setBrush(QBrush(QtGui.QColor(100, 200, 0, 200)))
    else:
        painter.setBrush(QBrush(Qt.NoBrush))

    painter.drawRect(option.rect)

    painter.restore()

Я хочу унаследовать столько, сколько смогу.

...

Что касается комментариев, я попытался применить ответ " Установить цвет для строки QTableView "... но я не могу заставить его работать на Python. Я не уверен, как optionV4.backgroundBrush() как-то влияет. Используется ли опция по ссылке, так что это изменение должно использоваться без возвращаемого значения?

(Они используются без переопределения paint)

def initStyleOption(self, option, index):
    print("initStyleOption...")
    MyBaseDelegate.initStyleOption(self, option, index)

    optionV4 = QtGui.QStyleOptionViewItemV4(option)
    optionV4.backgroundBrush = QBrush(QtGui.QColor(100, 200, 100, 200))

Я также пробовал это:

def initStyleOption(self, option, index):
    MyBaseDelegate.initStyleOption(self, option, index)
    option.backgroundBrush = QBrush(QtGui.QColor(100, 200, 100, 200))

...и это:

def initStyleOption(self, option, index):
    option.backgroundBrush = QBrush(QtGui.QColor(100, 200, 100, 200))
    MyBaseDelegate.initStyleOption(self, option, index)

И, согласно документам, это ничего не должно возвращать, поэтому я предполагаю, что опция IS передается по ссылке, что имеет смысл.

Я нашел другой пример, который работает (хотя я не пытался его понять)

def paint(self, painter, option, index):
    option = QtGui.QStyleOptionViewItemV4(option)  # Needed for "widget"
    self.initStyleOption(option, index)  # <--- I did not override this

    option.backgroundBrush = QBrush(QtGui.QColor(100, 200, 100, 200))
    option.widget.style().drawControl(QStyle.CE_ItemViewItem, option, painter)

    ColumnBaseDelegate.paint(self, painter, option, index)

... но цвет фона закрашивается цветом выделения. Поскольку я пытаюсь изменить цвет фона при выборе элемента, это проблема. Есть ли другая кисть или метод для работы с цветами выделения? Мне нужно, чтобы определенные типы предметов были другого цвета.

Я попробовал ответ, который демонстрирует инвертирование состояния выбора перед рисованием собственного фона, но по какой-то причине он нарисовал для меня пустой фон. А вот покраска сработала...

def paint(self, painter, option, index):

    if option.state & QStyle.State_Selected:
        option.state &= ~QStyle.State_Selected  # Invert state

        # This "cast", which is needed to get option.widget, seems to be
        #   needed for backgroundBrush as well.
        option = QtGui.QStyleOptionViewItemV4(option)  # Cast for widget
        option.backgroundBrush = QBrush(QColor(100, 200, 100, 200))

        option.widget.style().drawControl(QStyle.CE_ItemViewItem, option, painter)

    super(MyDelegate, self).paint(painter, option, index)

Я не понимаю, почему, поэтому я не буду добавлять это к ответу на данный момент.


person Rafe    schedule 07.06.2012    source источник
comment
Возможно, stackoverflow.com/questions/10630360/ вопрос поможет вам. Смотрите мой ответ в нем. Хотя этот конкретный вопрос касается стилизации индикатора выполнения, то же самое можно сделать и для древовидного представления.   -  person Ammar    schedule 07.06.2012
comment
возможный дубликат Установить цвет для строки QTableView   -  person alexisdm    schedule 07.06.2012
comment
@alexisdm: у меня проблемы с тем, чтобы заставить это что-то делать в Python. Смотрите мой пост   -  person Rafe    schedule 08.06.2012
comment
@Ammar: я не вижу, чтобы там использовался какой-либо делегат. Вы говорите, что применение стилей — это путь? Можно ли применить стиль непосредственно к индексу? Можете ли вы опубликовать простой общий пример для обычного фона элемента?   -  person Rafe    schedule 08.06.2012
comment
Присвоение было преобразованием типа в C++, но делает копию в python. Вам не нужен этот актерский состав здесь, просто option.backgroundBrush = QBrush(...). И да, аргумент option является возвращаемым значением.   -  person alexisdm    schedule 08.06.2012
comment
@alexisdm: я добавил то, что пытался, к моему вопросу выше. Если у вас есть рабочий пример, пожалуйста, опубликуйте его. Функция вызывается (моя строка печати работает), но, похоже, это не имеет никакого эффекта. Мне нужно что-то в другой функции? Мне все еще нужна краска () (я прокомментировал)? Спасибо еще раз за помощь. Надеюсь, я приближаюсь.   -  person Rafe    schedule 08.06.2012


Ответы (1)


Чтобы переопределить цвет фона для выбранных элементов, вы можете отключить выбранный флаг в initStyleOption. Например:

import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

class SelectionColorDelegate(QStyledItemDelegate):
        def __init__(self, parent):
        super(SelectionColorDelegate, self).__init__(parent)

    def initStyleOption(self, option, index):
        # let the base class initStyleOption fill option with the default values
        super(SelectionColorDelegate,self).initStyleOption(option, index)
        # override what you need to change in option
        if option.state & QStyle.State_Selected:
            option.state &= ~ QStyle.State_Selected
            option.backgroundBrush = QBrush(QColor(100, 200, 100, 200))

if __name__ == "__main__":
    app = QApplication(sys.argv)    
    treeWidget = QTreeWidget()
    treeWidget.setColumnCount(2)
    for i in range(5):
        item = QTreeWidgetItem(["Item %d"%i, "data" ])
        treeWidget.addTopLevelItem(item)
        for j in range(3):
            subItem = QTreeWidgetItem(["SubItem %d, %d"%(i,j), "subdata"])
            item.addChild(subItem)
        treeWidget.expandItem(item)

    treeWidget.setItemDelegate(SelectionColorDelegate(treeWidget))    
    treeWidget.show()   

    app.exec_()
    sys.exit()

По-видимому, фон также окрашивается QTreeView.drawRow перед вызовом функции делегата paint, поэтому для элементов с отступом часть этого фона сохраняет цвет по умолчанию.

person alexisdm    schedule 09.06.2012
comment
Пожалуйста, смотрите редактирование моего ответа. У меня это почему-то не сработало. Тем не менее, это было очень полезно! Мне придется посмотреть на drawRow дерева и подделать его там. Недостаточно оставить первую часть фона выделения исходным цветом. - person Rafe; 11.06.2012
comment
Есть еще кое-что еще происходит. Я пытался переопределить drawRow, но он рисовал фон для всей строки, хотя он всегда получает только index.column() 0. По какой-то причине поведение по умолчанию не заставляет цветной фон в моих других столбцах, которые обрабатываются делегатом, который просто вообще не рисует фон (обычно визуально выглядит так, будто выбран только столбец 0). Я хотел бы увидеть полную реализацию DrawRow и делегата Paint на Python. Это бы решило столько вопросов. - person Rafe; 12.06.2012