source: trunk/doc/src/examples/basicdrawing.qdoc@ 357

Last change on this file since 357 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 20.4 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information (qt-info@nokia.com)
5**
6** This file is part of the documentation of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** 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 are unsure which license is appropriate for your use, please
37** contact the sales department at qt-sales@nokia.com.
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*/
Note: See TracBrowser for help on using the repository browser.