Details
-
Bug
-
Resolution: Unresolved
-
P2: Important
-
None
-
5.12.2
-
None
Description
Tested by me under Qt 5.12.2 shipped with Ubuntu 19.04, but believed to apply to all versions/platforms.
I am finding there is strange and quite undocumented behaviour on "container" widgets and stylesheets. 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).
Start from
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:
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; }")
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?
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; }")
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; }")
Hmm, now descendants are all blue & green, which comes from QTabWidget, which we said does not cascade to children....
So, 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.
Finally, here's really scary behaviour:
mw.setStyleSheet("QPushButton { border: none; }")
tw.setStyleSheet("* { background-color: blue; } QScrollBar { background-color: green; }")
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("")
With no/empty stylesheet on QMainWindow, and only in this case, the background and QScrollBar do take from QTabWidget.
Final Note
My examples use colours because it's easiest to illustrate. As per https://doc.qt.io/Qt-5/stylesheet-syntax.html#inheritance I have tried
QCoreApplication.setAttribute(Qt.AA_UseStyleSheetPropagationInWidgetStyles, True)
This makes no difference to the results in pictures #1 to #5. Only in #6 does it make a difference, and even then it changes the background color but still cancels the scrollbar colour inheritance. I do not believe that is the issue.
Pictures #5 & #6 require special investigation. They illustrate some "special case" when having any kind of stylesheet string at all on an element (container?) interferes with/cancels all subsequent inheritance, when it should not. I am having other problems related to this behaviour in hierarchies too complex to break down so I could report here, which is the ultimate root of this issue.
This issue originally raised by me at https://forum.qt.io/topic/111137/stylesheet-inheritance-and-container-widgets, and also my related https://forum.qt.io/topic/110974/qwidget-setstylesheet-breaks-cascade-inheritance where I am attempting to find the underlying cause of pictures #5 & #6 which is interfering with a real-life complex hierarchy.