Stylesheet not applied correctly
-
Hello,
I have found out smth strange about how stylesheet is applied. I have prepared a minimal example, where I have a Drawer widget inside my main window.
If I have the Drawer as a separate class, the style to it is not applied correctly. Here is a minimal example, where the Drawer should be red, but it is not:
################################################################
import sys
from PySide6.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QPushButtonSample stylesheet
stylesheet = """
QWidget#Drawer {
background-color: red; /* Red background for the drawer */
}
"""class Drawer(QWidget):
def init(self):
super().init()
self.setObjectName('Drawer') # Set the object name for the drawer
self.setStyleSheet(stylesheet) # Apply the stylesheet to the drawer# Create a vertical layout for the drawer layout = QVBoxLayout(self) # Add a button to the drawer button = QPushButton("Drawer Button") layout.addWidget(button)
class MyWindow(QMainWindow):
def init(self):
super().init()
self.init_ui()def init_ui(self): self.setWindowTitle("Minimal PySide6 Drawer Example") # Create a central widget central_widget = QWidget() self.setCentralWidget(central_widget) # Create a vertical layout for the central widget layout = QVBoxLayout(central_widget) # Create the drawer widget and add it to the layout drawer_widget = Drawer() layout.addWidget(drawer_widget)
def main():
if not QApplication.instance():
app = QApplication(sys.argv)
else:
app = QApplication.instance()# Apply the stylesheet app.setStyleSheet(stylesheet) window = MyWindow() window.show() sys.exit(app.exec())
main()
#################################################################Can anyone explain why the drawer is not set to red?
Thank you.
-
Thx for the reply.
Neither #Drawer, nor Drawer work.
Here is again the code:
import sys from PySide6.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QPushButton # Sample stylesheet stylesheet = """ QWidget#Drawer { background-color: red; /* Red background for the drawer */ } """ class Drawer(QWidget): def __init__(self): super().__init__() self.setObjectName('Drawer') # Set the object name for the drawer self.setStyleSheet(stylesheet) # Apply the stylesheet to the drawer # Create a vertical layout for the drawer layout = QVBoxLayout(self) # Add a button to the drawer button = QPushButton("Drawer Button") layout.addWidget(button) class MyWindow(QMainWindow): def __init__(self): super().__init__() self.init_ui() def init_ui(self): self.setWindowTitle("Minimal PySide6 Drawer Example") # Create a central widget central_widget = QWidget() self.setCentralWidget(central_widget) # Create a vertical layout for the central widget layout = QVBoxLayout(central_widget) # Create the drawer widget and add it to the layout drawer_widget = Drawer() layout.addWidget(drawer_widget) def main(): if not QApplication.instance(): app = QApplication(sys.argv) else: app = QApplication.instance() # Apply the stylesheet app.setStyleSheet(stylesheet) window = MyWindow() window.show() sys.exit(app.exec()) main()
-
You are right. When I do not have it as a separate class, but rather create it inside the main window, then it works perfectly. However, this is not the solution, because I have a much more complex app and I cannot have everything inside the main function.
This is why I made this very minimal example so that the other can reproduce it and maybe someone can figure out what is going on there.
-
@Gazi
Just to let you know, I am presently playing with your code! I have Qt 5.15, not Qt 6. behaviour seems to be same (as expected).Start by noticing that the following CSS selector does work for your pushbutton:
stylesheet = """ QWidget#Drawer QPushButton { background-color: red; /* Red background for the drawer */ } """
Once you specify a selector which names a class/instance (
QWidget#Drawer
) the rule applies directly to that class/instance (i.e. theDrawer
) but does not cascade to its children (QPushButton
). This is the root of your issue. -
@Gazi
I believe your issue may be because you are trying to inherit widget's color. I refer you to https://doc.qt.io/qtforpython-6/overviews/stylesheet-syntax.html#inheritanceIn classic CSS, when font and color of an item is not explicitly set, it gets automatically inherited from the parent. By default, when using Qt Style Sheets, a widget does not automatically inherit its font and color setting from its parent widget.
Thus for your case I find the following (per the example there) does work:
stylesheet = """ QWidget#Drawer, QWidget#Drawer * { background-color: red; /* Red background for the drawer */ } """
Alternatively you can change to adding the
QCoreApplication.setAttribute(Qt.AA_UseStyleSheetPropagationInWidgetStyles, True)
statement to your program shown in that topic. (Note: I cannot test PySide6 but that statement may need adjusting I believe for PySide6, they moved all enumerated type values into their own classes, like https://doc.qt.io/qtforpython-6/PySide6/QtCore/Qt.html#PySide6.QtCore.PySide6.QtCore.Qt.ApplicationAttribute. I think you will need something which referencesQt.ApplicationAttribute.AA_UseStyleSheetPropagationInWidgetStyles
.) This would allow justQWidget#Drawer
alone to work as the selector. But it would change the behaviour of all widgets' color inheritance.Otherwise for your type case you just need to add the
*
all-children-selector to your rules explicitly.The absolute truth? I find Qt's CSS stuff either confusing, inconsistent or hard to get to grips with. I found HTML's CSS easier to work with. I just play with Qt CSS rules till I get what works....
-
-
@SGaist I wanted to have a centralized stylesheet. However, it would be helpful for me if you could point out how to apply it per widget.
@JonB Thank you for your response. I tried it out and indeed when I use your code, it will make the drawer button red. However, what surprises me is that the drawer itself still does not get red. So, I added 2 buttons to the drawer to explain better. Only the buttons are red, not the drawer itself, as shown in the pic below:
file:///home/gazi/Pictures/Screenshots/Screenshot%20from%202023-09-25%2011-36-32.png
Here is the code:
import sys from PySide6.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QPushButton # Sample stylesheet stylesheet = """ QWidget#Drawer, QWidget#Drawer * { background-color: red; /* Red background for the drawer */ } """ class Drawer(QWidget): def __init__(self): super().__init__() self.setObjectName('Drawer') # Set the object name for the drawer # Create a vertical layout for the drawer layout = QVBoxLayout(self) # Add a button to the drawer button1 = QPushButton("Drawer Button 1") button2 = QPushButton("Drawer Button 2") layout.addWidget(button1) layout.addStretch() layout.addWidget(button2) class MyWindow(QMainWindow): def __init__(self): super().__init__() self.init_ui() def init_ui(self): self.setWindowTitle("Minimal PySide6 Drawer Example") # Create a central widget central_widget = QWidget() self.setCentralWidget(central_widget) # Create a vertical layout for the central widget layout = QVBoxLayout(central_widget) # Create the drawer widget and add it to the layout drawer_widget = Drawer() layout.addWidget(drawer_widget) def main(): if not QApplication.instance(): app = QApplication(sys.argv) else: app = QApplication.instance() # Apply the stylesheet app.setStyleSheet(stylesheet) window = MyWindow() window.show() sys.exit(app.exec()) main()
Shouldn't the entire Drawer widget be red?
Thanks a lot for the support.
-
@Gazi
The drawerQWidget
itself is not red because of https://doc.qt.io/qtforpython-6/overviews/stylesheet-reference.html#list-of-stylable-widgets,QWidget
item:Supports only the background , background-clip and background-origin properties.
If you subclass fromQWidget
, you need to provide apaintEvent
for your customQWidget
as below:If you want that, in your
Drawer
class you need (tested under my PySide2/Qt5):from PySide2.QtWidgets import ..., QStyle, QStyleOption from PySide2.QtGui import QPainter class Drawer(QWidget): def paintEvent(self, arg__0): opt = QStyleOption() opt.initFrom(self) p = QPainter(self) self.style().drawPrimitive(QStyle.PE_Widget, opt, p, self)
-
@JonB Thx for pointing it out. Still i have a lot of trouble to understand why they made it so complicated. I don't know if there are many people who find it complicated, but i guess it would be much more convenient to have some styling capabilities as one has in react-native.
-
@Gazi depending on the result you are after, this article from KDAB about QStyle VS stylesheet might be of interest.