15. Qt Style Sheets - QSS

Qt Style Sheets is a feature that lets you customize the appearance of widgets using the familiar Cascading Style Sheets (CSS) syntax adapted to Qt Widgets. QSS can be set on the whole application using QApplication.setStyleSheet() or on a specific widget using QWidget.setStyleSheet(). Qt derives the effective style sheet from all the style sheets set at different levels. This mechanism is called cascading. Behind the scenes, Qt instantiates an internal QStyle subclass called QStyleSheetStyle, which wraps the native application style and applies the QSS rules.

A style sheet consists of a sequence of style rules. A rule has a selector that specifies which widgets are affected by the rule, and a declaration that specifies which properties should be set on the selected widget(s):

 1 Selector1 {
 2     property-name1: value;
 3     property-name2: value;
 4     . . .
 5 }
 6 
 7 Selector2 {
 8     property-name1: value;
 9     property-name2: value;
10     . . .
11 }
12 
13 . . .
14 
15 SelectorN {
16     property-name1: value;
17     property-name2: value;
18     . . .
19 }

15.1 Selector Types

Qt Style Sheets supports these selector types:

Selector Example Explanation
Universal Selector * Matches all widgets.
Type Selector QPushButton Matches all instances of QPushButton and of its subclasses (QCommandLinkButton).
Property Selector QPushButton[property="value"] Matches instances of QPushButton where property has the specified value.
Class Selector .QPushButton Matches instances of QPushButton, but not of its subclasses.
ID Selector QPushButton#okButton Matches all QPushButton instances whose object name is okButton.
Descendant Selector QDialog QPushButton Matches all instances of QPushButton that are descendants (children, grandchildren, etc.) of a QDialog.
Child Selector QDialog > QPushButton Matches all instances of QPushButton that are direct children of a QDialog.

This example illustrates the use of the different selector types.

 1 import sys
 2 from PySide6.QtWidgets import (QApplication, QGroupBox,
 3     QWidget, QPushButton, QVBoxLayout, QLineEdit, QLabel,
 4     QFrame, QComboBox, QStyle)
 5 
 6 
 7 STYLES = {
 8     'No QSS' : '',
 9     'Universal selector' : '* { background: orange; }',
10     'Type selector' : 'QPushButton { background: orange; }',
11     'Property selector':
12         'QPushButton[orange="true"] { background: orange; }',
13     'Class selector' : '.QPushButton { background: orange; }',
14     'ID selector' : '#headingLabel { background: orange; }',
15     'Descendant selector' : 'QGroupBox QLabel { background: orange; }',
16     'Child selector' : 'QGroupBox > QPushButton { background: orange; }'
17     }
18 
19 
20 class IconButton(QPushButton):
21     
22     def __init__(self, text='', parent=None):
23         super().__init__(parent)
24         icon = self.style().standardIcon(
25             QStyle.StandardPixmap.SP_MessageBoxCritical)
26         self.setText(text)
27         self.setIcon(icon)
28 
29 
30 class Window(QWidget):
31     
32     def __init__(self, parent=None):
33 
34         super().__init__(parent)
35         self.setMinimumWidth(400)
36         layout = QVBoxLayout()
37         self.setLayout(layout)
38         
39         self.groupbox = QGroupBox('Widget gallery')
40         groupbox_layout = QVBoxLayout()
41         self.groupbox.setLayout(groupbox_layout)
42         layout.addWidget(self.groupbox)
43         
44         heading_label = QLabel('Heading label')
45         heading_label.setObjectName('headingLabel')
46         groupbox_layout.addWidget(heading_label)
47 
48         save_button = QPushButton('Save')
49         groupbox_layout.addWidget(save_button)
50         
51         delete_button = IconButton('Delete')
52         groupbox_layout.addWidget(delete_button)
53         
54         flat_button = QPushButton('Flat button')
55         flat_button.setProperty('orange', 'true')
56         groupbox_layout.addWidget(flat_button)
57         
58         panel_frame = QFrame()
59         panel_frame.setFrameStyle(QFrame.Shape.StyledPanel)
60         panel_layout = QVBoxLayout()
61         panel_frame.setLayout(panel_layout)
62 
63         nested_label = QLabel('Nested label')
64         panel_layout.addWidget(nested_label)
65 
66         nested_edit = QLineEdit()
67         nested_edit.setPlaceholderText('Nested line edit')
68         panel_layout.addWidget(nested_edit)
69         
70         nested_button = QPushButton('Nested button')
71         panel_layout.addWidget(nested_button)
72         
73         groupbox_layout.addWidget(panel_frame)
74         
75         self.selector_combo = QComboBox()
76         
77         for selector, qss in STYLES.items():
78             self.selector_combo.addItem(selector, qss)
79         
80         self.selector_combo.currentIndexChanged.connect(self.set_style)
81         layout.addWidget(self.selector_combo)
82         
83         self.qss_label = QLabel()
84         layout.addWidget(self.qss_label)
85         
86         
87     def set_style(self, idx):
88         qss = self.selector_combo.itemData(idx)
89         self.groupbox.setStyleSheet(qss)
90         self.qss_label.setText(qss)
91 
92 
93 if __name__ == '__main__':
94     
95     app = QApplication(sys.argv)
96     main_window = Window()
97     main_window.show()
98     sys.exit(app.exec())

The application’s main window contains a groupbox with the following descendants:

1 QGroupBox              [groupbox]
2     QLabel             [heading_label, objectName="headingLabel"]
3     QPushButton        [save_button]
4     IconButton         [delete_button]
5     QPushButton        [flat_button]
6     QFrame             [panel_frame]
7         QLabel         [nested_label]
8         QLineEdit      [nested_edit]
9         QPushButton    [nested_button]

One of the widgets is an IconButton, a custom QPushButton subclass that adds an icon to its text. We also add a combobox (selector_combo) that lets the user select a QSS style from the STYLES dictionary, and a label that shows the currently applied style sheet.

STYLES contains an example of each of the selector types listed in the table above. Each rule sets the background of the selected widget(s) to orange:

  • The first entry ('No QSS') lets you clear custom QSS rules by setting the groupbox’s styleSheet to an empty string.

  • The universal selector (*) selects the groupbox and all the widgets inside it.

  • The type selector (QPushButton) selects all QPushButton objects that are descendants of the groupbox. Consequently save_button and flat_button are selected as its direct children. delete_button is also selected because IconButton is a subclass of QPushButton. nested_button is selected as well, because it is an indirect descendant of groupbox.

  • The property selector (QPushButton[orange="true"]) selects only flat_button, which is the sole QPushButton that has the custom orange property set to "true".

  • The class selector (.QPushButton) selects save_button, flat_button, and nested_button, but not delete_button, because the latter has a different class (IconButton).

  • The ID selector (#headingLabel) selects heading_label based on its object name.

  • The descendant selector (QGroupBox QLabel) selects both heading_label (a direct child of the groupbox) and nested_label (an indirect descendant).

  • The child selector (QGroupBox > QPushButton) selects save_button, delete_button, and flat_button as direct children of the groupbox, but not nested_button.

15.2 Properties

QSS supports a fixed set of properties, each restricted to a specific value type. The table below lists the some of the commonly used types:

Type Syntax Description Example
Border { Border Style | Length | Brush }* Shorthand border property. border: 2px solid #555;
Brush Color | Gradient | PaletteRole Specifies a Color, a Gradient, or an entry in the widget’s palette. background-color: #FFE4B5;
Color rgb(r, g, b) | rgba(r, g, b, a) | hsv(h, s, v) | hsva(h, s, v, a) | hsl(h, s, l) | hsla(h, s, l, a) | #rrggbb | Color Name Specifies a color as RGB, RGBA, HSV, HSVA, HSL, HSLA, or a named color. color: orange;
Font (Font Style | Font Weight){0,2} Font Size String Shorthand font property. font: bold italic 18px "Segoe UI";
Length Number (px | pt | em | ex)? A number followed by a measurement unit. Qt requires the unit to be specified explicitly. padding: 12px;
Radius Length{1, 2} One or two occurrences of Length, giving the horizontal and (optionally) vertical corner radius. border-radius: 12px;

This section’s main window contains a single line edit and a combobox that lets you select which of its properties will be styled:

 1 import sys
 2 from PySide6.QtWidgets import (QApplication, QGroupBox,
 3     QComboBox, QWidget, QLineEdit, QVBoxLayout, QLabel)
 4 
 5 
 6 STYLES = {
 7     'No QSS': '',
 8     'Color':
 9         'QLineEdit { color: orange; }',
10     'Background color':
11         'QLineEdit { background-color: #FFA500; }',
12     'Font size + Padding': 
13         'QLineEdit { font-size: 22px; padding: 12px; }',
14     'Font':
15         'QLineEdit { font: bold italic 18px Arial ; }',
16     'Alignment':
17         'QLineEdit { qproperty-alignment: AlignRight; }',
18     'Border + Radius':
19         'QLineEdit { border: 2px solid #555; '
20         'border-radius: 12px; padding: 8px; }',
21     'Gradient background':
22         'QLineEdit { background: qlineargradient('
23         'x1:0, y1:0, x2:0, y2:1, '
24         'stop:0 #FFF8E1, stop:1 #FFBB33); }'
25 }
26 
27 
28 class Window(QWidget):
29     
30     def __init__(self, parent=None):
31 
32         super().__init__(parent)
33         self.setMinimumWidth(400)
34         
35         layout = QVBoxLayout()
36         self.setLayout(layout)
37         
38         self.groupbox = QGroupBox('Widget gallery')
39         groupbox_layout = QVBoxLayout()
40         self.groupbox.setLayout(groupbox_layout)
41         layout.addWidget(self.groupbox)
42         
43         self.line_edit = QLineEdit()
44         self.line_edit.setMinimumHeight(80)
45         font = self.line_edit.font()
46         font.setPixelSize(18)
47         self.line_edit.setFont(font)
48         self.line_edit.setText('Styling properties with QSS')
49         groupbox_layout.addWidget(self.line_edit)
50 
51         self.selector_combo = QComboBox()
52         self.selector_combo.setEditable(False)
53         
54         for selector, qss in STYLES.items():
55             self.selector_combo.addItem(selector, qss)
56         
57         self.selector_combo.currentIndexChanged.connect(self.set_style)
58         layout.addWidget(self.selector_combo)
59         
60         self.qss_label = QLabel()
61         layout.addWidget(self.qss_label)
62 
63         
64     def set_style(self, idx):
65         qss = self.selector_combo.itemData(idx)
66         self.groupbox.setStyleSheet(qss)
67         self.qss_label.setText(qss)
68 
69 
70 if __name__ == '__main__':
71     
72     app = QApplication(sys.argv)
73     main_window = Window()
74     main_window.show()
75     sys.exit(app.exec())
  • The color property sets the line edit’s text to orange using its SVG color keyword name.

  • The background-color property sets the line edit’s background color to orange using its hex value (#FFA500). Both background-color and color accept values of the type Color.

  • The font-size property is of the Font Size which accepts values in px and pt units.

  • The padding property is a Length which accepts values in px, pt, em, and ex units. In the example, both font-size and padding are set in pixels.

  • font is of Font type, which is a shorthand property for setting the text’s font, equivalent to setting font-style and/or font-weight, font-family, and font-size, eg font: bold italic 18px;.

    Order is fixed and family must come last: [style], [weight] size family. Style and weight are optional and can change places (0, 1, or 2 of them, in either order), but everything after that is just assigned to size, then family. Putting family first breaks both. This is the same as the original CSS syntax but with a smaller vocabulary.

  • The qproperty-alignment property works differently. The qproperty- prefix works directly with Qt properties exposed through the widget’s meta-object system. The example sets QLineEdit’s alignment property, which expects a Qt.Alignment enum member (AlignRight). This only works if the target property has a write accessor - a read-only @Property cannot be set this way.

  • The border and border-radius properties are set together to give the line edit a solid rounded frame. border is of type Border, a shorthand accepting a Border Style, a Length, and a Brush in one declaration. border-radius is of type Radius, taking one or two Length values for the horizontal and (optionally) vertical corner radius. A single value like 12px applies uniformly to all four corners.

15.3 Pseudo-States

QSS selectors may contain pseudo-states that restrict the application of the rule based on the widget’s state. Pseudo-states appear at the end of the selector, with a colon (:) in between.

Many QSS pseudo-states also have CSS counterparts:

Pseudo-State Description
:active The widget resides in an active window.
:checked The item is checked.
:disabled The item is disabled.
:enabled The item is enabled.
:focus The item has input focus.
:hover The mouse is hovering over the item.
:indeterminate The item has indeterminate state.
:read-only The item is marked read only or non-editable.

While others are QSS specific:

Pseudo-State Description
:bottom The item is positioned at the bottom.
:closable The items can be closed.
:closed The item is in the closed state.
:editable The QComboBox is editable.
:exclusive The item is part of an exclusive item group.
:floatable The items can be floated.
:has-children The item has children

The example demonstrates six pseudo-states of a QCheckBox. Reaching each one requires manual interaction with the checkbox or the ‘Disable the checkbox’ button.

 1 import sys
 2 from PySide6.QtWidgets import (QApplication, QGroupBox,
 3     QComboBox, QWidget, QCheckBox, QVBoxLayout, QLabel,
 4     QPushButton)
 5 
 6 
 7 STYLES = {
 8     'No QSS' : '',
 9     'Hover' : 'QCheckBox:hover { background: orange; }',
10     'Pressed' : 'QCheckBox:pressed { background: orange; }',
11     'Checked' : 'QCheckBox:checked { background: orange; }',
12     'Indeterminate' : 'QCheckBox:indeterminate { background: orange; }',
13     'Focus' : 'QCheckBox:focus { background: orange; }',
14     'Disabled' : 'QCheckBox:disabled { background: orange; }',
15 }
16 
17 
18 class Window(QWidget):
19     
20     def __init__(self, parent=None):
21 
22         super().__init__(parent)
23         self.setMinimumWidth(400)
24         
25         layout = QVBoxLayout()
26         self.setLayout(layout)
27         
28         self.groupbox = QGroupBox('Widget gallery')
29         groupbox_layout = QVBoxLayout()
30         self.groupbox.setLayout(groupbox_layout)
31         layout.addWidget(self.groupbox)
32         
33         self.test_checkbox = QCheckBox('CheckBox')
34         self.test_checkbox.setMinimumHeight(60)
35         self.test_checkbox.setTristate(True)
36         groupbox_layout.addWidget(self.test_checkbox)
37         
38         self.disable_button = QPushButton('Disable the checkbox')
39         self.disable_button.setCheckable(True)
40         self.disable_button.clicked.connect(self.toggle_checkbox_enabled)
41         groupbox_layout.addWidget(self.disable_button)
42 
43         self.selector_combo = QComboBox()
44         self.selector_combo.setEditable(False)
45         
46         for selector, qss in STYLES.items():
47             self.selector_combo.addItem(selector, qss)
48         
49         self.selector_combo.currentIndexChanged.connect(self.set_style)
50         layout.addWidget(self.selector_combo)
51         
52         self.qss_label = QLabel()
53         layout.addWidget(self.qss_label)
54         
55         self.test_checkbox.setStyleSheet('border: 1px solid red;')
56 
57         
58     def set_style(self, idx):
59         qss = self.selector_combo.itemData(idx)
60         self.groupbox.setStyleSheet(qss)
61         self.qss_label.setText(qss)
62         
63     def toggle_checkbox_enabled(self):
64         if self.disable_button.isChecked():
65             self.test_checkbox.setEnabled(False)
66         else:
67             self.test_checkbox.setEnabled(True)
68 
69 
70 if __name__ == '__main__':
71     
72     app = QApplication(sys.argv)
73     main_window = Window()
74     main_window.show()
75     sys.exit(app.exec())
  • The :hover pseudo-state highlights the checkbox while the mouse pointer is over it.
  • The :pressed pseudo-state highlights the checkbox while the mouse button is held down on it.

  • The :checked pseudo-state highlights the checkbox once it has been clicked into the checked state.

  • :indeterminate only applies because setTristate(True) was called on test_checkbox. Clicking cycles the checkbox through its three states and the rule takse effect when it is partially checked.

  • :focus highlights the checkbox once it holds keyboard focus. Selecting ‘Focus’ from the combo box does not automatically move the focus to the checkbox. The effects is shown when you click (or tab) to the checkbox.

  • :disabled is the only one not driven by the checkbox directly. Selecting ‘Disabled’ from the combo box applies the rule, but the checkbox itself is enabled and disabled independently, via the togglable disable_button below it.

Notice that hovering over the checkbox only triggers the :hover background across the checkbox’s actual content (the indicator and the text). QCheckBox paints its QSS background and border across its entire widget geometry (whatever the layout stretched it to), but determines mouse interaction (both the :hover state and whether a click actually toggles the box) against a separate rectangle sized just to fit the indicator and text. You only notice this when the widget is stretched wider or taller by its layout.

15.4 Subcontrols

QSS lets you style a complex widget’s components, such as the drop-down button of a QComboBox or the up and down arrows of a QSpinBox. Selectors may contain subcontrols that make it possible to restrict the application of a rule to specific subcontrols.

Some of the commonly used subcontrols:

Sub-Control Description
::indicator The indicator of a QCheckBox, QRadioButton, a checkable menu item, or an item view.
::handle The handle (slider) of a QSlider, QScrollBar, or QSplitter.
::groove The groove of a QSlider.
::drop-down The drop-down button of a QComboBox.
::down-arrow The down arrow of a QComboBox, QSpinBox, QScrollBar, or a QHeaderView sort indicator.
::tab A tab of a QTabBar or QToolBox.
::title The title of a QGroupBox or QDockWidget.
::chunk The progress chunk of a QProgressBar.
::item An item of a QAbstractItemView, QMenuBar, QMenu, or QStatusBar.
 1 import sys
 2 from PySide6.QtCore import Qt
 3 from PySide6.QtWidgets import (QApplication, QGroupBox, QComboBox,
 4     QWidget, QSlider, QTabBar, QCheckBox, QVBoxLayout, QLabel)
 5 
 6 
 7 STYLES = {
 8     'No QSS' : '',
 9     'Slider groove' : 'QSlider::groove { background: orange; } ',
10     'Slider handle' : 'QSlider::handle { background: orange; }',
11     'Tabbar tab' : 'QTabBar::tab { background: orange; }',
12     'Tabbar tear' : 'QTabBar::tear { background: orange; }',
13     'Checkbox indicator' : 'QCheckBox::indicator { background: orange; }'
14         'QCheckBox::indicator:checked { background: green; }',
15     'Combobox dropdown' : 'QComboBox::drop-down { background: orange; }'
16         'QComboBox::down-arrow { background: green; }',
17     'Groupbox title': 'QGroupBox::title { background: orange; }'
18     }
19 
20 
21 class Window(QWidget):
22     
23     def __init__(self, parent=None):
24 
25         super().__init__(parent)
26         self.setMinimumWidth(400)
27         
28         layout = QVBoxLayout()
29         self.setLayout(layout)
30         
31         self.groupbox = QGroupBox('Widget gallery')
32         groupbox_layout = QVBoxLayout()
33         self.groupbox.setLayout(groupbox_layout)
34         layout.addWidget(self.groupbox)
35         
36         self.slider = QSlider()
37         self.slider.setValue(50)
38         self.slider.setOrientation(Qt.Orientation.Horizontal)
39         groupbox_layout.addWidget(self.slider)
40         
41         self.tabbar = QTabBar()
42         self.tabbar.setMaximumWidth(380)
43         self.tabbar.setUsesScrollButtons(True)
44         self.tabbar.setElideMode(Qt.TextElideMode.ElideNone)
45         for i in range(1, 10):
46             self.tabbar.addTab(f'Tab {i}')
47         self.tabbar.setCurrentIndex(8)
48         groupbox_layout.addWidget(self.tabbar)
49         
50         self.checkbox = QCheckBox('checkbox')
51         groupbox_layout.addWidget(self.checkbox)
52         
53         self.combobox = QComboBox()
54         self.combobox.addItems(['Item 1', 'Item 2', 'Item 3'])
55         groupbox_layout.addWidget(self.combobox)
56         
57         self.selector_combo = QComboBox()
58         self.selector_combo.setEditable(False)
59         
60         for selector, qss in STYLES.items():
61             self.selector_combo.addItem(selector, qss)
62         
63         self.selector_combo.currentIndexChanged.connect(self.set_style)
64         layout.addWidget(self.selector_combo)
65         
66         self.qss_label = QLabel()
67         layout.addWidget(self.qss_label)        
68 
69         
70     def set_style(self, idx):
71         qss = self.selector_combo.itemData(idx)
72         self.groupbox.setStyleSheet(qss)
73         self.qss_label.setText(qss)
74 
75 
76 if __name__ == '__main__':
77     
78     app = QApplication(sys.argv)
79     main_window = Window()
80     main_window.show()
81     sys.exit(app.exec())

This section’s main window contains a QSlider, a QTabBar with nine tabs, a QCheckBox, and a QComboBox inside a groupbox. A combobox lets you select which subcontrol rule is applied.

  • The QSlider::handle rule colors only the slider’s handle. THe groove is left natively rendered.
  • QSlider::groove, by contrast, makes the handle invisible. Styling a slider’s groove on its own causes the handle to stop rendering.

  • QTabBar::tab colors every tab in the bar.

  • QTabBar::tear colors the tear indicator (the small torn-edge marker Qt draws when there isn’t enough room to show every tab).

  • QCheckBox::indicator colors the checkbox’s indicator orange in its unchecked state and green once checked, leaving the checkbox’s text label unaffected.

  • QComboBox::drop-down colors the button area on the right side of the combobox. The arrow inside it is a separate subcontrol

  • QGroupBox::title colors the background behind the groupbox’s own title text.

15.5 The Box Model

QSS implements the same box model as CSS: margin, border, padding, and content, nested inside each other.

 1 import sys
 2 from PySide6.QtWidgets import (QApplication, QGroupBox,
 3     QWidget, QLabel, QVBoxLayout, QHBoxLayout, QSpinBox)
 4 
 5 
 6 STYLE = '''
 7 QGroupBox {
 8     background-color: white;
 9 }
10 
11 QLabel {
12     border: 1px solid orange;
13     background-color: #BFBFBF;
14 }
15 
16 #controlLabel {
17     margin-top: 10px;
18 }
19 '''
20 
21 
22 class Window(QWidget):
23 
24     def __init__(self):
25 
26         super().__init__()
27         self.resize(400, 400)
28 
29         layout = QVBoxLayout()
30         self.setLayout(layout)
31 
32         self.groupbox = QGroupBox()
33         self.groupbox.setStyleSheet(STYLE)
34         self.groupbox.setFlat(True)
35         groupbox_layout = QVBoxLayout()
36         self.groupbox.setLayout(groupbox_layout)
37         layout.addWidget(self.groupbox)
38 
39         self.styled_label = QLabel('Styled Label')
40         groupbox_layout.addWidget(self.styled_label)
41 
42         self.control_label = QLabel('Control Label')
43         self.control_label.setObjectName('controlLabel')
44         groupbox_layout.addWidget(self.control_label)
45 
46         self.margin_spin = QSpinBox()
47         self.margin_spin.setRange(0, 200)
48         self.margin_spin.valueChanged.connect(self.update_style)
49         margin_layout = QHBoxLayout()
50         margin_layout.addWidget(QLabel('Margin'))
51         margin_layout.addWidget(self.margin_spin)
52         layout.addLayout(margin_layout)
53 
54         self.border_spin = QSpinBox()
55         self.border_spin.setRange(0, 200)
56         self.border_spin.valueChanged.connect(self.update_style)
57         border_layout = QHBoxLayout()
58         border_layout.addWidget(QLabel('Border'))
59         border_layout.addWidget(self.border_spin)
60         layout.addLayout(border_layout)
61 
62         self.padding_spin = QSpinBox()
63         self.padding_spin.setRange(0, 200)
64         self.padding_spin.valueChanged.connect(self.update_style)
65         padding_layout = QHBoxLayout()
66         padding_layout.addWidget(QLabel('Padding'))
67         padding_layout.addWidget(self.padding_spin)
68         layout.addLayout(padding_layout)
69 
70         self.update_style()
71 
72     def update_style(self):
73         user_style = f'''
74             QLabel {{
75                 margin: {self.margin_spin.value()}px;
76                 border: {self.border_spin.value()}px solid orange;
77                 padding: {self.padding_spin.value()}px;
78             }}
79         '''
80         self.styled_label.setStyleSheet(user_style)
81 
82 
83 if __name__ == '__main__':
84 
85     app = QApplication(sys.argv)
86     main_window = Window()
87     main_window.show()
88     sys.exit(app.exec())

In the example, we have two labels: styled_label, whose box model rectangles can be adjusted with the three spinboxes below the groupbox, and control_label, given a fixed top margin once via the #controlLabel ID selector, and otherwise left untouched as a reference point. The border is the one layer actually visible as a distinct shape. Padding and margin have no visual representation of their own.

  • Increasing padding grows the space between the label’s text and its border without moving the border itself.

  • Increasing border thickens the visible ring, pushing the padding and content further inward.

  • Increasing margin pushes styled_label away from its neighbors.

Notice that, at first, groupbox_layout absorbs the growing styled_label by pushing control_label further down. Past a certain point, though, the layout’s minimum size hint exceeds the window’s current size altogether, and Qt grows the window to accomodate it.