source: trunk/doc/src/examples/painterpaths.qdoc@ 846

Last change on this file since 846 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 17.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the documentation of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:FDL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in a
14** written agreement between you and Nokia.
15**
16** GNU Free Documentation License
17** Alternatively, this file may be used under the terms of the GNU Free
18** Documentation License version 1.3 as published by the Free Software
19** Foundation and appearing in the file included in the packaging of this
20** file.
21**
22** If you have questions regarding the use of this file, please contact
23** Nokia at qt-info@nokia.com.
24** $QT_END_LICENSE$
25**
26****************************************************************************/
27
28/*!
29 \example painting/painterpaths
30 \title Painter Paths Example
31
32 The Painter Paths example shows how painter paths can be used to
33 build complex shapes for rendering.
34
35 \image painterpaths-example.png
36
37 The QPainterPath class provides a container for painting
38 operations, enabling graphical shapes to be constructed and
39 reused.
40
41 A painter path is an object composed of a number of graphical
42 building blocks (such as rectangles, ellipses, lines, and curves),
43 and can be used for filling, outlining, and clipping. The main
44 advantage of painter paths over normal drawing operations is that
45 complex shapes only need to be created once, but they can be drawn
46 many times using only calls to QPainter::drawPath().
47
48 The example consists of two classes:
49
50 \list
51 \o The \c RenderArea class which is a custom widget displaying
52 a single painter path.
53 \o The \c Window class which is the applications main window
54 displaying several \c RenderArea widgets, and allowing the user
55 to manipulate the painter paths' filling, pen, color
56 and rotation angle.
57 \endlist
58
59 First we will review the \c Window class, then we will take a look
60 at the \c RenderArea class.
61
62 \section1 Window Class Definition
63
64 The \c Window class inherits QWidget, and is the applications main
65 window displaying several \c RenderArea widgets, and allowing the
66 user to manipulate the painter paths' filling, pen, color and
67 rotation angle.
68
69 \snippet examples/painting/painterpaths/window.h 0
70
71 We declare three private slots to respond to user input regarding
72 filling and color: \c fillRuleChanged(), \c fillGradientChanged()
73 and \c penColorChanged().
74
75 When the user changes the pen width and the rotation angle, the
76 new value is passed directly on to the \c RenderArea widgets using
77 the QSpinBox::valueChanged() signal. The reason why we must
78 implement slots to update the filling and color, is that QComboBox
79 doesn't provide a similar signal passing the new value as
80 argument; so we need to retrieve the new value, or values, before
81 we can update the \c RenderArea widgets.
82
83 \snippet examples/painting/painterpaths/window.h 1
84
85 We also declare a couple of private convenience functions: \c
86 populateWithColors() populates a given QComboBox with items
87 corresponding to the color names Qt knows about, and \c
88 currentItemData() returns the current item for a given QComboBox.
89
90 \snippet examples/painting/painterpaths/window.h 2
91
92 Then we declare the various components of the main window
93 widget. We also declare a convenience constant specifying the
94 number of \c RenderArea widgets.
95
96 \section1 Window Class Implementation
97
98 In the implementation of the \c Window class we first declare the
99 constant \c Pi with six significant figures:
100
101 \snippet examples/painting/painterpaths/window.cpp 0
102
103 In the constructor, we then define the various painter paths and
104 create corresponding \c RenderArea widgets which will render the
105 graphical shapes:
106
107 \snippet examples/painting/painterpaths/window.cpp 1
108
109 We construct a rectangle with sharp corners using the
110 QPainterPath::moveTo() and QPainterPath::lineTo()
111 functions.
112
113 QPainterPath::moveTo() moves the current point to the point passed
114 as argument. A painter path is an object composed of a number of
115 graphical building blocks, i.e. subpaths. Moving the current point
116 will also start a new subpath (implicitly closing the previously
117 current path when the new one is started). The
118 QPainterPath::lineTo() function adds a straight line from the
119 current point to the given end point. After the line is drawn, the
120 current point is updated to be at the end point of the line.
121
122 We first move the current point starting a new subpath, and we
123 draw three of the rectangle's sides. Then we call the
124 QPainterPath::closeSubpath() function which draws a line to the
125 beginning of the current subpath. A new subpath is automatically
126 begun when the current subpath is closed. The current point of the
127 new path is (0, 0). We could also have called
128 QPainterPath::lineTo() to draw the last line as well, and then
129 explicitly start a new subpath using the QPainterPath::moveTo()
130 function.
131
132 QPainterPath also provide the QPainterPath::addRect() convenience
133 function, which adds a given rectangle to the path as a closed
134 subpath. The rectangle is added as a clockwise set of lines. The
135 painter path's current position after the rect has been added is
136 at the top-left corner of the rectangle.
137
138 \snippet examples/painting/painterpaths/window.cpp 2
139
140 Then we construct a rectangle with rounded corners. As before, we
141 use the QPainterPath::moveTo() and QPainterPath::lineTo()
142 functions to draw the rectangle's sides. To create the rounded
143 corners we use the QPainterPath::arcTo() function.
144
145 QPainterPath::arcTo() creates an arc that occupies the given
146 rectangle (specified by a QRect or the rectangle's coordinates),
147 beginning at the given start angle and extending the given degrees
148 counter-clockwise. Angles are specified in degrees. Clockwise arcs
149 can be specified using negative angles. The function connects the
150 current point to the starting point of the arc if they are not
151 already connected.
152
153 \snippet examples/painting/painterpaths/window.cpp 3
154
155 We also use the QPainterPath::arcTo() function to construct the
156 ellipse path. First we move the current point starting a new
157 path. Then we call QPainterPath::arcTo() with starting angle 0.0
158 and 360.0 degrees as the last argument, creating an ellipse.
159
160 Again, QPainterPath provides a convenience function (
161 QPainterPath::addEllipse()) which creates an ellipse within a
162 given bounding rectangle and adds it to the painter path. If the
163 current subpath is closed, a new subpath is started. The ellipse
164 is composed of a clockwise curve, starting and finishing at zero
165 degrees (the 3 o'clock position).
166
167 \snippet examples/painting/painterpaths/window.cpp 4
168
169 When constructing the pie chart path we continue to use a
170 combination of the mentioned functions: First we move the current
171 point, starting a new subpath. Then we create a line from the
172 center of the chart to the arc, and the arc itself. When we close
173 the subpath, we implicitly construct the last line back to the
174 center of the chart.
175
176 \snippet examples/painting/painterpaths/window.cpp 5
177
178 Constructing a polygon is equivalent to constructing a rectangle.
179
180 QPainterPath also provide the QPainterPath::addPolygon()
181 convenience function which adds the given polygon to the path as a
182 new subpath. Current position after the polygon has been added is
183 the last point in polygon.
184
185 \snippet examples/painting/painterpaths/window.cpp 6
186
187 Then we create a path consisting of a group of subpaths: First we
188 move the current point, and create a circle using the
189 QPainterPath::arcTo() function with starting angle 0.0, and 360
190 degrees as the last argument, as we did when we created the
191 ellipse path. Then we move the current point again, starting a
192 new subpath, and construct three sides of a square using the
193 QPainterPath::lineTo() function.
194
195 Now, when we call the QPainterPath::closeSubpath() fucntion the
196 last side is created. Remember that the
197 QPainterPath::closeSubpath() function draws a line to the
198 beginning of the \e current subpath, i.e the square.
199
200 QPainterPath provide a convenience function,
201 QPainterPath::addPath() which adds a given path to the path that
202 calls the function.
203
204 \snippet examples/painting/painterpaths/window.cpp 7
205
206 When creating the text path, we first create the font. Then we set
207 the font's style strategy which tells the font matching algorithm
208 what type of fonts should be used to find an appropriate default
209 family. QFont::ForceOutline forces the use of outline fonts.
210
211 To construct the text, we use the QPainterPath::addText() function
212 which adds the given text to the path as a set of closed subpaths
213 created from the supplied font. The subpaths are positioned so
214 that the left end of the text's baseline lies at the specified
215 point.
216
217 \snippet examples/painting/painterpaths/window.cpp 8
218
219 To create the Bezier path, we use the QPainterPath::cubicTo()
220 function which adds a Bezier curve between the current point and
221 the given end point with the given control point. After the curve
222 is added, the current point is updated to be at the end point of
223 the curve.
224
225 In this case we omit to close the subpath so that we only have a
226 simple curve. But there is still a logical line from the curve's
227 endpoint back to the beginning of the subpath; it becomes visible
228 when filling the path as can be seen in the applications main
229 window.
230
231 \snippet examples/painting/painterpaths/window.cpp 9
232
233 The final path that we construct shows that you can use
234 QPainterPath to construct rather complex shapes using only the
235 previous mentioned QPainterPath::moveTo(), QPainterPath::lineTo()
236 and QPainterPath::closeSubpath() functions.
237
238 \snippet examples/painting/painterpaths/window.cpp 10
239
240 Now that we have created all the painter paths that we need, we
241 create a corresponding \c RenderArea widget for each. In the end,
242 we make sure that the number of render areas is correct using the
243 Q_ASSERT() macro.
244
245 \snippet examples/painting/painterpaths/window.cpp 11
246
247 Then we create the widgets associated with the painter paths' fill
248 rule.
249
250 There are two available fill rules in Qt: The Qt::OddEvenFill rule
251 determine whether a point is inside the shape by drawing a
252 horizontal line from the point to a location outside the shape,
253 and count the number of intersections. If the number of
254 intersections is an odd number, the point is inside the
255 shape. This rule is the default.
256
257 The Qt::WindingFill rule determine whether a point is inside the
258 shape by drawing a horizontal line from the point to a location
259 outside the shape. Then it determines whether the direction of the
260 line at each intersection point is up or down. The winding number
261 is determined by summing the direction of each intersection. If
262 the number is non zero, the point is inside the shape.
263
264 The Qt::WindingFill rule can in most cases be considered as the
265 intersection of closed shapes.
266
267 \snippet examples/painting/painterpaths/window.cpp 12
268
269 We also create the other widgets associated with the filling, the
270 pen and the rotation angle.
271
272 \snippet examples/painting/painterpaths/window.cpp 16
273
274 We connect the comboboxes \l {QComboBox::activated()}{activated()}
275 signals to the associated slots in the \c Window class, while we
276 connect the spin boxes \l
277 {QSpinBox::valueChanged()}{valueChanged()} signal directly to the
278 \c RenderArea widget's respective slots.
279
280 \snippet examples/painting/painterpaths/window.cpp 17
281
282 We add the \c RenderArea widgets to a separate layout which we
283 then add to the main layout along with the rest of the widgets.
284
285 \snippet examples/painting/painterpaths/window.cpp 18
286
287 Finally, we initialize the \c RenderArea widgets by calling the \c
288 fillRuleChanged(), \c fillGradientChanged() and \c
289 penColorChanged() slots, and we set the inital pen width and
290 window title.
291
292 \snippet examples/painting/painterpaths/window.cpp 19
293 \codeline
294 \snippet examples/painting/painterpaths/window.cpp 20
295 \codeline
296 \snippet examples/painting/painterpaths/window.cpp 21
297
298 The private slots are implemented to retrieve the new value, or
299 values, from the associated comboboxes and update the RenderArea
300 widgets.
301
302 First we determine the new value, or values, using the private \c
303 currentItemData() function and the qvariant_cast() template
304 function. Then we call the associated slot for each of the \c
305 RenderArea widgets to update the painter paths.
306
307 \snippet examples/painting/painterpaths/window.cpp 22
308
309 The \c populateWithColors() function populates the given combobox
310 with items corresponding to the color names Qt knows about
311 provided by the static QColor::colorNames() function.
312
313 \snippet examples/painting/painterpaths/window.cpp 23
314
315 The \c currentItemData() function simply return the current item
316 of the given combobox.
317
318 \section1 RenderArea Class Definition
319
320 The \c RenderArea class inherits QWidget, and is a custom widget
321 displaying a single painter path.
322
323 \snippet examples/painting/painterpaths/renderarea.h 0
324
325 We declare several public slots updating the \c RenderArea
326 widget's associated painter path. In addition we reimplement the
327 QWidget::minimumSizeHint() and QWidget::sizeHint() functions to
328 give the \c RenderArea widget a reasonable size within our
329 application, and we reimplement the QWidget::paintEvent() event
330 handler to draw its painter path.
331
332 \snippet examples/painting/painterpaths/renderarea.h 1
333
334 Each instance of the \c RenderArea class has a QPainterPath, a
335 couple of fill colors, a pen width, a pen color and a rotation
336 angle.
337
338 \section1 RenderArea Class Implementation
339
340 The constructor takes a QPainterPath as argument (in addition to
341 the optional QWidget parent):
342
343 \snippet examples/painting/painterpaths/renderarea.cpp 0
344
345 In the constructor we initialize the \c RenderArea widget with the
346 QPainterPath parameter as well as initializing the pen width and
347 rotation angle. We also set the widgets \l
348 {QWidget::backgroundRole()}{background role}; QPalette::Base is
349 typically white.
350
351 \snippet examples/painting/painterpaths/renderarea.cpp 1
352 \codeline
353 \snippet examples/painting/painterpaths/renderarea.cpp 2
354
355 Then we reimplement the QWidget::minimumSizeHint() and
356 QWidget::sizeHint() functions to give the \c RenderArea widget a
357 reasonable size within our application.
358
359 \snippet examples/painting/painterpaths/renderarea.cpp 3
360 \codeline
361 \snippet examples/painting/painterpaths/renderarea.cpp 4
362 \codeline
363 \snippet examples/painting/painterpaths/renderarea.cpp 5
364 \codeline
365 \snippet examples/painting/painterpaths/renderarea.cpp 6
366 \codeline
367 \snippet examples/painting/painterpaths/renderarea.cpp 7
368
369 The various public slots updates the \c RenderArea widget's
370 painter path by setting the associated property and make a call to
371 the QWidget::update() function, forcing a repaint of the widget
372 with the new rendering preferences.
373
374 The QWidget::update() slot does not cause an immediate repaint;
375 instead it schedules a paint event for processing when Qt returns
376 to the main event loop.
377
378 \snippet examples/painting/painterpaths/renderarea.cpp 8
379
380 A paint event is a request to repaint all or parts of the
381 widget. The paintEvent() function is an event handler that can be
382 reimplemented to receive the widget's paint events. We reimplement
383 the event handler to render the \c RenderArea widget's painter
384 path.
385
386 First, we create a QPainter for the \c RenderArea instance, and
387 set the painter's render hints. The QPainter::RenderHints are used
388 to specify flags to QPainter that may, or may not, be respected by
389 any given engine. QPainter::Antialiasing indicates that the engine
390 should anti-alias the edges of primitives if possible, i.e. put
391 additional pixels around the original ones to smooth the edges.
392
393 \snippet examples/painting/painterpaths/renderarea.cpp 9
394
395 Then we scale the QPainter's coordinate system to ensure that the
396 painter path is rendered in the right size, i.e that it grows with
397 the \c RenderArea widget when the application is resized. When we
398 constructed the various painter paths, they were all rnedered
399 within a square with a 100 pixel width wich is equivalent to \c
400 RenderArea::sizeHint(). The QPainter::scale() function scales the
401 coordinate system by the \c RenderArea widget's \e current width
402 and height divided by 100.
403
404 Now, when we are sure that the painter path has the right size, we
405 can translate the coordinate system to make the painter path
406 rotate around the \c RenderArea widget's center. After we have
407 performed the rotation, we must remember to translate the
408 coordinate system back again.
409
410 \snippet examples/painting/painterpaths/renderarea.cpp 10
411
412 Then we set the QPainter's pen with the instance's rendering
413 preferences. We create a QLinearGradient and set its colors
414 corresponding to the \c RenderArea widget's fill colors. Finally,
415 we set the QPainter's brush (the gradient is automatically
416 converted into a QBrush), and draw the \c RenderArea widget's
417 painter path using the QPainter::drawPath() function.
418*/
Note: See TracBrowser for help on using the repository browser.