1 /****************************************************************************
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
6 ** This file is part of the documentation of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:FDL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
17 ** GNU Free Documentation License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Free
19 ** Documentation License version 1.3 as published by the Free Software
20 ** Foundation and appearing in the file included in the packaging of
21 ** this file. Please review the following information to ensure
22 ** the GNU Free Documentation License version 1.3 requirements
23 ** will be met: http://www.gnu.org/copyleft/fdl.html.
26 ****************************************************************************/
29 \example painting/basicdrawing
30 \title Basic Drawing Example
32 \brief The Basic Drawing example shows how to display basic graphics
33 primitives in a variety of styles using the QPainter class.
35 QPainter performs low-level painting on widgets and other paint
36 devices. The class can draw everything from simple lines to
37 complex shapes like pies and chords. It can also draw aligned text
38 and pixmaps. Normally, it draws in a "natural" coordinate system,
39 but it can in addition do view and world transformation.
41 \image basicdrawing-example.png
43 The example provides a render area, displaying the currently
44 active shape, and lets the user manipulate the rendered shape and
45 its appearance using the QPainter parameters: The user can change
46 the active shape (\gui Shape), and modify the QPainter's pen (\gui
47 {Pen Width}, \gui {Pen Style}, \gui {Pen Cap}, \gui {Pen Join}),
48 brush (\gui {Brush Style}) and render hints (\gui
49 Antialiasing). In addition the user can rotate a shape (\gui
50 Transformations); behind the scenes we use QPainter's ability to
51 manipulate the coordinate system to perform the rotation.
53 The Basic Drawing example consists of two classes:
56 \o \c RenderArea is a custom widget that renders multiple
57 copies of the currently active shape.
58 \o \c Window is the application's main window displaying a
59 \c RenderArea widget in addition to several parameter widgets.
62 First we will review the \c Window class, then we will take a
63 look at the \c RenderArea class.
65 \section1 Window Class Definition
67 The Window class inherits QWidget, and is the application's main
68 window displaying a \c RenderArea widget in addition to several
71 \snippet examples/painting/basicdrawing/window.h 0
73 We declare the various widgets, and three private slots updating
74 the \c RenderArea widget: The \c shapeChanged() slot updates the
75 \c RenderArea widget when the user changes the currently active
76 shape. We call the \c penChanged() slot when either of the
77 QPainter's pen parameters changes. And the \c brushChanged() slot
78 updates the \c RenderArea widget when the user changes the
79 painter's brush style.
81 \section1 Window Class Implementation
83 In the constructor we create and initialize the various widgets
84 appearing in the main application window.
86 \snippet examples/painting/basicdrawing/window.cpp 1
88 First we create the \c RenderArea widget that will render the
89 currently active shape. Then we create the \gui Shape combobox,
90 and add the associated items (i.e. the different shapes a QPainter
93 \snippet examples/painting/basicdrawing/window.cpp 2
95 QPainter's pen is a QPen object; the QPen class defines how a
96 painter should draw lines and outlines of shapes. A pen has
97 several properties: Width, style, cap and join.
99 A pen's width can be \e zero or greater, but the most common width
100 is zero. Note that this doesn't mean 0 pixels, but implies that
101 the shape is drawn as smoothly as possible although perhaps not
102 mathematically correct.
104 We create a QSpinBox for the \gui {Pen Width} parameter.
106 \snippet examples/painting/basicdrawing/window.cpp 3
108 The pen style defines the line type. The default style is solid
109 (Qt::SolidLine). Setting the style to none (Qt::NoPen) tells the
110 painter to not draw lines or outlines. The pen cap defines how
111 the end points of lines are drawn. And the pen join defines how
112 two lines join when multiple connected lines are drawn. The cap
113 and join only apply to lines with a width of 1 pixel or greater.
115 We create \l {QComboBox}es for each of the \gui {Pen Style}, \gui
116 {Pen Cap} and \gui {Pen Join} parameters, and adds the associated
117 items (i.e the values of the Qt::PenStyle, Qt::PenCapStyle and
118 Qt::PenJoinStyle enums respectively).
120 \snippet examples/painting/basicdrawing/window.cpp 4
122 The QBrush class defines the fill pattern of shapes drawn by a
123 QPainter. The default brush style is Qt::NoBrush. This style tells
124 the painter to not fill shapes. The standard style for filling is
127 We create a QComboBox for the \gui {Brush Style} parameter, and add
128 the associated items (i.e. the values of the Qt::BrushStyle enum).
130 \snippet examples/painting/basicdrawing/window.cpp 5
131 \snippet examples/painting/basicdrawing/window.cpp 6
133 Antialiasing is a feature that "smoothes" the pixels to create
134 more even and less jagged lines, and can be applied using
135 QPainter's render hints. QPainter::RenderHints are used to specify
136 flags to QPainter that may or may not be respected by any given
139 We simply create a QCheckBox for the \gui Antialiasing option.
141 \snippet examples/painting/basicdrawing/window.cpp 7
143 The \gui Transformations option implies a manipulation of the
144 coordinate system that will appear as if the rendered shape is
145 rotated in three dimensions.
147 We use the QPainter::translate(), QPainter::rotate() and
148 QPainter::scale() functions to implement this feature represented
149 in the main application window by a simple QCheckBox.
151 \snippet examples/painting/basicdrawing/window.cpp 8
153 Then we connect the parameter widgets with their associated slots
154 using the static QObject::connect() function, ensuring that the \c
155 RenderArea widget is updated whenever the user changes the shape,
156 or any of the other parameters.
158 \snippet examples/painting/basicdrawing/window.cpp 9
159 \snippet examples/painting/basicdrawing/window.cpp 10
161 Finally, we add the various widgets to a layout, and call the \c
162 shapeChanged(), \c penChanged(), and \c brushChanged() slots to
163 initialize the application. We also turn on antialiasing.
165 \snippet examples/painting/basicdrawing/window.cpp 11
167 The \c shapeChanged() slot is called whenever the user changes the
168 currently active shape.
170 First we retrieve the shape the user has chosen using the
171 QComboBox::itemData() function. This function returns the data for
172 the given role in the given index in the combobox. We use
173 QComboBox::currentIndex() to retrieve the index of the shape, and
174 the role is defined by the Qt::ItemDataRole enum; \c IdRole is an
175 alias for Qt::UserRole.
177 Note that Qt::UserRole is only the first role that can be used for
178 application-specific purposes. If you need to store different data
179 in the same index, you can use different roles by simply
180 incrementing the value of Qt::UserRole, for example: 'Qt::UserRole
181 + 1' and 'Qt::UserRole + 2'. However, it is a good programming
182 practice to give each role their own name: 'myFirstRole =
183 Qt::UserRole + 1' and 'mySecondRole = Qt::UserRole + 2'. Even
184 though we only need a single role in this particular example, we
185 add the following line of code to the beginning of the \c
188 \snippet examples/painting/basicdrawing/window.cpp 0
190 The QComboBox::itemData() function returns the data as a QVariant,
191 so we need to cast the data to \c RenderArea::Shape. If there is
192 no data for the given role, the function returns
195 In the end we call the \c RenderArea::setShape() slot to update
196 the \c RenderArea widget.
198 \snippet examples/painting/basicdrawing/window.cpp 12
200 We call the \c penChanged() slot whenever the user changes any of
201 the pen parameters. Again we use the QComboBox::itemData()
202 function to retrieve the parameters, and then we call the \c
203 RenderArea::setPen() slot to update the \c RenderArea widget.
205 \snippet examples/painting/basicdrawing/window.cpp 13
207 The brushChanged() slot is called whenever the user changes the
208 brush parameter which we retrieve using the QComboBox::itemData()
211 \snippet examples/painting/basicdrawing/window.cpp 14
213 If the brush parameter is a gradient fill, special actions are
216 The QGradient class is used in combination with QBrush to specify
217 gradient fills. Qt currently supports three types of gradient
218 fills: linear, radial and conical. Each of these is represented by
219 a subclass of QGradient: QLinearGradient, QRadialGradient and
222 So if the brush style is Qt::LinearGradientPattern, we first
223 create a QLinearGradient object with interpolation area between
224 the coordinates passed as arguments to the constructor. The
225 positions are specified using logical coordinates. Then we set the
226 gradient's colors using the QGradient::setColorAt() function. The
227 colors is defined using stop points which are composed by a
228 position (between 0 and 1) and a QColor. The set of stop points
229 describes how the gradient area should be filled. A gradient can
230 have an arbitrary number of stop points.
232 In the end we call \c RenderArea::setBrush() slot to update the \c
233 RenderArea widget's brush with the QLinearGradient object.
235 \snippet examples/painting/basicdrawing/window.cpp 15
237 A similar pattern of actions, as the one used for QLinearGradient,
238 is used in the cases of Qt::RadialGradientPattern and
239 Qt::ConicalGradientPattern.
241 The only difference is the arguments passed to the constructor:
242 Regarding the QRadialGradient constructor the first argument is
243 the center, and the second the radial gradient's radius. The third
244 argument is optional, but can be used to define the focal point of
245 the gradient inside the circle (the default focal point is the
246 circle center). Regarding the QConicalGradient constructor, the
247 first argument specifies the center of the conical, and the second
248 specifies the start angle of the interpolation.
250 \snippet examples/painting/basicdrawing/window.cpp 16
252 If the brush style is Qt::TexturePattern we create a QBrush from a
253 QPixmap. Then we call \c RenderArea::setBrush() slot to update the
254 \c RenderArea widget with the newly created brush.
256 \snippet examples/painting/basicdrawing/window.cpp 17
258 Otherwise we simply create a brush with the given style and a
259 green color, and then call \c RenderArea::setBrush() slot to
260 update the \c RenderArea widget with the newly created brush.
262 \section1 RenderArea Class Definition
264 The \c RenderArea class inherits QWidget, and renders multiple
265 copies of the currently active shape using a QPainter.
267 \snippet examples/painting/basicdrawing/renderarea.h 0
269 First we define a public \c Shape enum to hold the different
270 shapes that can be rendered by the widget (i.e the shapes that can
271 be rendered by a QPainter). Then we reimplement the constructor as
272 well as two of QWidget's public functions: \l
273 {QWidget::minimumSizeHint()}{minimumSizeHint()} and \l
274 {QWidget::sizeHint()}{sizeHint()}.
276 We also reimplement the QWidget::paintEvent() function to be able
277 to draw the currently active shape according to the specified
280 We declare several private slots: The \c setShape() slot changes
281 the \c RenderArea's shape, the \c setPen() and \c setBrush() slots
282 modify the widget's pen and brush, and the \c setAntialiased() and
283 \c setTransformed() slots modify the widget's respective
286 \section1 RenderArea Class Implementation
288 In the constructor we initialize some of the widget's variables.
290 \snippet examples/painting/basicdrawing/renderarea.cpp 0
292 We set its shape to be a \gui Polygon, its antialiased property to
293 be false and we load an image into the widget's pixmap
294 variable. In the end we set the widget's background role, defining
295 the brush from the widget's \l {QWidget::palette}{palette} that
296 will be used to render the background. QPalette::Base is typically
299 \snippet examples/painting/basicdrawing/renderarea.cpp 2
301 The \c RenderArea inherits QWidget's \l
302 {QWidget::sizeHint()}{sizeHint} property holding the recommended
303 size for the widget. If the value of this property is an invalid
304 size, no size is recommended.
306 The default implementation of the QWidget::sizeHint() function
307 returns an invalid size if there is no layout for the widget, and
308 returns the layout's preferred size otherwise.
310 Our reimplementation of the function returns a QSize with a 400
311 pixels width and a 200 pixels height.
313 \snippet examples/painting/basicdrawing/renderarea.cpp 1
315 \c RenderArea also inherits QWidget's
316 \l{QWidget::minimumSizeHint()}{minimumSizeHint} property holding
317 the recommended minimum size for the widget. Again, if the value
318 of this property is an invalid size, no size is recommended.
320 The default implementation of QWidget::minimumSizeHint() returns
321 an invalid size if there is no layout for the widget, and returns
322 the layout's minimum size otherwise.
324 Our reimplementation of the function returns a QSize with a 100
325 pixels width and a 100 pixels height.
327 \snippet examples/painting/basicdrawing/renderarea.cpp 3
329 \snippet examples/painting/basicdrawing/renderarea.cpp 4
331 \snippet examples/painting/basicdrawing/renderarea.cpp 5
333 The public \c setShape(), \c setPen() and \c setBrush() slots are
334 called whenever we want to modify a \c RenderArea widget's shape,
335 pen or brush. We set the shape, pen or brush according to the
336 slot parameter, and call QWidget::update() to make the changes
337 visible in the \c RenderArea widget.
339 The QWidget::update() slot does not cause an immediate
340 repaint; instead it schedules a paint event for processing when Qt
341 returns to the main event loop.
343 \snippet examples/painting/basicdrawing/renderarea.cpp 6
345 \snippet examples/painting/basicdrawing/renderarea.cpp 7
347 With the \c setAntialiased() and \c setTransformed() slots we
348 change the state of the properties according to the slot
349 parameter, and call the QWidget::update() slot to make the changes
350 visible in the \c RenderArea widget.
352 \snippet examples/painting/basicdrawing/renderarea.cpp 8
354 Then we reimplement the QWidget::paintEvent() function. The first
355 thing we do is to create the graphical objects we will need to
356 draw the various shapes.
358 We create a vector of four \l {QPoint}s. We use this vector to
359 render the \gui Points, \gui Polyline and \gui Polygon
360 shapes. Then we create a QRect, defining a rectangle in the plane,
361 which we use as the bounding rectangle for all the shapes excluding
362 the \gui Path and the \gui Pixmap.
364 We also create a QPainterPath. The QPainterPath class provides a
365 container for painting operations, enabling graphical shapes to be
366 constructed and reused. A painter path is an object composed of a
367 number of graphical building blocks, such as rectangles, ellipses,
368 lines, and curves. For more information about the QPainterPath
369 class, see the \l {painting/painterpaths}{Painter Paths}
370 example. In this example, we create a painter path composed of one
371 straight line and a Bezier curve.
373 In addition we define a start angle and an arc length that we will
374 use when drawing the \gui Arc, \gui Chord and \gui Pie shapes.
376 \snippet examples/painting/basicdrawing/renderarea.cpp 9
378 We create a QPainter for the \c RenderArea widget, and set the
379 painters pen and brush according to the \c RenderArea's pen and
380 brush. If the \gui Antialiasing parameter option is checked, we
381 also set the painter's render hints. QPainter::Antialiasing
382 indicates that the engine should antialias edges of primitives if
385 \snippet examples/painting/basicdrawing/renderarea.cpp 10
387 Finally, we render the multiple copies of the \c RenderArea's
388 shape. The number of copies is depending on the size of the \c
389 RenderArea widget, and we calculate their positions using two \c
390 for loops and the widgets height and width.
392 For each copy we first save the current painter state (pushes the
393 state onto a stack). Then we translate the coordinate system,
394 using the QPainter::translate() function, to the position
395 determined by the variables of the \c for loops. If we omit this
396 translation of the coordinate system all the copies of the shape
397 will be rendered on top of each other in the top left cormer of
398 the \c RenderArea widget.
400 \snippet examples/painting/basicdrawing/renderarea.cpp 11
402 If the \gui Transformations parameter option is checked, we do an
403 additional translation of the coordinate system before we rotate
404 the coordinate system 60 degrees clockwise using the
405 QPainter::rotate() function and scale it down in size using the
406 QPainter::scale() function. In the end we translate the coordinate
407 system back to where it was before we rotated and scaled it.
409 Now, when rendering the shape, it will appear as if it was rotated
412 \snippet examples/painting/basicdrawing/renderarea.cpp 12
414 Next, we identify the \c RenderArea's shape, and render it using
415 the associated QPainter drawing function:
418 \o QPainter::drawLine(),
419 \o QPainter::drawPoints(),
420 \o QPainter::drawPolyline(),
421 \o QPainter::drawPolygon(),
422 \o QPainter::drawRect(),
423 \o QPainter::drawRoundedRect(),
424 \o QPainter::drawEllipse(),
425 \o QPainter::drawArc(),
426 \o QPainter::drawChord(),
427 \o QPainter::drawPie(),
428 \o QPainter::drawPath(),
429 \o QPainter::drawText() or
430 \o QPainter::drawPixmap()
433 Before we started rendering, we saved the current painter state
434 (pushes the state onto a stack). The rationale for this is that we
435 calculate each shape copy's position relative to the same point in
436 the coordinate system. When translating the coordinate system, we
437 lose the knowledge of this point unless we save the current
438 painter state \e before we start the translating process.
440 \snippet examples/painting/basicdrawing/renderarea.cpp 13
442 Then, when we are finished rendering a copy of the shape we can
443 restore the original painter state, with its associated coordinate
444 system, using the QPainter::restore() function. In this way we
445 ensure that the next shape copy will be rendered in the correct
448 We could translate the coordinate system back using
449 QPainter::translate() instead of saving the painter state. But
450 since we in addition to translating the coordinate system (when
451 the \gui Transformation parameter option is checked) both rotate
452 and scale the coordinate system, the easiest solution is to save
453 the current painter state.