Как нарисовать стилизованный прямоугольник фокуса в QStyledItemDelegate?

Следующий вопрос от Бенно Дильманна из списка рассылки PyQt остается без ответа с 2008 года:

[..] У меня есть подкласс QStyledItemDelegate, который реализует функцию paint() для рисования содержимого некоторых ячеек QTableView. Как заставить его рисовать прямоугольник фокуса, если одна из этих ячеек имеет фокус? Я пробовал это:

class MyDelegate(QStyledItemDelegate):  
    ...
    def paint(self, painter, option, index):
        ...
        painter.save()
        if option.state & QStyle.State_HasFocus:
           self.parent().style().drawPrimitive(QStyle.PE_FrameFocusRect, option, painter)
        ...
        painter.restore()

но это просто ничего не делает. Ошибок нет, рамки фокусировки нет. Я просто хочу, чтобы система QStyle каким-то образом рисовала обычную рамку фокуса, если одна из моих пользовательских окрашенных ячеек имеет фокус. Документация QStyle говорит мне создать QStyleOptionFocusRect и использовать initFrom(). Но для initFrom() нужен QWidget, которого в данном случае у меня нет.

Я просто не понимаю.

Каков обычный способ получить кадры фокуса в ячейках QTableView, окрашенные пользовательскими делегатами?[..]


person Mark Visser    schedule 31.12.2014    source источник


Ответы (1)


Я столкнулся с той же проблемой. После большого разочарования я нашел ответ, похороненный в устаревшем классе QStyledItem. Вот решение PyQt/PySide, основанное на этом коде:

class MyDelegate(QtGui.QStyledItemDelegate):
    ...
    def drawFocus(self, painter, option, rect, widget=None):
        if (option.state & QtGui.QStyle.State_HasFocus) == 0 or not rect.isValid():
            return
        o = QtGui.QStyleOptionFocusRect()
        # no operator= in python, so we have to do this manually
        o.state = option.state
        o.direction = option.direction
        o.rect = option.rect
        o.fontMetrics = option.fontMetrics
        o.palette = option.palette

        o.state |= QtGui.QStyle.State_KeyboardFocusChange
        o.state |= QtGui.QStyle.State_Item
        cg = QtGui.QPalette.Normal if (option.state & QtGui.QStyle.State_Enabled) else QtGui.QPalette.Disabled
        o.backgroundColor = option.palette.color(cg, QtGui.QPalette.Highlight if (option.state & QtGui.QStyle.State_Selected) else QtGui.QPalette.Window)
        style = widget.style() if widget else QtGui.QApplication.style()
        style.drawPrimitive(QtGui.QStyle.PE_FrameFocusRect, o, painter, widget)

    def paint(self, painter, option, index):
        painter.save()
        # ... draw your delegate here, or call your widget's render method ...
        painter.restore()

        painter.save()
        # omit the last argument if you're not drawing a widget
        self.drawFocus(painter, option, option.rect, widget)
        painter.restore()
person Mark Visser    schedule 31.12.2014