Styling¶
QtPie provides CSS-like class helpers and color scheme utilities to make styling your Qt applications cleaner and more maintainable.
CSS Classes¶
Qt doesn't have native CSS classes, but QtPie uses dynamic properties to achieve similar functionality. This lets you write QSS (Qt Style Sheets) that feel more like web CSS.
Setting Classes on Widgets¶
Use the classes parameter on @widget to assign CSS classes:
from qtpie import widget
from qtpy.QtWidgets import QWidget
@widget(classes=["card", "shadow"])
class MyWidget(QWidget):
pass
This sets a class property on the widget containing ["card", "shadow"].
Manipulating Classes at Runtime¶
QtPie provides helpers to add, remove, and toggle classes dynamically:
from qtpie.styles import add_class, remove_class, toggle_class, has_class
# Add a class
add_class(widget, "active")
# Remove a class
remove_class(widget, "active")
# Toggle a class (add if not present, remove if present)
toggle_class(widget, "highlighted")
# Check if widget has a class
if has_class(widget, "error"):
print("Widget has error styling")
Additional Helpers¶
from qtpie.styles import (
add_classes, # Add multiple classes at once
get_classes, # Get list of all classes
set_classes, # Replace all classes
replace_class, # Swap one class for another
has_any_class, # Check if widget has any of the given classes
)
# Add multiple classes
add_classes(widget, ["primary", "large"])
# Replace a class
replace_class(widget, "primary", "secondary")
# Check multiple classes
if has_any_class(widget, ["error", "warning"]):
print("Widget needs attention")
Using Classes in QSS¶
In your Qt Style Sheets, match classes using attribute selectors with the ~= operator:
/* Match any QPushButton with the "primary" class */
QPushButton[class~="primary"] {
background-color: #007bff;
color: white;
border-radius: 4px;
}
/* Match labels with the "error" class */
QLabel[class~="error"] {
color: red;
font-weight: bold;
}
/* Combine with other selectors */
QPushButton[class~="primary"]:hover {
background-color: #0056b3;
}
The ~= operator matches if the class list contains the given value.
Object Name Selectors¶
Qt Style Sheets support ID selectors using #objectName syntax, just like CSS. QtPie automatically sets object names on your widgets, making this styling approach easy to use.
How QtPie Sets Object Names¶
QtPie automatically assigns objectName to widgets:
- Widget classes get their name from the class name (with "Widget" suffix stripped):
@widget
class CounterWidget(QWidget): # objectName = "Counter"
pass
@widget
class Editor(QWidget): # objectName = "Editor"
pass
@widget(name="CustomName")
class MyWidget(QWidget): # objectName = "CustomName"
pass
- Child widgets get their name from the field name:
@widget
class MyWidget(QWidget):
label: QLabel = make(QLabel, "Hello") # objectName = "label"
submit_btn: QPushButton = make(QPushButton, "Submit") # objectName = "submit_btn"
- Override with selector syntax - use CSS selector as first arg to
make():
@widget
class MyWidget(QWidget):
# Set custom objectName
label: QLabel = make("#title", QLabel, "Hello") # objectName = "title"
# Set classes only (objectName defaults to field name)
button: QPushButton = make(".primary", QPushButton, "Click") # objectName = "button", class = ["primary"]
# Set both objectName and classes
submit: QPushButton = make("#submit-btn.primary.large", QPushButton, "Submit")
The selector syntax mirrors CSS:
- #name sets the objectName
- .class adds a class
- #name.class1.class2 sets both
Using #objectName in QSS¶
Target widgets by their object name using the # selector:
/* Style the Counter widget */
#Counter {
background-color: #f0f0f0;
border: 1px solid #ccc;
padding: 10px;
}
/* Style a child widget by field name */
#label {
font-size: 18px;
color: #333;
}
#submit_btn {
background-color: #4CAF50;
color: white;
}
Combining with Type Selectors¶
For more specific targeting, combine type and ID selectors:
/* Only QLabel widgets named "label" */
QLabel#label {
font-weight: bold;
}
/* Only QPushButton widgets named "submit_btn" */
QPushButton#submit_btn {
border-radius: 4px;
}
Example: Styling by Object Name¶
from qtpie import entrypoint, widget, make
from qtpy.QtWidgets import QWidget, QLabel, QPushButton
@entrypoint(stylesheet="styles.qss")
@widget
class Counter(QWidget): # objectName = "Counter"
label: QLabel = make(QLabel, "Count: 0") # objectName = "label"
button: QPushButton = make(QPushButton, "+1") # objectName = "button"
styles.qss:
#Counter {
background-color: #ffffff;
padding: 20px;
}
#label {
font-size: 24px;
color: #333;
}
#button {
background-color: #007bff;
color: white;
padding: 8px 16px;
border: none;
border-radius: 4px;
}
#button:hover {
background-color: #0056b3;
}
ID vs Class Selectors¶
| Selector | Syntax | Use Case |
|---|---|---|
ID (#) |
#objectName |
Target a specific widget instance |
Class ([class~=]) |
[class~="primary"] |
Target widgets sharing a style category |
Use ID selectors when you want to style a specific widget. Use class selectors when multiple widgets should share the same style.
Color Schemes¶
QtPie provides simple helpers for dark and light mode:
from qtpie.styles import enable_dark_mode, enable_light_mode, set_color_scheme, ColorScheme
# Enable dark mode
enable_dark_mode()
# Enable light mode
enable_light_mode()
# Or use the enum directly
set_color_scheme(ColorScheme.Dark)
How It Works¶
The color scheme functions work in two ways:
- Before app creation: Sets environment variables that Qt will use when the app starts
- After app creation: Uses Qt 6.8+ runtime API to change the scheme immediately
This means you can call these functions either before or after creating your QApplication:
from qtpie import entrypoint, widget
from qtpie.styles import enable_dark_mode
from qtpy.QtWidgets import QWidget
# Option 1: Enable before app runs
enable_dark_mode()
@entrypoint
@widget
class MyApp(QWidget):
pass
# Option 2: Enable after app exists
@entrypoint
@widget
class MyApp(QWidget):
def setup(self) -> None:
enable_dark_mode() # Works here too
SCSS Support¶
QtPie has built-in support for SCSS compilation and hot reload during development. This lets you write stylesheets in SCSS and have them automatically compiled to QSS.
Quick Options¶
For app-wide styles, use @entrypoint with stylesheet options:
from qtpie import entrypoint, widget
from qtpy.QtWidgets import QWidget
@entrypoint(stylesheet="styles.scss", watch_stylesheet=True)
@widget
class MyApp(QWidget):
pass
For component-scoped styles, use the @stylesheet decorator:
from qtpie import stylesheet, widget
from qtpy.QtWidgets import QWidget
@stylesheet("card.scss", watch=True)
@widget
class Card(QWidget):
pass
For details on SCSS imports, file watching, and manual control, see the SCSS Hot Reload guide.
Example: Themed Button Widget¶
Here's a complete example combining classes, runtime manipulation, and QSS:
from qtpie import widget, make
from qtpie.styles import toggle_class, enable_dark_mode
from qtpy.QtWidgets import QWidget, QPushButton
@widget(classes=["themed"])
class ThemedButton(QWidget):
button: QPushButton = make(
QPushButton,
"Toggle Primary",
clicked="toggle_primary"
)
def setup(self) -> None:
# Apply a stylesheet using classes
self.setStyleSheet("""
QPushButton[class~="primary"] {
background-color: #007bff;
color: white;
padding: 8px 16px;
border-radius: 4px;
}
QPushButton[class~="primary"]:hover {
background-color: #0056b3;
}
QPushButton {
background-color: #e0e0e0;
padding: 8px 16px;
border-radius: 4px;
}
""")
def toggle_primary(self) -> None:
toggle_class(self.button, "primary")
See Also¶
- Windows & Menus - Window styling
- SCSS Hot Reload - Advanced styling with SCSS
- @stylesheet Decorator - Component-scoped styles
- Class Helpers Reference - Complete API
- Color Schemes Reference - Complete API