PyQt5 – 鼠标悬停时为组合框的行编辑部分设置背景色

  • Post category:Python

PyQt5 是 Python 编程语言和Qt框架的结合,Python开发人员通过Qt设计图形界面和编写交互应用程序,同时利用Python所拥有的便利性。

PyQt5的组合框(QComboBox)具有悬停事件(QEvent.HoverEnter和QEvent.HoverLeave),可以让我们在鼠标悬停组合框的行编辑部分时进行背景色的设置。

下面是详细的使用攻略:

步骤1:导入必要的包

from PyQt5.QtCore import Qt, QEvent
from PyQt5.QtGui import QColor, QPalette
from PyQt5.QtWidgets import QComboBox, QStyledItemDelegate, QApplication

步骤2:设定QStyledItemDelegate子类

我们需要定义一个QStyledItemDelegate的子类,用于防止QComboBox每个项目都受到影响。定义方法如下:


class ComboBoxDelegate(QStyledItemDelegate):
    def __init__(self, parent=None):
        super(ComboBoxDelegate, self).__init__(parent)

    def paint(self, painter, option, index):
        if option.state & QStyle.State_MouseOver:
            painter.fillRect(option.rect, QColor('#C2E2F2'))
        else:
            painter.fillRect(option.rect, QColor(Qt.white))

        self.drawDecoration(painter, option, option.rect, index)

        text = index.model().data(index, Qt.DisplayRole)
        self.drawDisplay(painter, option, option.rect, text)

        if option.state & QStyle.State_Selected:
            self.drawFocus(painter, option, option.rect)

在该问题中,我们主要关心鼠标悬停组合框时设置背景色的部分,请看painter.fillRect的操作。当鼠标停留在行编辑部分时,我们使用“#C2E2F2”色值来对其进行设置;否则,则使用白色进行设置。

步骤3:在主程序中实例化ComboBoxDelegate

为了能够使用ComboBoxDelegate设置QComboBox的背景颜色,我们需要在主程序中实例化ComboBoxDelegate。实例化过程如下:


if __name__ == '__main__':
    app = QApplication(sys.argv)
    combo = QComboBox()
    delegate = ComboBoxDelegate(combo)
    combo.setItemDelegate(delegate)
    combo.addItems(["item1", "item2", "item3", "item4"])
    combo.show()
    sys.exit(app.exec_())

这个程序中,我们实例化了一个QComboBox,并使用setItemDelegate方法来使用ComboBoxDelegate为QComboBox进行设置。程序运行后,我们可以看到每个项目在被鼠标经过时背景色都会根据ComboBoxDelegate中所设置的方式变换。

示例1

在实际应用中,我们需要通过改写ComboBoxDelegate对QComboBox的样式进行灵活的操作。

例如,我们需要让QComboBox中只选定一个项目后关闭:

class ComboBoxDelegate(QStyledItemDelegate):
    def __init__(self, parent=None):
        super(ComboBoxDelegate, self).__init__(parent)

    def paint(self, painter, option, index):
        if option.state & QStyle.State_MouseOver:
            painter.fillRect(option.rect, QColor('#C2E2F2'))
        else:
            painter.fillRect(option.rect, QColor(Qt.white))

        self.drawDecoration(painter, option, option.rect, index)

        text = index.model().data(index, Qt.DisplayRole)
        self.drawDisplay(painter, option, option.rect, text)

        if option.state & QStyle.State_Selected:
            self.drawFocus(painter, option, option.rect)

    def editorEvent(self, event, model, option, index):
        if event.type() == QEvent.MouseButtonPress and event.button() == Qt.LeftButton and \
                index.data(Qt.UserRole) != "0":
            model.setData(index, "1", Qt.UserRole)
            model.setData(index, QPalette().brush(QPalette.Background).color(), Qt.BackgroundRole)
            for row in range(model.rowCount(index)):
                if row == index.row():
                    continue
                otherIndex = index.sibling(row, index.column())
                model.setData(otherIndex, "0", Qt.UserRole)
        elif event.type() == QEvent.MouseButtonRelease and event.button() == Qt.LeftButton:
            value = index.data(Qt.UserRole)
            if value == "1":
                option.widget().hidePopup()
                return True
        return super().editorEvent(event, model, option, index)

在ComboBoxDelegate子类中,我们需要注意几点:

  • 为了关闭QComboBox列表,我们需要重写editorEvent方法,并在方法中添加option.widget().hidePopup()。
  • 我们需要定义新的UserRold,如这里定义的”0″和”1″,来让程式更好的理解所选取的项目。
  • 当用户单击一个项目时,我们需要同时设置其他项目的UserRold为”0″。

示例2

在实际应用中,我们需要将QComboBox中的每个项目更改为具有不同颜色的背景色,以增加页面的美观。

例如:


class ComboBoxDelegate(QStyledItemDelegate):
    def __init__(self, parent=None):
        super(ComboBoxDelegate, self).__init__(parent)

    def paint(self, painter, option, index):
        if option.state & QStyle.State_MouseOver:
            painter.fillRect(option.rect, QColor('#C2E2F2'))
        else:
            painter.fillRect(option.rect, QColor(Qt.white))

        self.drawDecoration(painter, option, option.rect, index)

        text = index.model().data(index, Qt.DisplayRole)
        self.drawDisplay(painter, option, option.rect, text)

        if index.row() % 2:
            painter.fillRect(option.rect, QColor("#445566"))

        if option.state & QStyle.State_Selected:
            self.drawFocus(painter, option, option.rect)

在ComboBoxDelegate子类中,我们特别注意到了这个重写的部分:

if index.row() % 2:
    painter.fillRect(option.rect, QColor("#445566"))

该代码段使得当检测到每个项目的行数均为偶数时,会将对应的背景色改为”#445566″。这用来替换了原来由于鼠标的悬停所产生的交互变化背景色的效果。

总之,以上就是PyQt5鼠标悬停时为组合框的行编辑部分设置背景色的完整使用攻略,同时配有两个示例来帮助我们更容易地理解组合框与鼠标悬停之间的交互机制。