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