您的try 没有成功,原因如下:
QTreeView::item
Select 器仅指定项目,但树状视图使用水平shifts项目矩形的缩进级别:大多数样式仅在项目几何图形内绘制 Select 背景;
- 在几乎任何复杂的小部件中(参见sub-controls QSS documentation底部的注释),当自定义一个属性或子控件(包括one property of a subcontrol)时,必须设置所有其他属性:
QTreeView::branch
肯定属于该类别,这意味着设置分支背景将完全忽略任何默认行为,包括绘制箭头;
- 与
QTreeView::item
try 类似,重写委托的paint
将没有帮助,因为委托只能在项目的内容内绘制,而项目是水平平移的;
有些样式实际上用突出显示的 colored颜色 绘制整行,但这不是必需的,并且完全依赖于样式实现,这意味着我们不能依赖使用代理样式的部分样式表或公共QStyle函数(这也会停止使用样式表).
(almost)唯一可靠的解决方案是在项目之前完全绘制整行的背景,这必须从树视图中完成,这是通过重写QTreeView.drawRow()
:
- 102 Select 索引:
- 绘制自定义背景;
- 将
option.palette
的Highlight
角色强制为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()
的自定义委派子类应该知道这一切.