【问题标题】:Set background colour for a custom QWidget为自定义 QWidget 设置背景颜色
【发布时间】:2020-01-06 18:13:41
【问题描述】:

我正在尝试创建一个背景颜色可以更改的自定义 QWidget(来自 PyQt5)。但是,所有设置背景颜色的标准方法似乎都不适用于自定义 QWidget 类

到目前为止,我已经尝试通过 QSS 样式表和设置调色板来更改颜色。这适用于常规 QWidget,但由于某种原因不适用于自定义小部件。

我在 C++ 文档https://wiki.qt.io/How_to_Change_the_Background_Color_of_QWidget 中找到了需要 paintEvent() 函数的参考自定义 QWidget,并且确实在 Python 中找到了对它的引用。但是,由于 PyQt5 中似乎不存在 QStyleOption,所以实现链接的paintevent 失败。

下面显示了我创建的 QWidget 类的高级(它还包含一堆标签)和我用于 Widget 的 QSS(样式已在父小部件中设置但已尝试直接设置)

class AlarmWidget(QWidget):
    def __init__(self, alarm, parent=None):
        super(AlarmWidget, self).__init__(parent)
        self.setFixedHeight(200)
        self.setProperty("active", True)

        self.setAutoFillBackground(True)
        p = self.palette()
        p.setColor(self.backgroundRole(), PyQt5.QtCore.Qt.red)
        self.setPalette(p)
AlarmWidget {
  background-color: red
}

总的来说,无论我做什么,它都不允许我为自定义 QWidget 设置背景颜色,所以非常感谢帮助

【问题讨论】:

    标签: python python-3.x pyqt5 qwidget qtstylesheets


    【解决方案1】:

    最简单的解决方法是:

    class AlarmWidget(QWidget):
        def __init__(self, alarm, parent=None):
        ...
        self.setAttribute(QtCore.Qt.WA_StyledBackground, True)
        self.setStyleSheet('background-color: red')
    

    只要将样式表应用于自定义小部件或其祖先小部件之一,就会出现此问题。引用QWidget.setPalette 文档:

    警告:请勿将此功能与Qt Style Sheets 结合使用。 使用样式表时,可以自定义小部件的调色板 使用“颜色”、“背景颜色”、“选择颜色”, “选择背景颜色”和“替代背景颜色”。

    然而,这里没有提到的是,出于性能原因,自定义小部件默认禁用样式表支持。因此,要让您的示例正常工作,您必须 (1) 通过样式表设置背景颜色,以及 (2) 使用 WA_StyledBackground 小部件属性显式启用样式表支持。

    一个演示这一点的最小示例如下所示:

    import sys
    from PyQt5 import QtCore, QtWidgets
    
    class AlarmWidget(QtWidgets.QWidget):
        def __init__(self, alarm, parent=None):
            super(AlarmWidget, self).__init__(parent)
            self.setFixedHeight(200)
    #         self.setAutoFillBackground(True)
    #         p = self.palette()
    #         p.setColor(self.backgroundRole(), QtCore.Qt.red)
    #         self.setPalette(p)
            self.setAttribute(QtCore.Qt.WA_StyledBackground, True)
            self.setStyleSheet('background-color: red')
    
    class Window(QtWidgets.QWidget):
        def __init__(self):
            super(Window, self).__init__()
            self.setStyleSheet('background-color: green')
            self.widget = AlarmWidget('')
            layout = QtWidgets.QVBoxLayout(self)
            layout.addWidget(self.widget)
    
    if __name__ == '__main__':
    
        app = QtWidgets.QApplication(sys.argv)
        window = Window()
        window.setWindowTitle('BG Colour Test')
        window.setGeometry(600, 100, 300, 200)
        window.show()
        sys.exit(app.exec_())
    

    这应该显示一个窗口,其中包含一个带有绿色边框的红色矩形,如下所示:

    为了进一步测试,只在AlarmWidget 类中设置调色板,而不在Window 类中设置样式表。这应该显示一个没有绿色边框的红色矩形。最后,只在 both 类中设置样式表 - 但没有 setAttribute 行。这应该显示一个没有内部红色矩形的纯绿色矩形(即不再应用自定义小部件上的样式表)。

    【讨论】:

      【解决方案2】:

      所有方法都对我有用,但如果你想实现paintEvent,那么转换为 PyQt5 是:

      class AlarmWidget(QtWidgets.QWidget):
          # ...
      
          def paintEvent(self, event):
              opt = QtWidgets.QStyleOption()
              opt.initFrom(self)
              p = QtGui.QPainter(self)
              self.style().drawPrimitive(QtWidgets.QStyle.PE_Widget, opt, p, self)
      

      【讨论】:

      • 感谢您的回答。如果可以的话,我也会将此标记为正确的解决方案,但我认为另一个答案更完整。你从哪里知道如何做到这一点?我花了很长时间寻找如何编写这种paintevent
      • @rmasp98 仅从 Qt4 到 Qt5 的修改:1) 将 init() 更改为 initFrom(),以及 2) 将一些类从 QtGui 移动到 QtWidgets
      猜你喜欢
      • 2012-09-21
      • 2020-12-14
      • 2014-09-03
      • 1970-01-01
      • 2018-06-29
      • 2015-03-15
      • 2020-02-22
      • 1970-01-01
      • 2017-04-14
      相关资源
      最近更新 更多