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

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

trunk: Merged in qt 4.6.2 sources.

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