【问题标题】:How Do I Use a QStyledItemDelegate to Paint Only the Background, Without Covering the Text?如何使用 QStyledItemDelegate 仅绘制背景而不覆盖文本?
【发布时间】:2012-06-07 00:31:52
【问题描述】:

我应该如何使用委托仅更改树项的背景颜色?

如果不在文本上绘画,我无法弄清楚如何做到这一点。换句话说,当我使用下面的代码时,颜色会绘制在文本之上。文本在背景下...

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()

我想尽可能多地继承。

...

关于 cmets,我尝试应用答案“Set color to a QTableView row” ...但我似乎无法让它在 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)

根据文档,这不应该返回任何东西,所以我假设选项是通过引用传递的,这是有道理的。

我找到了另一个例子,它有效(虽然我没有试图理解它)

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)

我不明白为什么,所以我现在不会将其添加到答案中。

【问题讨论】:

  • 也许stackoverflow.com/questions/10630360/… 的问题会对你有所帮助。看看我在里面的回答。尽管该特定问题是关于样式进度条的,但树视图也可以这样做。
  • @alexisdm:我很难让它在 Python 中做某​​事。看我的帖子
  • @Ammar:我没有看到那里使用任何代表。你是说应用样式是要走的路吗?样式可以直接应用于索引吗?您可以为常规项目背景发布一个简单的通用示例吗?
  • 赋值是 C++ 中的类型转换,但在 python 中进行了复制。您不需要这里的演员表,只需option.backgroundBrush = QBrush(...)。是的,option 参数就是返回值。

标签: python qt delegates background paint


【解决方案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()

显然,在调用委托paint 函数之前,背景也是由QTreeView.drawRow 绘制的,因此对于缩进的项目,该背景的一部分保持默认颜色。

【讨论】:

  • 请查看我的答案的编辑。由于某种原因,这对我不起作用。不过还是很有帮助的!我得看看树的drawRow 并在那里伪造它。将选择背景的第一部分保留为原始颜色是不够的。
  • 还有更多事情要做。我试图覆盖drawRow,但它为整个行绘制了背景,尽管它只接收index.column()0。由于某种原因,默认行为不会在我处理的其他列上强制使用彩色背景由一个根本不绘制背景的委托​​(通常看起来只选择了第 0 列,视觉上)。我很想看到 drawRow 和委托绘制的完整 python 实现。这将解决很多问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-06-08
  • 1970-01-01
  • 2022-06-11
  • 2017-06-14
  • 2021-02-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多