0
|
1 |
/****************************************************************************
|
|
2 |
**
|
|
3 |
** Copyright (C) 2009 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/transformations
|
|
44 |
\title Transformations Example
|
|
45 |
|
|
46 |
The Transformations example shows how transformations influence
|
|
47 |
the way that QPainter renders graphics primitives. In particular
|
|
48 |
it shows how the order of transformations affect the result.
|
|
49 |
|
|
50 |
\image transformations-example.png
|
|
51 |
|
|
52 |
The application allows the user to manipulate the rendering of a
|
|
53 |
shape by changing the translation, rotation and scale of
|
|
54 |
QPainter's coordinate system.
|
|
55 |
|
|
56 |
The example consists of two classes and a global enum:
|
|
57 |
|
|
58 |
\list
|
|
59 |
\o The \c RenderArea class controls the rendering of a given shape.
|
|
60 |
\o The \c Window class is the application's main window.
|
|
61 |
\o The \c Operation enum describes the various transformation
|
|
62 |
operations available in the application.
|
|
63 |
\endlist
|
|
64 |
|
|
65 |
First we will take a quick look at the \c Operation enum, then we
|
|
66 |
will review the \c RenderArea class to see how a shape is
|
|
67 |
rendered. Finally, we will take a look at the Transformations
|
|
68 |
application's features implemented in the \c Window class.
|
|
69 |
|
|
70 |
\section1 Transformation Operations
|
|
71 |
|
|
72 |
Normally, the QPainter operates on the associated device's own
|
|
73 |
coordinate system, but it also has good support for coordinate
|
|
74 |
transformations.
|
|
75 |
|
|
76 |
The default coordinate system of a paint device has its origin at
|
|
77 |
the top-left corner. The x values increase to the right and the y
|
|
78 |
values increase downwards. You can scale the coordinate system by
|
|
79 |
a given offset using the QPainter::scale() function, you can
|
|
80 |
rotate it clockwise using the QPainter::rotate() function and you
|
|
81 |
can translate it (i.e. adding a given offset to the points) using
|
|
82 |
the QPainter::translate() function. You can also twist the
|
|
83 |
coordinate system around the origin (called shearing) using the
|
|
84 |
QPainter::shear() function.
|
|
85 |
|
|
86 |
All the tranformation operations operate on QPainter's
|
|
87 |
tranformation matrix that you can retrieve using the
|
|
88 |
QPainter::worldTransform() function. A matrix transforms a point in the
|
|
89 |
plane to another point. For more information about the
|
|
90 |
transformation matrix, see the \l {The Coordinate System} and
|
|
91 |
QTransform documentation.
|
|
92 |
|
|
93 |
\snippet examples/painting/transformations/renderarea.h 0
|
|
94 |
|
|
95 |
The global \c Operation enum is declared in the \c renderarea.h
|
|
96 |
file and describes the various transformation operations available
|
|
97 |
in the Transformations application.
|
|
98 |
|
|
99 |
\section1 RenderArea Class Definition
|
|
100 |
|
|
101 |
The \c RenderArea class inherits QWidget, and controls the
|
|
102 |
rendering of a given shape.
|
|
103 |
|
|
104 |
\snippet examples/painting/transformations/renderarea.h 1
|
|
105 |
|
|
106 |
We declare two public functions, \c setOperations() and
|
|
107 |
\c setShape(), to be able to specify the \c RenderArea widget's shape
|
|
108 |
and to transform the coordinate system the shape is rendered
|
|
109 |
within.
|
|
110 |
|
|
111 |
We reimplement the QWidget's \l
|
|
112 |
{QWidget::minimumSizeHint()}{minimumSizeHint()} and \l
|
|
113 |
{QWidget::sizeHint()}{sizeHint()} functions to give the \c
|
|
114 |
RenderArea widget a reasonable size within our application, and we
|
|
115 |
reimplement the QWidget::paintEvent() event handler to draw the
|
|
116 |
render area's shape applying the user's transformation choices.
|
|
117 |
|
|
118 |
\snippet examples/painting/transformations/renderarea.h 2
|
|
119 |
|
|
120 |
We also declare several convenience functions to draw the shape,
|
|
121 |
the coordinate system's outline and the coordinates, and to
|
|
122 |
transform the painter according to the chosen transformations.
|
|
123 |
|
|
124 |
In addition, the \c RenderArea widget keeps a list of the
|
|
125 |
currently applied transformation operations, a reference to its
|
|
126 |
shape, and a couple of convenience variables that we will use when
|
|
127 |
rendering the coordinates.
|
|
128 |
|
|
129 |
\section1 RenderArea Class Implementation
|
|
130 |
|
|
131 |
The \c RenderArea widget controls the rendering of a given shape,
|
|
132 |
including the transformations of the coordinate system, by
|
|
133 |
reimplementing the QWidget::paintEvent() event handler. But first
|
|
134 |
we will take a quick look at the constructor and at the functions
|
|
135 |
that provides access to the \c RenderArea widget:
|
|
136 |
|
|
137 |
\snippet examples/painting/transformations/renderarea.cpp 0
|
|
138 |
|
|
139 |
In the constructor we pass the parent parameter on to the base
|
|
140 |
class, and customize the font that we will use to render the
|
|
141 |
coordinates. The QWidget::font() funtion returns the font
|
|
142 |
currently set for the widget. As long as no special font has been
|
|
143 |
set, or after QWidget::setFont() is called, this is either a
|
|
144 |
special font for the widget class, the parent's font or (if this
|
|
145 |
widget is a top level widget) the default application font.
|
|
146 |
|
|
147 |
After ensuring that the font's size is 12 points, we extract the
|
|
148 |
rectangles enclosing the coordinate letters, 'x' and 'y', using the
|
|
149 |
QFontMetrics class.
|
|
150 |
|
|
151 |
QFontMetrics provides functions to access the individual metrics
|
|
152 |
of the font, its characters, and for strings rendered in the
|
|
153 |
font. The QFontMetrics::boundingRect() function returns the
|
|
154 |
bounding rectangle of the given character relative to the
|
|
155 |
left-most point on the base line.
|
|
156 |
|
|
157 |
\snippet examples/painting/transformations/renderarea.cpp 1
|
|
158 |
\codeline
|
|
159 |
\snippet examples/painting/transformations/renderarea.cpp 2
|
|
160 |
|
|
161 |
In the \c setShape() and \c setOperations() functions we update
|
|
162 |
the \c RenderArea widget by storing the new value or values
|
|
163 |
followed by a call to the QWidget::update() slot which schedules a
|
|
164 |
paint event for processing when Qt returns to the main event loop.
|
|
165 |
|
|
166 |
\snippet examples/painting/transformations/renderarea.cpp 3
|
|
167 |
\codeline
|
|
168 |
\snippet examples/painting/transformations/renderarea.cpp 4
|
|
169 |
|
|
170 |
We reimplement the QWidget's \l
|
|
171 |
{QWidget::minimumSizeHint()}{minimumSizeHint()} and \l
|
|
172 |
{QWidget::sizeHint()}{sizeHint()} functions to give the \c
|
|
173 |
RenderArea widget a reasonable size within our application. The
|
|
174 |
default implementations of these functions returns an invalid size
|
|
175 |
if there is no layout for this widget, and returns the layout's
|
|
176 |
minimum size or preferred size, respectively, otherwise.
|
|
177 |
|
|
178 |
\snippet examples/painting/transformations/renderarea.cpp 5
|
|
179 |
|
|
180 |
The \c paintEvent() event handler recieves the \c RenderArea
|
|
181 |
widget's paint events. A paint event is a request to repaint all
|
|
182 |
or part of the widget. It can happen as a result of
|
|
183 |
QWidget::repaint() or QWidget::update(), or because the widget was
|
|
184 |
obscured and has now been uncovered, or for many other reasons.
|
|
185 |
|
|
186 |
First we create a QPainter for the \c RenderArea widget. The \l
|
|
187 |
{QPainter::RenderHint}{QPainter::Antialiasing} render hint
|
|
188 |
indicates that the engine should antialias edges of primitives if
|
|
189 |
possible. Then we erase the area that needs to be repainted using
|
|
190 |
the QPainter::fillRect() function.
|
|
191 |
|
|
192 |
We also translate the coordinate system with an constant offset to
|
|
193 |
ensure that the original shape is renderend with a suitable
|
|
194 |
margin.
|
|
195 |
|
|
196 |
\snippet examples/painting/transformations/renderarea.cpp 6
|
|
197 |
|
|
198 |
Before we start to render the shape, we call the QPainter::save()
|
|
199 |
function.
|
|
200 |
|
|
201 |
QPainter::save() saves the current painter state (i.e. pushes the
|
|
202 |
state onto a stack) including the current coordinate system. The
|
|
203 |
rationale for saving the painter state is that the following call
|
|
204 |
to the \c transformPainter() function will transform the
|
|
205 |
coordinate system depending on the currently chosen transformation
|
|
206 |
operations, and we need a way to get back to the original state to
|
|
207 |
draw the outline.
|
|
208 |
|
|
209 |
After transforming the coordinate system, we draw the \c
|
|
210 |
RenderArea's shape, and then we restore the painter state using
|
|
211 |
the QPainter::restore() function (i.e. popping the saved state off
|
|
212 |
the stack).
|
|
213 |
|
|
214 |
\snippet examples/painting/transformations/renderarea.cpp 7
|
|
215 |
|
|
216 |
Then we draw the square outline.
|
|
217 |
|
|
218 |
\snippet examples/painting/transformations/renderarea.cpp 8
|
|
219 |
|
|
220 |
Since we want the coordinates to correspond with the coordinate
|
|
221 |
system the shape is rendered within, we must make another call to
|
|
222 |
the \c transformPainter() function.
|
|
223 |
|
|
224 |
The order of the painting operations is essential with respect to
|
|
225 |
the shared pixels. The reason why we don't render the coordinates
|
|
226 |
when the coordinate system already is transformed to render the
|
|
227 |
shape, but instead defer their rendering to the end, is that we
|
|
228 |
want the coordinates to appear on top of the shape and its
|
|
229 |
outline.
|
|
230 |
|
|
231 |
There is no need to save the QPainter state this time since
|
|
232 |
drawing the coordinates is the last painting operation.
|
|
233 |
|
|
234 |
\snippet examples/painting/transformations/renderarea.cpp 9
|
|
235 |
\codeline
|
|
236 |
\snippet examples/painting/transformations/renderarea.cpp 10
|
|
237 |
\codeline
|
|
238 |
\snippet examples/painting/transformations/renderarea.cpp 11
|
|
239 |
|
|
240 |
The \c drawCoordinates(), \c drawOutline() and \c drawShape() are
|
|
241 |
convenience functions called from the \c paintEvent() event
|
|
242 |
handler. For more information about QPainter's basic drawing
|
|
243 |
operations and how to display basic graphics primitives, see the
|
|
244 |
\l {painting/basicdrawing}{Basic Drawing} example.
|
|
245 |
|
|
246 |
\snippet examples/painting/transformations/renderarea.cpp 12
|
|
247 |
|
|
248 |
The \c transformPainter() convenience function is also called from
|
|
249 |
the \c paintEvent() event handler, and transforms the given
|
|
250 |
QPainter's coordinate system according to the user's
|
|
251 |
transformation choices.
|
|
252 |
|
|
253 |
\section1 Window Class Definition
|
|
254 |
|
|
255 |
The \c Window class is the Transformations application's main
|
|
256 |
window.
|
|
257 |
|
|
258 |
The application displays four \c RenderArea widgets. The left-most
|
|
259 |
widget renders the shape in QPainter's default coordinate system,
|
|
260 |
the others render the shape with the chosen transformation in
|
|
261 |
addition to all the transformations applied to the \c RenderArea
|
|
262 |
widgets to their left.
|
|
263 |
|
|
264 |
\snippet examples/painting/transformations/window.h 0
|
|
265 |
|
|
266 |
We declare two public slots to make the application able to
|
|
267 |
respond to user interaction, updating the displayed \c RenderArea
|
|
268 |
widgets according to the user's transformation choices.
|
|
269 |
|
|
270 |
The \c operationChanged() slot updates each of the \c RenderArea
|
|
271 |
widgets applying the currently chosen transformation operations, and
|
|
272 |
is called whenever the user changes the selected operations. The
|
|
273 |
\c shapeSelected() slot updates the \c RenderArea widgets' shapes
|
|
274 |
whenever the user changes the preferred shape.
|
|
275 |
|
|
276 |
\snippet examples/painting/transformations/window.h 1
|
|
277 |
|
|
278 |
We also declare a private convenience function, \c setupShapes(),
|
|
279 |
that is used when constructing the \c Window widget, and we
|
|
280 |
declare pointers to the various components of the widget. We
|
|
281 |
choose to keep the available shapes in a QList of \l
|
|
282 |
{QPainterPath}s. In addition we declare a private enum counting
|
|
283 |
the number of displayed \c RenderArea widgets except the widget
|
|
284 |
that renders the shape in QPainter's default coordinate system.
|
|
285 |
|
|
286 |
\section1 Window Class Implementation
|
|
287 |
|
|
288 |
In the constructor we create and initialize the application's
|
|
289 |
components:
|
|
290 |
|
|
291 |
\snippet examples/painting/transformations/window.cpp 0
|
|
292 |
|
|
293 |
First we create the \c RenderArea widget that will render the
|
|
294 |
shape in the default coordinate system. We also create the
|
|
295 |
associated QComboBox that allows the user to choose among four
|
|
296 |
different shapes: A clock, a house, a text and a truck. The shapes
|
|
297 |
themselves are created at the end of the constructor, using the
|
|
298 |
\c setupShapes() convenience function.
|
|
299 |
|
|
300 |
\snippet examples/painting/transformations/window.cpp 1
|
|
301 |
|
|
302 |
Then we create the \c RenderArea widgets that will render their
|
|
303 |
shapes with coordinate tranformations. By default the applied
|
|
304 |
operation is \gui {No Transformation}, i.e. the shapes are
|
|
305 |
rendered within the default coordinate system. We create and
|
|
306 |
initialize the associated \l {QComboBox}es with items
|
|
307 |
corresponding to the various transformation operations decribed by
|
|
308 |
the global \c Operation enum.
|
|
309 |
|
|
310 |
We also connect the \l {QComboBox}es' \l
|
|
311 |
{QComboBox::activated()}{activated()} signal to the \c
|
|
312 |
operationChanged() slot to update the application whenever the
|
|
313 |
user changes the selected transformation operations.
|
|
314 |
|
|
315 |
\snippet examples/painting/transformations/window.cpp 2
|
|
316 |
|
|
317 |
Finally, we set the layout for the application window using the
|
|
318 |
QWidget::setLayout() function, construct the available shapes
|
|
319 |
using the private \c setupShapes() convenience function, and make
|
|
320 |
the application show the clock shape on startup using the public
|
|
321 |
\c shapeSelected() slot before we set the window title.
|
|
322 |
|
|
323 |
|
|
324 |
\snippet examples/painting/transformations/window.cpp 3
|
|
325 |
\snippet examples/painting/transformations/window.cpp 4
|
|
326 |
\snippet examples/painting/transformations/window.cpp 5
|
|
327 |
\snippet examples/painting/transformations/window.cpp 6
|
|
328 |
\dots
|
|
329 |
|
|
330 |
\snippet examples/painting/transformations/window.cpp 7
|
|
331 |
|
|
332 |
The \c setupShapes() function is called from the constructor and
|
|
333 |
create the QPainterPath objects representing the shapes that are
|
|
334 |
used in the application. For construction details, see the \l
|
|
335 |
{painting/transformations/window.cpp}{window.cpp} example
|
|
336 |
file. The shapes are stored in a QList. The QList::append()
|
|
337 |
function inserts the given shape at the end of the list.
|
|
338 |
|
|
339 |
We also connect the associated QComboBox's \l
|
|
340 |
{QComboBox::activated()}{activated()} signal to the \c
|
|
341 |
shapeSelected() slot to update the application when the user
|
|
342 |
changes the preferred shape.
|
|
343 |
|
|
344 |
\snippet examples/painting/transformations/window.cpp 8
|
|
345 |
|
|
346 |
The public \c operationChanged() slot is called whenever the user
|
|
347 |
changes the selected operations.
|
|
348 |
|
|
349 |
We retrieve the chosen transformation operation for each of the
|
|
350 |
transformed \c RenderArea widgets by querying the associated \l
|
|
351 |
{QComboBox}{QComboBoxes}. The transformed \c RenderArea widgets
|
|
352 |
are supposed to render the shape with the transformation specified
|
|
353 |
by its associated combobox \e {in addition to} all the
|
|
354 |
transformations applied to the \c RenderArea widgets to its
|
|
355 |
left. For that reason, for each widget we query, we append the
|
|
356 |
associated operation to a QList of transformations which we apply
|
|
357 |
to the widget before proceeding to the next.
|
|
358 |
|
|
359 |
\snippet examples/painting/transformations/window.cpp 9
|
|
360 |
|
|
361 |
The \c shapeSelected() slot is called whenever the user changes
|
|
362 |
the preferred shape, updating the \c RenderArea widgets using
|
|
363 |
their public \c setShape() function.
|
|
364 |
|
|
365 |
\section1 Summary
|
|
366 |
|
|
367 |
The Transformations example shows how transformations influence
|
|
368 |
the way that QPainter renders graphics primitives. Normally, the
|
|
369 |
QPainter operates on the device's own coordinate system, but it
|
|
370 |
also has good support for coordinate transformations. With the
|
|
371 |
Transformations application you can scale, rotate and translate
|
|
372 |
QPainter's coordinate system. The order in which these
|
|
373 |
tranformations are applied is essential for the result.
|
|
374 |
|
|
375 |
All the tranformation operations operate on QPainter's
|
|
376 |
tranformation matrix. For more information about the
|
|
377 |
transformation matrix, see the \l {The Coordinate System} and
|
|
378 |
QTransform documentation.
|
|
379 |
|
|
380 |
The Qt reference documentation provides several painting
|
|
381 |
demos. Among these is the \l {demos/affine}{Affine
|
|
382 |
Transformations} demo that shows Qt's ability to perform
|
|
383 |
transformations on painting operations. The demo also allows the
|
|
384 |
user to experiment with the various transformation operations.
|
|
385 |
*/
|