我正在Centos7.6上做一个PySide2 GUI项目.

我try 在选中某行时更改该行的 colored颜色 :

 QTreeView::item:selected {
        background-color: rgba(48, 140, 198, 128);
    }

以下是我得到的信息:

selected row

项 Select 器不会影响整行.

在包括GTP在内的互联网上搜索后,我添加了如下分支 Select 器:

QTreeView::branch:selected {
        background-color: rgba(48, 140, 198, 128);
    }

不幸的是,它仍然没有像我预期的那样工作:

branch selector

分支 Select 器没有使前面的区域透明,相反,它使展开/折叠标记消失.

然后我try 在Delegate中覆盖Paint方法:

if option.state & QStyle.State_Selected:
            painter.fillRect(option.rect, QColor(48, 140, 198, 128))

但仍然是这样:

overwrite paint method

我想要的是当它被选中时更改整行,但不知何故我无法使其在分支区域上工作.现在我真的很困惑,有人能帮帮我吗?

推荐答案

您的try 没有成功,原因如下:

  • QTreeView::item Select 器仅指定项目,但树状视图使用水平shifts项目矩形的缩进级别:大多数样式仅在项目几何图形内绘制 Select 背景;
  • 在几乎任何复杂的小部件中(参见sub-controls QSS documentation底部的注释),当自定义一个属性或子控件(包括one property of a subcontrol)时,必须设置所有其他属性:QTreeView::branch肯定属于该类别,这意味着设置分支背景将完全忽略任何默认行为,包括绘制箭头;
  • QTreeView::itemtry 类似,重写委托的paint将没有帮助,因为委托只能在项目的内容内绘制,而项目是水平平移的;

有些样式实际上用突出显示的 colored颜色 绘制整行,但这不是必需的,并且完全依赖于样式实现,这意味着我们不能依赖使用代理样式的部分样式表或公共QStyle函数(这也会停止使用样式表).

(almost)唯一可靠的解决方案是在项目之前完全绘制整行的背景,这必须从树视图中完成,这是通过重写QTreeView.drawRow():

  • 102 Select 索引:
    • 绘制自定义背景;
    • option.paletteHighlight角色强制为transparent画笔,这样即使选中该项目,代理也不会绘制任何内容;
  • else:
    • restore默认调色板 colored颜色 ,以便它可以正确地用于其他含义;
  • 最后,使用super().drawRow(...)调用默认实现,如果需要的话,它最终会使用上面的画笔绘制项目的背景;

最后一段非常重要,因为在Item视图的某些函数中使用的QStyleOptionViewItem通常只创建一次,然后在迭代访问Items的各种for个循环中重用;这样做是为了优化目的,因此在option个成员中实际上只修改了应该更改的方面,但也有一个缺点,即对视图/委托不知道的选项所做的任何更改也将无法恢复.

在循环访问项时,调色板通常不会修改,因此如果在此期间更改它,以下任何项都可能继承它,即使它不应该:例如,一些QStyles(可能包括WindowsXP/WindowsVista)使用Highlight角色 colored颜色 来决定如何绘制悬停项的背景并显示特定调色板 colored颜色 角色的阴影,如果没有明确设置,该 colored颜色 对于决定文本的适当对比色也可能很重要.

在下面的例子中,我使用QTreeWidget来提供一个简单的MRE,但drawRow()实现在QTreeView中也是相同的.

class TreeTest(QTreeWidget):
    # default "static" class members, so we don't need to continuously and 
    # unnecessarily create brush objects every time they are required
    SelectBrush = QBrush(QColor(48, 140, 198, 128))
    NoBrush = QBrush(Qt.transparent, style=Qt.NoBrush)

    def __init__(self):
        super().__init__()
        top = QTreeWidgetItem(self, ['top'])
        QTreeWidgetItem(top, ['whatever'])
        QTreeWidgetItem(top, ['wherever'])
        QTreeWidgetItem(top, ['whenever'])
        self.expandAll()

    def drawRow(self, qp, opt, index):
        if self.selectionModel().isSelected(index):
            qp.fillRect(opt.rect, self.SelectBrush)
            opt.palette.setBrush(QPalette.Highlight, self.NoBrush)
        else:
            # IMPORTANT! The default highlight palette must be restored!
            opt.palette.setBrush(
                QPalette.Highlight, self.palette().highlight())
        super().drawRow(qp, opt, index)


app = QApplication([])
test = TreeTest()
test.show()
app.exec()

注意,NoBrush显式地将 colored颜色 设置为Qt.transparent,而不是更简单的QBrush():虽然没有参数的QBrush()具有Qt.BrushStyle.NoBrush样式(这意味着它不应该被绘制),但一些样式仍然使用它的color()作为引用,并且默认情况下该 colored颜色 是valid QColor:全不透明黑色.将其设置为透明可确保样式的任何try 将该 colored颜色 用于任何目的都不会导致任何绘制(至少在理论上,假设绘制不会忽略Alpha通道).

如果您想要使用样式表自定义所选内容的 colored颜色 ,一种可能的变化是设置树视图的selection-background-color属性.

不过,请注意,使用样式表always会使依赖于样式函数的定制小部件的事情变得复杂.任何使用QTreeView::item:<whatever>的try 都可能会使这一切化为泡影.

class Tree(QTreeWidget):
    NoBrush = QBrush(Qt.transparent, style=Qt.NoBrush)

    def __init__(self):
        ...
        self.setStyleSheet('''
            QTreeView { 
                selection-background-color: rgba(48, 140, 198, 128); 
            }
        ''')

    def drawRow(self, qp, opt, index):
        brush = self.palette().highlight()
        if self.selectionModel().isSelected(index):
            qp.fillRect(opt.rect, brush)
            brush = self.NoBrush
        opt.palette.setBrush(QPalette.Highlight, brush)
        super().drawRow(qp, opt, index)

上面提到的问题的一种可能的解决方法是使用自动取消设置选项的State_Selected标志的自定义委托,但请注意,这可能会意外中断其他事情.

class Delegate(QStyledItemDelegate):
    def initStyleOption(self, opt, index):
        super().initStyleOption(opt, index)
        opt.state &= ~QStyle.State_Selected


class Tree(QTreeWidget):
    ...
    def __init__(self):
        ...
        self.setItemDelegate(Delegate(self))
    ...

另一个需要记住的重要方面是,用户可以使用替代配色方案(例如,用于深色模式),这可能会使项目文本在某些条件下几乎不可见.

作为预防措施,您可能还应该为Text角色设置适当的对比度前景画笔,记住在未 Select 索引时将其重置为默认设置:

    def drawRow(self, qp, opt, index):
        textColor = self.palette().text()
        ...
        if self.selectionModel().isSelected(index):
            textColor = <QBrush color for text with appropriate contrast>
            ...
        opt.palette.setBrush(QPalette.Text, textColor)
        ...

然而,如上所述,设置QTreeView::item { color: ...; }将完全忽略所有这些,因为风格总是优先于此类问题.自定义项的默认文本 colored颜色 的唯一替代方法是为通用QTreeView Select 器设置text属性,类似于上面selection-background-color所做的操作.

最后,正如所说的,这并不是paint()%可靠的.最重要的是,一些样式可能会完全忽略/ destruct 上面所做的任何try ,而自己重写paint()的自定义委派子类应该知道这一切.

Python-3.x相关问答推荐

Pandas 中每行的最大值范围

无法导入名称';核心';来自部分初始化的模块';tensorflow_datasets';(很可能是由于循环导入)

如何转置和 Pandas DataFrame 并命名新列?

有没有一种方法可以通过输入从 0 到 255 的 R、G 和 B 值来生成 RGB colored颜色 ,而无需使用 python 中的 matplotlib 模块?

Pandas 窗口聚合两个排序表

使用gekko python的混合整数非线性规划

为什么 mypy 不适用于 sqlalchemy?

将元组列表转换为以整个元组为键的字典列表

Await Future 来自 Executor:Future 不能在await表达式中使用

使用 distutils 分发预编译的 python 扩展模块

为 python3 安装 opencv

如何从另一个目录导入 python 包?

为什么我在 Python 中收到错误消息无法导入名称 NoneType?

python 3.4版不支持'ur'前缀

如何通过命令行将数组传递给python

如何在 Python3 中添加带有标志的命令行参数?

如何在继承的数据类中创建可选字段?

使用完整路径激活 conda 环境

Python 3.4 多处理队列比 Pipe 快,出乎意料

如何使用异步 for 循环遍历列表?