Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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_())
    

  • Lifetime Qt Champion

    Hi
    For a plain QWidget subclass, you must do

     void 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.


  • Lifetime Qt Champion

    @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 why QWidegt (seems to) work directly, but anything directly sub-classed from QWidget 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 from QWidget you lose that route of code and hence have to re-provide your own. OTOH if you derive from any Qt class derived from QWidget, e.g. QLabel, that already has the necessary explicit paint code so you do not need to add same yourself in such a case.


Log in to reply