单独设置 QComboBox 菜单项的样式 PyQt5
Styling the items of a QComboBox menu individually PyQt5
我试图单独设置 QComboBox 菜单项的样式。
在 Qt Style Sheets Examples 中,它通过 QAbstractItemView
设置菜单样式
QComboBox QAbstractItemView {
border: 2px solid darkgray;
selection-background-color: lightgray;
}
它提供了对菜单的一般控制,但除了对所选项目的轻微控制外,无法控制单个项目。另一个解决方案是使用 QAbstractItemView::item,但对我不起作用。
你似乎有一个 XY problem 因为你指出你的 objective 是 "paint the dropdown menu"(这是非常通用的)但是你要求一个可能的解决方案的错误(另一个问题)不一定能为您服务。
考虑到以上情况,我将解释错误的原因和可能的解决方案(显然做了很多假设)。
主要错误是此代码适用于 PyQt4,您可能正在使用 PyQt5,在 PyQt4 中,data() 方法 returns 必须转换为 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_())
我试图单独设置 QComboBox 菜单项的样式。 在 Qt Style Sheets Examples 中,它通过 QAbstractItemView
设置菜单样式QComboBox QAbstractItemView {
border: 2px solid darkgray;
selection-background-color: lightgray;
}
它提供了对菜单的一般控制,但除了对所选项目的轻微控制外,无法控制单个项目。另一个解决方案是使用 QAbstractItemView::item,但对我不起作用。
你似乎有一个 XY problem 因为你指出你的 objective 是 "paint the dropdown menu"(这是非常通用的)但是你要求一个可能的解决方案的错误(另一个问题)不一定能为您服务。
考虑到以上情况,我将解释错误的原因和可能的解决方案(显然做了很多假设)。
主要错误是此代码适用于 PyQt4,您可能正在使用 PyQt5,在 PyQt4 中,data() 方法 returns 必须转换为 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_())