Custom QWidget setStyleSheet not working - Python
-
Hello,
I'm trying to set the background color of a custom QWidget. I have tried with this minimum example:
class other(QWidget): def __init__(self, parent = None): super(other, self).__init__(parent) # self.setAutoFillBackground(False) if __name__ == '__main__': app = QApplication(sys.argv) main_widget = QWidget() main_layout = QVBoxLayout() main_widget.setLayout(main_layout) main_widget.setStyleSheet(".QWidget{background-color: blue}") child_widget1 = QWidget() child_widget1.setStyleSheet(".QWidget{background-color: green}") child_widget2 = QWidget() child_widget2.setStyleSheet(".QWidget{background-color: white}") other = other() other.setStyleSheet(".other{background-color: black}") main_widget.setMinimumSize(QSize(600, 600)) main_layout.addWidget(child_widget1) main_layout.addWidget(child_widget2) main_layout.addWidget(other) main_widget.show() sys.exit(app.exec_())
I can change the first two widget colors without problem. But the last one, which my own class just inheriting from QWidget doesn't change its color to black.
If I just change my "other" class to inherit from QLabel everything work as expected. Can someone bring some light into this behavior?
Working example with QLabel:
class other(QLabel): def __init__(self, parent = None): super(other, self).__init__(parent) # self.setAutoFillBackground(False) if __name__ == '__main__': app = QApplication(sys.argv) main_widget = QWidget() main_layout = QVBoxLayout() main_widget.setLayout(main_layout) main_widget.setStyleSheet(".QWidget{background-color: blue}") child_widget1 = QWidget() child_widget1.setStyleSheet(".QWidget{background-color: green}") child_widget2 = QWidget() child_widget2.setStyleSheet(".QWidget{background-color: white}") other = other() other.setStyleSheet(".other{background-color: black}") main_widget.setMinimumSize(QSize(600, 600)) main_layout.addWidget(child_widget1) main_layout.addWidget(child_widget2) main_layout.addWidget(other) main_widget.show() sys.exit(app.exec_())
-
Hi
For a plain QWidget subclass, you must dovoid CustomWidget::paintEvent(QPaintEvent *) { QStyleOption opt; opt.init(this); QPainter p(this); style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); }
def paintEvent(self, pe): o = QStyleOption() o.initFrom(self) p = QPainter(self) self.style().drawPrimitive(QStyle.PE_Widget, o, p, self)
to let it paint with style sheet effect. ( assuming you did overwrite paintEvent for your class)
-
@orensbruli
@mrjj is quite correct!https://stackoverflow.com/a/32889486 even gives you Python code for this :)
And if, like me, you wonder why it's needed given that
QWidget
itself does work and you're deriving from it, there's a comment on that page including [my italics]:I can only guess that by default Qt's style mechanism that draws the control (QStyle::drawControl) performs some default painting for QWidgets (as identified by meta data as result of Q_OBJECT in QWidget). As soon as you provide Q_OBJECT for your own widget derivative, the default behaviour does not hold anymore, and Qt's drawControl begins to rely on code within paintEvent to draw the control.
-
@JonB said in Custom QWidget setStyleSheet not working - Python:
d Qt's drawControl begins to rely on code within paintEvent to draw the control.
Thank you both @mrjj and @JonB! It works and @JonB as you guessed I was wondering why it's like that and after the explanation it still makes me fell like it's a really weird behavior. If it happens with QWidget, I think anyone would also expect it to happen with any other derived widget as QLabel or QButton, but with those widgets it works as the intuition says it should work.
-
@orensbruli
Hi
well default paintEvent for QWidget does nothing.
https://code.woboq.org/qt5/qtbase/src/widgets/kernel/qwidget.cpp.html
line 9810
But the others already uses QStyle to paint.
so jonBs guessing seems pretty straight on. -
@orensbruli said in Custom QWidget setStyleSheet not working - Python:
nyone would also expect it to happen with any other derived widget as
@mrjj Thank you. What I then don't understand is why the setStyleSheet to child_widget1 on my example works. It's a QWidget, so no paintEvent is implemented on this either, right? Why does it works in this case? Thank you again for your patience.
-
@orensbruli
Please re-read the link/comment I posted, and the bit I said I had italicized. That explains/guesses whyQWidegt
(seems to) work directly, but anything directly sub-classed fromQWidget
does not:(QStyle::drawControl) performs some default painting for QWidgets (as identified by meta data as result of Q_OBJECT in QWidget).
This is saying that there is (presumably) some code in Qt base which has a special case for drawing
QWidget
if and only if that is widget's exact type. It goes on to say that if you derive directly fromQWidget
you lose that route of code and hence have to re-provide your own. OTOH if you derive from any Qt class derived fromQWidget
, e.g.QLabel
, that already has the necessary explicit paint code so you do not need to add same yourself in such a case.