3

Consider the following example code:

from PyQt5.QtWidgets import (QApplication, QHBoxLayout, QLabel, QWidget,
                             QMainWindow, QVBoxLayout, QTextEdit)

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        cwidget = QWidget(self)
        cwidget.setStyleSheet("QWidget { background-color: red; }")
        self.setCentralWidget(cwidget)
        self.resize(100, 100)

        vbox = QVBoxLayout(cwidget)
        vbox.addWidget(QTextEdit(self))
        vbox.addWidget(BlackBar(self))

class BlackBar(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setStyleSheet("* { background-color: black; color: white; }")
        hbox = QHBoxLayout(self)
        hbox.setSpacing(5)
        hbox.addWidget(QLabel(text="eggs"))
        hbox.addWidget(QLabel(text="bacon"))

if __name__ == '__main__':
    app = QApplication([])
    main = MainWindow()
    main.show()
    app.exec_()

It has:

  • A QMainWindow, QWidget as central widget (red), QVBoxLayout as a child of the cental widget. Inside there:
    • A QTextEdit (just as a filler)
    • A QWidget (black), which contains a QHBoxLayout. Inside that:
      • Two QLabels

This looks like this:

Qt HBoxLayout

I'd expect the spaces between the labels to be black, because the QHBoxLayout is a child of BlackBar, but it seems BlackBar is just "invisible" in between and the central widget "shines through". Why is this?

The Compiler
  • 11,126
  • 4
  • 40
  • 54

2 Answers2

3

The bugreport has now been answered with a solution that's easier than @ekhumoro's answer and works:

I don't think this is valid. The paint code your are looking for is not drawn in the paintEvent. Look for QWidgetPrivate::paintBackground instead. For performance reasons widgets will ignore style sheets by default, but you can set the WA_StyledBackground attribute on the widget and it should respect style sheet backgrounds.

And indeed, doing this before setting the stylesheet does the trick:

self.setAttribute(Qt.WA_StyledBackground)
The Compiler
  • 11,126
  • 4
  • 40
  • 54
2

Although the Style Sheet Syntax does not mention it, it seems that the QWidget class is treated differently when it comes to stylesheets.

Other widgets will work fine with your example code. For example, if QWidget is replaced everywhere with QFrame, then everything works as expected.

To get stylesheet support for QWidget subclasses, you need to reimplement the paintEvent and enable it explicitly:

class BlackBar(QWidget):
...
    def paintEvent(self, event):
        option = QStyleOption()
        option.initFrom(self)
        painter = QPainter(self)
        self.style().drawPrimitive(
            QStyle.PE_Widget, option, painter, self)
ekhumoro
  • 115,249
  • 20
  • 229
  • 336
  • Interesting - I just looked at the Qt source, and [QWidget](https://qt.gitorious.org/qt/qt/source/763f4e54a818f31b4e89c99ec10924b2738f5de6:src/gui/kernel/qwidget.cpp) doesn't implement paintEvent at all. Am I missing something, or should I submit a Qt bug, so this is either changed, or the documentation is clarified? – The Compiler Feb 12 '14 at 08:48
  • @TheCompiler. It does seem strange, and I must admit that I haven't got a definitive answer to this. My understanding is that this only affects _subclasses_ of QWidget, but I cannot remember where I got this from. – ekhumoro Feb 12 '14 at 20:10
  • I now submitted this as [QTBUG-36884](https://bugreports.qt-project.org/browse/QTBUG-36884). Let's see what they say. – The Compiler Feb 17 '14 at 07:40
  • The bug has now been answered to with an easier solution. I answered my own question now. Thanks anyways! – The Compiler Feb 18 '14 at 16:04