单独设置 QComboBox 菜单项的样式 PyQt5

Posted

技术标签:

【中文标题】单独设置 QComboBox 菜单项的样式 PyQt5【英文标题】:Styling the items of a QComboBox menu individually PyQt5 【发布时间】:2020-08-02 13:56:04 【问题描述】:

我试图单独设置 QComboBox 菜单项的样式。 在Qt Style Sheets Examples 中,它通过 QAbstractItemView

设置菜单样式
QComboBox QAbstractItemView 
    border: 2px solid darkgray;
    selection-background-color: lightgray;

它提供了对菜单的一般控制,但对单个项目没有控制,除了对所选项目的轻微控制。另一种解决方案是使用对我不起作用的 QAbstractItemView::item

【问题讨论】:

【参考方案1】:

您似乎有一个XY problem,因为正如您指出的那样,您的目标是“绘制下拉菜单”(这是非常通用的),但您要求可能的解决方案(另一个问题)的错误不会一定要为你服务。

考虑到以上,我会解释错误的原因和可能的解决方案(显然做了很多假设)。

主要错误是这段代码是针对 PyQt4 的,您可能正在使用 PyQt5,在 PyQt4 中,data() 方法返回一个必须转换为 python 对象的 QVariant,因此您使用 isValid() 和 toPyObject() 但是在 pyqt5 中不再需要。另一个错误是 UserRole 值将为 None 因为您在创建项目时没有分配任何值(这可能是由于其他问题中的遗漏造成的)。

考虑到上述情况,一个可能的解决方案(兼容 PyQt4 和 PyQt5)是:

class LineStyleDelegate(QItemDelegate):
    def paint(self, painter, option, index):
        data = index.data(Qt.UserRole)
        if hasattr(data, "toPyObject"):
            data = data.toPyObject()
        if data is not None:
            painter.save()
            rect = option.rect
            rect.adjust(+5, 0, -5, 0)
            pen = QPen()
            pen.setColor(Qt.black)
            pen.setWidth(3)
            pen.setStyle(data)
            painter.setPen(pen)
            middle = (rect.bottom() + rect.top()) / 2
            painter.drawLine(rect.left(), middle, rect.right(), middle)
            painter.restore()
        else:
            QItemDelegate.paint(self, painter, option, index)
        self.searchEdit = QComboBox(sef.searchContent)
        for text, style in (
            ("Item 1", Qt.SolidLine),
            ("Item 2", Qt.DotLine),
            ("Item 3", Qt.DashDotDotLine),
        ):
            self.searchEdit.addItem(text, style)
        self.delegate = LineStyleDelegate(self.searchEdit)
        self.searchEdit.setItemDelegate(self.delegate)
        self.searchEdit.setMinimumWidth(500)
        self.searchEdit.setEditable(True)

更新:

通过修改问题,可以验证 OP 存在 XY 问题。要修改 QComboBox 的项目的绘制,必须使用委托:QItemDelegate 或 QStyledItemDelegate。我更喜欢使用第二种,因为它使用的是QStyle,即设计会尊重GUI的风格。要设置每个项目的颜色,请使用 QStyleOptionViewItem 的 backgroundBrush 属性,并且对于边框绘制,则必须重写 paint() 方法:

import random

from PyQt5 import QtCore, QtGui, QtWidgets


class CustomStyleDelegate(QtWidgets.QStyledItemDelegate):
    def initStyleOption(self, option, index):
        super(CustomStyleDelegate, self).initStyleOption(option, index)
        random_color = QtGui.QColor(*random.sample(range(255), 3))
        option.backgroundBrush = random_color

    def paint(self, painter, option, index):
        super(CustomStyleDelegate, self).paint(painter, option, index)
        margins = 2
        border_color = QtGui.QColor(*random.sample(range(255), 3))
        painter.save()
        pen = QtGui.QPen()
        pen.setColor(border_color)
        pen.setWidth(margins)
        painter.setPen(pen)
        r = QtCore.QRect(option.rect).adjusted(0, 0, -margins, -margins)
        painter.drawRect(r)
        painter.restore()


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = QtWidgets.QComboBox()
    w.addItems(["Item 1", "Item 2", "Item 3"])
    delegate = CustomStyleDelegate(w)
    w.setItemDelegate(delegate)
    w.show()
    sys.exit(app.exec_())

【讨论】:

@O.Shehab 如果您希望它是文本,那么您不需要使用委托(删除self.delegate = LineStyleDelegate(self.searchEdit)self.searchEdit.setItemDelegate(self.delegate))。正如我指出的那样,您的问题令人困惑,请更好地解释自己。请记住,SO 不是教程服务。 我想更好地控制组合框项目的样式,而我找到的唯一答案就是绘制它。 @O.Shehab Pointing 我想更好地控制组合框项目的样式非常通用,如果您的要求具体,我们可以为您提供帮助。在 Qt 中有很多方法可以设置元素的样式。 我知道如何在 PyQt 中设置元素的样式,但我花了两个小时或更长时间试图找到一种方法来通过样式设置 QAbstractItemView 来设置组合框项的样式,但它们都不起作用。 @O.Shehab 正如我已经指出的那样:如果您的要求不具体,那么我将无法为您提供帮助,再见。

以上是关于单独设置 QComboBox 菜单项的样式 PyQt5的主要内容,如果未能解决你的问题,请参考以下文章

子菜单不在WordPress下拉菜单中复制样式

如何设置qtableview中的qcombobox的显示样式

当鼠标通过 QSS 悬停在 QComboBox 上时,样式 QComboBox 的子控件向下箭头

Qt,如何更改 QComboBox 的一项的文本颜色? (C++)

QComboBox的PyQt右键菜单

asp.net menu控件菜单项的间距如何调?