summaryrefslogtreecommitdiffstats
path: root/doc/src/examples/transformations.qdoc
blob: 26b558c15fd5074e107eb25a2c7c22b1cf88e63c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:FDL$
** GNU Free Documentation License
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms
** and conditions contained in a signed written agreement between you
** and Nokia.
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

/*!
    \example painting/transformations
    \title Transformations Example

    The Transformations example shows how transformations influence
    the way that QPainter renders graphics primitives. In particular
    it shows how the order of transformations affect the result.

    \image transformations-example.png

    The application allows the user to manipulate the rendering of a
    shape by changing the translation, rotation and scale of
    QPainter's coordinate system.

    The example consists of two classes and a global enum:

    \list
    \o The \c RenderArea class controls the rendering of a given shape.
    \o The \c Window class is the application's main window.
    \o The \c Operation enum describes the various transformation
       operations available in the application.
    \endlist

    First we will take a quick look at the \c Operation enum, then we
    will review the \c RenderArea class to see how a shape is
    rendered. Finally, we will take a look at the Transformations
    application's features implemented in the \c Window class.

    \section1 Transformation Operations

    Normally, the QPainter operates on the associated device's own
    coordinate system, but it also has good support for coordinate
    transformations.

    The default coordinate system of a paint device has its origin at
    the top-left corner. The x values increase to the right and the y
    values increase downwards. You can scale the coordinate system by
    a given offset using the QPainter::scale() function, you can
    rotate it clockwise using the QPainter::rotate() function and you
    can translate it (i.e. adding a given offset to the points) using
    the QPainter::translate() function. You can also twist the
    coordinate system around the origin (called shearing) using the
    QPainter::shear() function.

    All the tranformation operations operate on QPainter's
    tranformation matrix that you can retrieve using the
    QPainter::worldTransform() function. A matrix transforms a point in the
    plane to another point. For more information about the
    transformation matrix, see the \l {Coordinate System} and
    QTransform documentation.

    \snippet examples/painting/transformations/renderarea.h 0

    The global \c Operation enum is declared in the \c renderarea.h
    file and describes the various transformation operations available
    in the Transformations application.

    \section1 RenderArea Class Definition

    The \c RenderArea class inherits QWidget, and controls the
    rendering of a given shape.

    \snippet examples/painting/transformations/renderarea.h 1

    We declare two public functions, \c setOperations() and
    \c setShape(), to be able to specify the \c RenderArea widget's shape
    and to transform the coordinate system the shape is rendered
    within.

    We reimplement the QWidget's \l
    {QWidget::minimumSizeHint()}{minimumSizeHint()} and \l
    {QWidget::sizeHint()}{sizeHint()} functions to give the \c
    RenderArea widget a reasonable size within our application, and we
    reimplement the QWidget::paintEvent() event handler to draw the
    render area's shape applying the user's transformation choices.

    \snippet examples/painting/transformations/renderarea.h 2

    We also declare several convenience functions to draw the shape,
    the coordinate system's outline and the coordinates, and to
    transform the painter according to the chosen transformations.

    In addition, the \c RenderArea widget keeps a list of the
    currently applied transformation operations, a reference to its
    shape, and a couple of convenience variables that we will use when
    rendering the coordinates.

    \section1 RenderArea Class Implementation

    The \c RenderArea widget controls the rendering of a given shape,
    including the transformations of the coordinate system, by
    reimplementing the QWidget::paintEvent() event handler. But first
    we will take a quick look at the constructor and at the functions
    that provides access to the \c RenderArea widget:

    \snippet examples/painting/transformations/renderarea.cpp 0

    In the constructor we pass the parent parameter on to the base
    class, and customize the font that we will use to render the
    coordinates. The QWidget::font() funtion returns the font
    currently set for the widget. As long as no special font has been
    set, or after QWidget::setFont() is called, this is either a
    special font for the widget class, the parent's font or (if this
    widget is a top level widget) the default application font.

    After ensuring that the font's size is 12 points, we extract the
    rectangles enclosing the coordinate letters, 'x' and 'y',  using the
    QFontMetrics class.

    QFontMetrics provides functions to access the individual metrics
    of the font, its characters, and for strings rendered in the
    font. The QFontMetrics::boundingRect() function returns the
    bounding rectangle of the given character relative to the
    left-most point on the base line.

    \snippet examples/painting/transformations/renderarea.cpp 1
    \codeline
    \snippet examples/painting/transformations/renderarea.cpp 2

    In the \c setShape() and \c setOperations() functions we update
    the \c RenderArea widget by storing the new value or values
    followed by a call to the QWidget::update() slot which schedules a
    paint event for processing when Qt returns to the main event loop.

    \snippet examples/painting/transformations/renderarea.cpp 3
    \codeline
    \snippet examples/painting/transformations/renderarea.cpp 4

    We reimplement the QWidget's \l
    {QWidget::minimumSizeHint()}{minimumSizeHint()} and \l
    {QWidget::sizeHint()}{sizeHint()} functions to give the \c
    RenderArea widget a reasonable size within our application. The
    default implementations of these functions returns an invalid size
    if there is no layout for this widget, and returns the layout's
    minimum size or preferred size, respectively, otherwise.

    \snippet examples/painting/transformations/renderarea.cpp 5

    The \c paintEvent() event handler recieves the \c RenderArea
    widget's paint events. A paint event is a request to repaint all
    or part of the widget. It can happen as a result of
    QWidget::repaint() or QWidget::update(), or because the widget was
    obscured and has now been uncovered, or for many other reasons.

    First we create a QPainter for the \c RenderArea widget. The \l
    {QPainter::RenderHint}{QPainter::Antialiasing} render hint
    indicates that the engine should antialias edges of primitives if
    possible. Then we erase the area that needs to be repainted using
    the QPainter::fillRect() function.

    We also translate the coordinate system with an constant offset to
    ensure that the original shape is renderend with a suitable
    margin.

    \snippet examples/painting/transformations/renderarea.cpp 6

    Before we start to render the shape, we call the QPainter::save()
    function.

    QPainter::save() saves the current painter state (i.e. pushes the
    state onto a stack) including the current coordinate system. The
    rationale for saving the painter state is that the following call
    to the \c transformPainter() function will transform the
    coordinate system depending on the currently chosen transformation
    operations, and we need a way to get back to the original state to
    draw the outline.

    After transforming the coordinate system, we draw the \c
    RenderArea's shape, and then we restore the painter state using
    the QPainter::restore() function (i.e. popping the saved state off
    the stack).

    \snippet examples/painting/transformations/renderarea.cpp 7

    Then we draw the square outline.

    \snippet examples/painting/transformations/renderarea.cpp 8

    Since we want the coordinates to correspond with the coordinate
    system the shape is rendered within, we must make another call to
    the \c transformPainter() function.

    The order of the painting operations is essential with respect to
    the shared pixels. The reason why we don't render the coordinates
    when the coordinate system already is transformed to render the
    shape, but instead defer their rendering to the end, is that we
    want the coordinates to appear on top of the shape and its
    outline.

    There is no need to save the QPainter state this time since
    drawing the coordinates is the last painting operation.

    \snippet examples/painting/transformations/renderarea.cpp 9
    \codeline
    \snippet examples/painting/transformations/renderarea.cpp 10
    \codeline
    \snippet examples/painting/transformations/renderarea.cpp 11

    The \c drawCoordinates(), \c drawOutline() and \c drawShape() are
    convenience functions called from the \c paintEvent() event
    handler. For more information about QPainter's basic drawing
    operations and how to display basic graphics primitives, see the
    \l {painting/basicdrawing}{Basic Drawing} example.

    \snippet examples/painting/transformations/renderarea.cpp 12

    The \c transformPainter() convenience function is also called from
    the \c paintEvent() event handler, and transforms the given
    QPainter's coordinate system according to the user's
    transformation choices.

    \section1 Window Class Definition

    The \c Window class is the Transformations application's main
    window.

    The application displays four \c RenderArea widgets. The left-most
    widget renders the shape in QPainter's default coordinate system,
    the others render the shape with the chosen transformation in
    addition to all the transformations applied to the \c RenderArea
    widgets to their left.

    \snippet examples/painting/transformations/window.h 0

    We declare two public slots to make the application able to
    respond to user interaction, updating the displayed \c RenderArea
    widgets according to the user's transformation choices.

    The \c operationChanged() slot updates each of the \c RenderArea
    widgets applying the currently chosen transformation operations, and
    is called whenever the user changes the selected operations. The
    \c shapeSelected() slot updates the \c RenderArea widgets' shapes
    whenever the user changes the preferred shape.

    \snippet examples/painting/transformations/window.h 1

    We also declare a private convenience function, \c setupShapes(),
    that is used when constructing the \c Window widget, and we
    declare pointers to the various components of the widget. We
    choose to keep the available shapes in a QList of \l
    {QPainterPath}s. In addition we declare a private enum counting
    the number of displayed \c RenderArea widgets except the widget
    that renders the shape in QPainter's default coordinate system.

    \section1 Window Class Implementation

    In the constructor we create and initialize the application's
    components:

    \snippet examples/painting/transformations/window.cpp 0

    First we create the \c RenderArea widget that will render the
    shape in the default coordinate system. We also create the
    associated QComboBox that allows the user to choose among four
    different shapes: A clock, a house, a text and a truck. The shapes
    themselves are created at the end of the constructor, using the
    \c setupShapes() convenience function.

    \snippet examples/painting/transformations/window.cpp 1

    Then we create the \c RenderArea widgets that will render their
    shapes with coordinate tranformations. By default the applied
    operation is \gui {No Transformation}, i.e. the shapes are
    rendered within the default coordinate system. We create and
    initialize the associated \l {QComboBox}es with items
    corresponding to the various transformation operations decribed by
    the global \c Operation enum.

    We also connect the \l {QComboBox}es' \l
    {QComboBox::activated()}{activated()} signal to the \c
    operationChanged() slot to update the application whenever the
    user changes the selected transformation operations.

    \snippet examples/painting/transformations/window.cpp 2

    Finally, we set the layout for the application window using the
    QWidget::setLayout() function, construct the available shapes
    using the private \c setupShapes() convenience function, and make
    the application show the clock shape on startup using the public
    \c shapeSelected() slot before we set the window title.


    \snippet examples/painting/transformations/window.cpp 3
    \snippet examples/painting/transformations/window.cpp 4
    \snippet examples/painting/transformations/window.cpp 5
    \snippet examples/painting/transformations/window.cpp 6
    \dots

    \snippet examples/painting/transformations/window.cpp 7

    The \c setupShapes() function is called from the constructor and
    create the QPainterPath objects representing the shapes that are
    used in the application. For construction details, see the \l
    {painting/transformations/window.cpp}{window.cpp} example
    file. The shapes are stored in a QList. The QList::append()
    function inserts the given shape at the end of the list.

    We also connect the associated QComboBox's \l
    {QComboBox::activated()}{activated()} signal to the \c
    shapeSelected() slot to update the application when the user
    changes the preferred shape.

    \snippet examples/painting/transformations/window.cpp 8

    The public \c operationChanged() slot is called whenever the user
    changes the selected operations.

    We retrieve the chosen transformation operation for each of the
    transformed \c RenderArea widgets by querying the associated \l
    {QComboBox}{QComboBoxes}. The transformed \c RenderArea widgets
    are supposed to render the shape with the transformation specified
    by its associated combobox \e {in addition to} all the
    transformations applied to the \c RenderArea widgets to its
    left. For that reason, for each widget we query, we append the
    associated operation to a QList of transformations which we apply
    to the widget before proceeding to the next.

    \snippet examples/painting/transformations/window.cpp 9

    The \c shapeSelected() slot is called whenever the user changes
    the preferred shape, updating the \c RenderArea widgets using
    their public \c setShape() function.

    \section1 Summary

    The Transformations example shows how transformations influence
    the way that QPainter renders graphics primitives. Normally, the
    QPainter operates on the device's own coordinate system, but it
    also has good support for coordinate transformations. With the
    Transformations application you can scale, rotate and translate
    QPainter's coordinate system.  The order in which these
    tranformations are applied is essential for the result.

    All the tranformation operations operate on QPainter's
    tranformation matrix. For more information about the
    transformation matrix, see the \l {Coordinate System} and
    QTransform documentation.

    The Qt reference documentation provides several painting
    demos. Among these is the \l {demos/affine}{Affine
    Transformations} demo that shows Qt's ability to perform
    transformations on painting operations. The demo also allows the
    user to experiment with the various transformation operations.
*/