Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
styles-checkbox-walkthrough.qdoc
Go to the documentation of this file.
1// Copyright (C) 2026 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
3
4/*!
5 \page style-checkbox-walkthrough.html
6 \title Styling a Checkbox: A Walkthrough
7 \brief How a QCheckBox is drawn, from its paint event through QCommonStyle
8 to a custom indicator in a proxy style.
9
10 This page follows a checkbox from the moment it receives a paint event to
11 the moment the style finishes painting. It shows how the widget builds its
12 style option, how \l QCommonStyle breaks the element into parts, and how a
13 \l QProxyStyle replaces one of those parts. Most widgets follow the same
14 structure, so the same reading strategy works for them: find the style
15 option the widget builds, find the elements it draws, and read the
16 \l QCommonStyle implementation of those elements.
17
18 \section1 The widget builds a style option
19
20 \l QCheckBox uses \l QStyleOptionButton. Its \c initStyleOption() function
21 fills the option out like this, slightly simplified:
22
23 \snippet code/doc_src_styles.cpp 0
24
25 \l QStyleOption::initFrom() sets the information that every widget shares.
26 Its implementation amounts to this:
27
28 \snippet code/doc_src_styles.cpp 1
29
30 \c State_Enabled is set when the widget is enabled, \c State_HasFocus when
31 it has focus, \c State_KeyboardFocusChange when the user last changed focus
32 with the keyboard, and \c State_Active when the widget's window is the
33 active window. \c State_MouseOver is set while the mouse cursor is over the
34 widget. In addition to the state, \c initFrom() stores the layout direction,
35 the widget's rectangle, its palette, and its font metrics in the option.
36
37 \l QCheckBox then adds its own state. \c State_Sunken is set while the user
38 presses the box, whether it's checked or not. \c State_NoChange is set for a
39 partially checked tristate box; otherwise \c State_On or \c State_Off
40 reflects the check state. The option also carries the text, the icon, and
41 the icon size. \l QCheckBox keeps \c State_MouseOver only while the widget
42 has the \l{Qt::}{WA_Hover} attribute, which a style typically sets in
43 \l{QStyle::}{polish()}.
44
45 Suppose the user presses the checked checkbox in the following screenshot
46 with the mouse while it has focus. The screenshot also shows a radio button,
47 which uses the same structure with \c PE_IndicatorRadioButton and
48 \c CE_RadioButtonLabel:
49
50 \image styles/checkbox.webp
51 {Checkbox and radio button with their indicator, label, and focus
52 rectangles outlined and named in a legend}
53
54 At that moment, its option has these state flags:
55
56 \table 90%
57 \header
58 \li State flag
59 \li Set
60 \row
61 \li \c State_Sunken
62 \li Yes
63 \row
64 \li \c State_NoChange
65 \li No
66 \row
67 \li \c State_On
68 \li Yes
69 \row
70 \li \c State_Off
71 \li No
72 \row
73 \li \c State_MouseOver
74 \li Yes
75 \row
76 \li \c State_Enabled
77 \li Yes
78 \row
79 \li \c State_HasFocus
80 \li Yes
81 \row
82 \li \c State_KeyboardFocusChange
83 \li No
84 \row
85 \li \c State_Active
86 \li Yes
87 \endtable
88
89 \section1 The widget asks the style to draw
90
91 \l QCheckBox paints itself in \l{QWidget::}{paintEvent()} with a
92 \l QStylePainter, which wraps the drawing functions of \l QStyle:
93
94 \snippet code/doc_src_styles.cpp 2
95
96 That's all the widget does. Everything else happens in the style.
97
98 \section1 QCommonStyle breaks the element into parts
99
100 \l QCommonStyle handles \c CE_CheckBox by asking for the rectangles of its
101 two subelements, \c SE_CheckBoxIndicator and \c SE_CheckBoxContents, and
102 drawing an element into each. If the checkbox has focus, it also draws the
103 focus frame:
104
105 \snippet code/doc_src_styles.cpp 3
106
107 Note the \c proxy() calls. A style always draws its child elements through
108 \l{QStyle::}{proxy()} so that a \l QProxyStyle wrapped around it gets the
109 chance to override them.
110
111 \c CE_CheckBoxLabel is also implemented in \l QCommonStyle:
112
113 \snippet code/doc_src_styles.cpp 4
114
115 \l{QStyle::}{visualAlignment()} adjusts the alignment for the layout
116 direction. The style draws the icon, if there is one, and shrinks the
117 remaining text rectangle accordingly. \l{QStyle::}{drawItemText()} draws the
118 text with the alignment, the layout direction, and the mnemonic taken into
119 account, and it uses the palette to pick the text color. Drawing a label
120 involves many details, and the base class handles them well, so a custom
121 style rarely needs to reimplement it.
122
123 \section1 A proxy style replaces the indicator
124
125 The indicator, \c PE_IndicatorCheckBox, is where styles differ, so it's the
126 part to replace. The following \l QProxyStyle subclass draws a rounded
127 indicator from the palette colors in the option and forwards every other
128 element to the base style:
129
130 \snippet customstyle/checkboxstyle.cpp 0
131
132 \snippet customstyle/checkboxstyle.cpp 1
133
134 The implementation reads all of its information from the option. It picks
135 the color group from \c State_Enabled and \c State_Active, highlights the
136 frame while \c State_MouseOver is set, darkens the background while
137 \c State_Sunken is set, and draws a check mark for \c State_On or a filled
138 square for \c State_NoChange. Because every color comes from the palette,
139 the indicator follows the application palette and works in both light and
140 dark color schemes. It also saves and restores the painter, so the base
141 class finds the painter in the state it expects.
142
143 The same indicator appears wherever the style draws \c PE_IndicatorCheckBox:
144 in checkboxes, in checkable group boxes, and in item views that use it for
145 check marks. That reuse is the reason primitive elements exist.
146
147 To use the style, install it before the application creates its widgets:
148
149 \snippet customstyle/checkboxstyle.cpp 2
150
151 \section1 Apply the same reading to other widgets
152
153 To learn how a widget is drawn, you don't have to read all of the code. It's
154 usually enough to know which style elements the widget draws, which states
155 it sets, and what its style option contains. The widget builds an option and
156 calls the style one or more times; the style draws the elements the widget
157 asks for. \l{Widget Style Reference} lists exactly that for each widget.
158
159 \sa {How a Style Draws a Widget}, {Widget Style Reference}, QProxyStyle,
160 QStyleOptionButton
161*/