Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Stylesheet inheritance and "container" widgets
QtWS25 Last Chance

Stylesheet inheritance and "container" widgets

Scheduled Pinned Locked Moved Unsolved General and Desktop
8 Posts 2 Posters 2.8k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • J Offline
    J Offline
    JonB
    wrote on 29 Jan 2020, 09:24 last edited by JonB
    #1

    I am finding there is strange and quite undocumented behaviour on "container" widgets and stylesheets. I have noticed this as a result of my investigations into my https://forum.qt.io/topic/110974/qwidget-setstylesheet-breaks-cascade-inheritance, but it is not the same issue as that (I don't know if it might be related somehow), so I am creating a standalone thread for this.

    Briefly, stylesheets on individual widget elements in a hierarchy should "inherit"/"cascade" downward to descendants. But I am finding strange behaviour with a stylesheet set on "container" widgets (i.e. those Qt Designer groups as Containers).

    import sys
    from PySide2 import QtWidgets
    # from PyQt5 import QtWidgets
    
    def window():
       app = QtWidgets.QApplication(sys.argv)
    
       # mw: main window
       mw = QtWidgets.QMainWindow()
       mw.setGeometry(100,100,200,250)
       mw.setWindowTitle("PySide2")
    
       # sw: tab widget, set as main window's central widget
       tw = QtWidgets.QTabWidget(mw)
       mw.setCentralWidget(tw)
    
       # p1: page #1 of tab widget, it is a scroll area 
       p1 = QtWidgets.QScrollArea(tw)
       p1.setFixedHeight(100)
       tw.addTab(p1, "Page 1")
    
       # wg: widget on page, tall enough to cause scroll area scrollbars
       wg = QtWidgets.QWidget(p1)
       wg.setFixedHeight(200)
       p1.setWidget(wg)
    
       # main window sets color to red
       mw.setStyleSheet("* { background-color: red; }")
       # tab widget sets color to blue
       # affects the tab widget itself, but it has no effect on any page inside the tab widget :(
       # tw.setStyleSheet("* { background-color: blue; }")
    
       mw.show()
       sys.exit(app.exec_())
    	
    if __name__ == '__main__':
       window()
    

    This creates a simple hierarchy: QMainWindow > QTabWidget > QScrollArea > QWidget. When run the above code produces:

    1. Screenshot from 2020-01-29 09-17-43.png

    Good! The red is set on QMainWindow and inherits down to QTabWidget and on into its QScrollArea and content.

    Now let's uncomment the line which sets a stylesheet on the QTabWidget:

       tw.setStyleSheet("* { background-color: blue; }")
    
    1. Screenshot from 2020-01-29 09-21-06.png

    Now what's going on here? The QTabWidget itself is blue, but the QScrollArea remains red? It's as though the QTabWidget "partially stands outside" the inheritance hierarchy: it inherits from its parent, but its own setting does not cascade down to its children, they inherit from higher up the tree....? It's as though we have two separate hierarchies:

    QMainWindow > QTabWidget > [STOP]
    QMainWindow > QScrollArea > QWidget
    

    I have also tested the above with a QStackedWidget instead of QTabWidget "container", and behaviour is the same.

    How does this work? Where is there any mention when this applies to what widgets in the docs?

    1 Reply Last reply
    0
    • J Offline
      J Offline
      JonB
      wrote on 29 Jan 2020, 09:55 last edited by JonB
      #2

      A follow-up post, showing even odder behaviour.

      Continuing from above code. Let's make the two style lines as follows:

         mw.setStyleSheet("* { background-color: red; } QScrollBar { background-color: yellow; }")
      
         tw.setStyleSheet("* { background-color: blue; }  QScrollBar { background-color: green; }")
      
      1. Screenshot from 2020-01-29 09-48-51.png

      Again, this shows the scrollbar color is inherited from QMainWindow and ignored from QTabWidget, as before. Now let's comment out the QMainWindow's stylesheet totally:

         # mw.setStyleSheet("* { background-color: red; } QScrollBar { background-color: yellow; }")
      
         tw.setStyleSheet("* { background-color: blue; }  QScrollBar { background-color: green; }")
      
      1. Screenshot from 2020-01-29 09-51-03.png

      Hmm, now descendants are all blue & green, which comes from QTabWidget, which we said does not cascade to children....

      Sooo, what we are seeing now seems to be:

      • When all we do is set style on QTabWidget it does cascade down to children...
      • ...but if something higher up the hierarchy (QMainWindow here, but I've tried others) happens to have a stylesheet then inheritance is taken from there and QTabWidget is ignored.

      Wot??

      1 Reply Last reply
      0
      • J Offline
        J Offline
        JonB
        wrote on 29 Jan 2020, 10:16 last edited by JonB
        #3

        Finally, here's really scary behaviour:

           mw.setStyleSheet("QPushButton { border: none; }")
        
           tw.setStyleSheet("* { background-color: blue; }  QScrollBar { background-color: green; }")
        
        1. Screenshot from 2020-01-29 10-08-16.png

        I have put a stylesheet on QMainWindow but with a rule totally unrelated to the widgets I am showing. [I could have put anything non-empty, even mw.setStyleSheet(" ").] Nothing now inherits from QTabWidget.

        Now let's change to

        # or omit the following line completely
        mw.setStyleSheet("")
        
        1. Screenshot from 2020-01-29 10-09-43.png

        With no/empty stylesheet on QMainWindow, and only in this case, the background and QScrollBar do take from QTabWidget. [And this finally might be related to my problem in the other thread.]

        Triple-wot???

        P 1 Reply Last reply 29 Jan 2020, 10:56
        1
        • J JonB
          29 Jan 2020, 10:16

          Finally, here's really scary behaviour:

             mw.setStyleSheet("QPushButton { border: none; }")
          
             tw.setStyleSheet("* { background-color: blue; }  QScrollBar { background-color: green; }")
          
          1. Screenshot from 2020-01-29 10-08-16.png

          I have put a stylesheet on QMainWindow but with a rule totally unrelated to the widgets I am showing. [I could have put anything non-empty, even mw.setStyleSheet(" ").] Nothing now inherits from QTabWidget.

          Now let's change to

          # or omit the following line completely
          mw.setStyleSheet("")
          
          1. Screenshot from 2020-01-29 10-09-43.png

          With no/empty stylesheet on QMainWindow, and only in this case, the background and QScrollBar do take from QTabWidget. [And this finally might be related to my problem in the other thread.]

          Triple-wot???

          P Offline
          P Offline
          Pl45m4
          wrote on 29 Jan 2020, 10:56 last edited by Pl45m4
          #4

          @JonB

          I guess it has something to do with the fact, that setStylesheet("...") is a QWidget function and not from QTabWidget itself.
          So even setting a stylesheet background color on tw would start at QWidget-level (as well as setting stylesheet to mw). The * says ' all Widgets', so I guess the tw stylesheet gets ignored...
          Just a guess... Could be totally wrong :-)


          If debugging is the process of removing software bugs, then programming must be the process of putting them in.

          ~E. W. Dijkstra

          J 1 Reply Last reply 29 Jan 2020, 11:01
          0
          • P Pl45m4
            29 Jan 2020, 10:56

            @JonB

            I guess it has something to do with the fact, that setStylesheet("...") is a QWidget function and not from QTabWidget itself.
            So even setting a stylesheet background color on tw would start at QWidget-level (as well as setting stylesheet to mw). The * says ' all Widgets', so I guess the tw stylesheet gets ignored...
            Just a guess... Could be totally wrong :-)

            J Offline
            J Offline
            JonB
            wrote on 29 Jan 2020, 11:01 last edited by
            #5

            @Pl45m4
            QTabWidget inherits from QWidget, so I don't know what you mean about the setStylesheet("..."). Nor, I'm afraid, your other observations. The behaviour is not observed on non-container widgets. But thank you for responding.

            I would politely request someone look through the examples I have given (or better still try them!). Only by following through what I show will someone appreciate how odd/inconsistent the exact behaviour illustrated is....

            P 1 Reply Last reply 29 Jan 2020, 11:14
            0
            • J JonB
              29 Jan 2020, 11:01

              @Pl45m4
              QTabWidget inherits from QWidget, so I don't know what you mean about the setStylesheet("..."). Nor, I'm afraid, your other observations. The behaviour is not observed on non-container widgets. But thank you for responding.

              I would politely request someone look through the examples I have given (or better still try them!). Only by following through what I show will someone appreciate how odd/inconsistent the exact behaviour illustrated is....

              P Offline
              P Offline
              Pl45m4
              wrote on 29 Jan 2020, 11:14 last edited by Pl45m4
              #6

              @JonB

              Ok it IS weird

              Cascading

              • When conflicts arise, the widget's own style sheet is always preferred to any inherited style sheet, irrespective of the specificity of the conflicting rules. Likewise, the parent widget's style sheet is preferred to the grandparent's, etc.

              So normally it should behave like you expected, but it (strangely) doesn't

              @JonB said in Stylesheet inheritance and "container" widgets:

              QTabWidget inherits from QWidget, so I don't know what you mean about the setStylesheet("...")

              Yes and because of that, I thought, setting a stylesheet to tw is the same as setting the same style to mw, which isn't the case, because mw is parent of tw and

              the widget's own style sheet is always preferred

              (At least, should be preferred)

              What happens if you replace the * with the actual class or type selector? (Could be a missinterpretation issue of * while cascading / inheriting)


              If debugging is the process of removing software bugs, then programming must be the process of putting them in.

              ~E. W. Dijkstra

              J 1 Reply Last reply 29 Jan 2020, 13:04
              0
              • P Pl45m4
                29 Jan 2020, 11:14

                @JonB

                Ok it IS weird

                Cascading

                • When conflicts arise, the widget's own style sheet is always preferred to any inherited style sheet, irrespective of the specificity of the conflicting rules. Likewise, the parent widget's style sheet is preferred to the grandparent's, etc.

                So normally it should behave like you expected, but it (strangely) doesn't

                @JonB said in Stylesheet inheritance and "container" widgets:

                QTabWidget inherits from QWidget, so I don't know what you mean about the setStylesheet("...")

                Yes and because of that, I thought, setting a stylesheet to tw is the same as setting the same style to mw, which isn't the case, because mw is parent of tw and

                the widget's own style sheet is always preferred

                (At least, should be preferred)

                What happens if you replace the * with the actual class or type selector? (Could be a missinterpretation issue of * while cascading / inheriting)

                J Offline
                J Offline
                JonB
                wrote on 29 Jan 2020, 13:04 last edited by
                #7

                @Pl45m4 said in Stylesheet inheritance and "container" widgets:

                What happens if you replace the * with the actual class or type selector? (Could be a missinterpretation issue of * while cascading / inheriting)

                Makes no difference to the basic behaviours. Depending on which example you looking at, you could get rid of rules other than for QScrollBar and still see the weirdness.

                This also has nothing to do with at least the behaviour of #5/6, which shows in its case that the content of the setStyleSheet() (other than whether it is empty or not) is not relevant to the behaviour.

                1 Reply Last reply
                0
                • J Offline
                  J Offline
                  JonB
                  wrote on 7 Feb 2020, 11:07 last edited by
                  #8

                  I have raised https://bugreports.qt.io/browse/QTBUG-81958, as I'm not getting an answer here.

                  1 Reply Last reply
                  0

                  • Login

                  • Login or register to search.
                  • First post
                    Last post
                  0
                  • Categories
                  • Recent
                  • Tags
                  • Popular
                  • Users
                  • Groups
                  • Search
                  • Get Qt Extensions
                  • Unsolved