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
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
|
/****************************************************************************
**
** 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 graphicsview/padnavigator
\title Pad Navigator Example
The Pad Navigator Example shows how you can use Graphics View together with
embedded widgets and Qt's \l{State Machine Framework} to create a simple
but useful, dynamic, animated user interface.
\image padnavigator-example.png
The interface consists of a flippable, rotating pad with icons that can be
selected using the arrow keys on your keyboard or keypad. Pressing enter
will flip the pad around and reveal its back side, which has a form
embedded into a QGraphicsProxyWidget. You can interact with the form, and
press the enter key to flip back to the front side of the pad at any time.
Graphics View provides the QGraphicsScene class for managing and
interacting with a large number of custom-made 2D graphical items derived
from the QGraphicsItem class, and a QGraphicsView widget for visualizing
the items, with support for zooming and rotation.
This example consists of a \c RoundRectItem class, a \c FlippablePad class,
a \c PadNavigator class, a \c SplashItem class, and a \c main() function.
\section1 RoundRectItem Class Definition
The \c RoundRectItem class is used by itself to diplay the icons on the
pad, and as a base class for \c FlippablePad, the class for the pad itself.
The role of the class is to paint a round rectangle of a specified size and
gradient color, and optionally to paint a pixmap icon on top. To support \c
FlippablePad it also allows filling its contents with a plain window
background color.
Let's start by reviewing the \c RoundRectItem class declaration.
\snippet examples/graphicsview/padnavigator/roundrectitem.h 0
\c RoundRectItem inherits QGraphicsObject, which makes it easy to control
its properties using QPropertyAnimation. Its constructor takes a rectangle
to determine its bounds, and a color.
Besides implementing the mandatory \l{QGraphicsItem::paint()}{paint()} and
\l{QGraphicsItem::boundingRect()}{boundingRect()} pure virtual functions,
it also provides the \c pixmap and \c fill properties.
The \c pixmap property sets an optional pixmap that is drawn on top of the
round rectangle. The \c fill property will, when true, fill the round
rectangle contents with a fixed QPalette::Window background color.
Otherwise the contents are filled using a gradient based on the color
passed to \c RoundRectItem's constructor.
\snippet examples/graphicsview/padnavigator/roundrectitem.h 1
The private data members are:
\list
\o \c pix: The optional pixmap that is drawn on top of the rectangle.
\o \c fillRect: Corresponds to the \c fill property.
\o \c color: The configurable gradient color fill of the rectangle.
\o \c bounds: The bounds of the rectangle.
\o \c gradient: A precalculated gradient used to fill the rectangle.
\endlist
We will now review the \c RoundRectItem implementation. Let's start by
looking at its constructor:
\snippet examples/graphicsview/padnavigator/roundrectitem.cpp 0
The constructor initializes its member variables and forwards the \c parent
argument to QGraphicsObject's constructor. It then constructs the linear
gradient that is used in \l{QGraphicsItem::paint()}{paint()} to draw the
round rectangle's gradient background. The linear gradient's starting point
is at the top-left corner of the bounds, and the end is at the bottom-left
corner. The start color is identical to the color passed as an argument,
and a slightly darker color is chosen for the final stop.
We store this gradient as a member variable to avoid having to recreate the
gradient every time the item is repainted.
Finally we set the cache mode
\l{QGraphicsItem::ItemCoordinateCache}{ItemCoordinateCache}. This mode
causes the item's rendering to be cached into an off-screen pixmap that
remains persistent as we move and transform the item. This mode is ideal
for this example, and works particularily well with OpenGL and OpenGL ES.
\snippet examples/graphicsview/padnavigator/roundrectitem.cpp 1
The \c pixmap property implementation simple returns the member pixmap, or
sets it and then calls \l{QGraphicsItem::update()}{update()}.
\snippet examples/graphicsview/padnavigator/roundrectitem.cpp 2
As the \l{QGraphicsItem::paint()}{paint()} implementation below draws a
simple drop shadow down and to the right of the item, we return a slightly
adjusted rectangle from \l{QGraphicsItem::boundingRect()}{boundingRect()}.
\snippet examples/graphicsview/padnavigator/roundrectitem.cpp 3
The \l{QGraphicsItem::paint()}{paint()} implementation starts by rendering
a semi transparent black round rectangle drop shadow, two units down and to
the right of the main item.
\snippet examples/graphicsview/padnavigator/roundrectitem.cpp 4
We then draw the "foreground" round rectangle itself. The fill depends on
the \c fill property; if true, we will with a plain QPalette::Window color.
We get the corrent brush from QApplication::palette(). We assign a single
unit wide pen for the stroke, assign the brush, and then draw the
rectangle.
\snippet examples/graphicsview/padnavigator/roundrectitem.cpp 5
If a pixmap has been assigned to the \e pixmap property, we draw this
pixmap in the center of the rectangle item. The pixmaps are scaled to match
the size of the icons; in arguably a better approach would have been to
store the icons with the right size in the first places.
\snippet examples/graphicsview/padnavigator/roundrectitem.cpp 6
Finally, for completeness we include the \c fill property implementation.
It returns the \c fill member variable's value, and when assigned to, it
calls \l{QGraphicsItem::update()}{update()}.
As mentioned already, \c RoundRectItem is the base class for \c
FlippablePad, which is the class representing the tilting pad itself. We
will proceed to reviewing \c FlippablePad.
\section1 FlippablePad Class Definition
\c FlippablePad is, in addition to its inherited \c RoundRectItem
responsibilities, responsible for creating and managing a grid of icons.
\snippet examples/graphicsview/padnavigator/flippablepad.h 0
Its declaration is very simple: It inherits \c RoundRectItem and does not
need any special polymorphic behavior. It's suitable to declare its own
constructor, and a getter-function that allows \c PadNavigator to access
the icons in the grid by (row, column).
The example has no "real" behavior or logic of any kind, and because of
that, the icons do not need to provide any \e behavior or special
interactions management. In a real application, however, it would be
natural for the \c FlippablePad and its icons to handle more of the
navigation logic. In this example, we have chosen to leave this to
the \c PadNavigator class, which we will get back to below.
We will now review the \c FlippablePad implementation. This implementation
starts with two helper functions: \c boundsFromSize() and \c
posForLocation():
\snippet examples/graphicsview/padnavigator/flippablepad.cpp 0
\c boundsForSize() takes a QSize argument, and returns the bounding
rectangle of the flippable pad item. The QSize determines how many rows and
columns the icon grid should have. Each icon is given 150x150 units of
space, and this determines the bounds.
\snippet examples/graphicsview/padnavigator/flippablepad.cpp 1
\c posForLocation() returns the position of an icon given its row and
column position. Like \c boundsForSize(), the function assumes each icon is
given 150x150 units of space, and that all icons are centered around the
flippable pad item's origin (0, 0).
\snippet examples/graphicsview/padnavigator/flippablepad.cpp 2
The \c FlippablePad constructor passes suitable bounds (using \c
boundsForSize()) and specific color to \c RoundRectItem's constructor.
\snippet examples/graphicsview/padnavigator/flippablepad.cpp 3
It then loads pixmaps from compiled-in resources to use for its icons.
QDirIterator is very useful in this context, as it allows us to fetch all
resource "*.png" files inside the \c :/images directory without explicitly
naming the files.
We also make sure not to load more pixmaps than we need.
\snippet examples/graphicsview/padnavigator/flippablepad.cpp 4
Now that we have the pixmaps, we can create icons, position then and assign
pixmaps. We start by finding a suitable size and color for the icons, and
initializing a convenient grid structure for storing the icons. This \c
iconGrid is also used later to find the icon for a specific (column, row)
location.
For each row and column in our grid, we proceed to constructing each icon
as an instance of \c RoundRectItem. The item is placed by using the \c
posForLocation() helper function. To make room for the slip-behind
selection item, we give each icon a \l{QGraphicsItem::zValue()}{Z-value} of
1. The pixmaps are distributed to the icons in round-robin fasion.
Again, this approach is only suitable for example purposes. In a real-life
application where each icon represents a specific action, it would be more
natural to assign the pixmaps directly, or that the icons themselves
provide suitable pixmaps.
\snippet examples/graphicsview/padnavigator/flippablepad.cpp 5
Finally, the \c iconAt() function returns a pointer to the icon at a
specific row and column. It makes a somewhat bold assumption that the input
is valid, which is fair because the \c PadNavigator class only calls this
function with correct input.
We will now review the \c SplashItem class.
\section1 SplashItem Class Definition
The \c SplashItem class represents the "splash window", a semitransparent
white overlay with text that appears immediately after the application has
started, and disappears after pressing any key. The animation is controlled
by \c PadNavigator; this class is very simple by itself.
\snippet examples/graphicsview/padnavigator/splashitem.h 0
The class declaration shows that \c SplashItem inherits QGraphicsObject to
allow it to be controlled by QPropertyAnimation. It reimplements the
mandatory \l{QGraphicsItem::paint()}{paint()} and
\l{QGraphicsItem::boundingRect()}{boundingRect()} pure virtual functions,
and keeps a \c text member variable which will contain the information text
displayed on this splash item.
Let's look at its implementation.
\snippet examples/graphicsview/padnavigator/splashitem.cpp 0
The constructor forwards to QGraphicsObject as expected, assigns a text
message to the \c text member variable, and enables
\l{QGraphicsItem::DeviceCoordinateCache}{DeviceCoordinateCache}. This cache
mode is suitable because the splash item only moves and is never
transformed, and because it contains text, it's important that it has a
pixel perfect visual appearance (in constrast to
\l{QGraphicsItem::ItemCoordinateCache}{ItemCoordinateCache}, where the
visual appearance is not as good).
We use caching to avoid having to relayout and rerender the text for each
frame. An alterative approach would be to use the new QStaticText class.
\snippet examples/graphicsview/padnavigator/splashitem.cpp 1
\c SplashItem's bounding rectangle is fixed at (400x175).
\snippet examples/graphicsview/padnavigator/splashitem.cpp 2
The \l{QGraphicsItem::paint()}{paint()} implementation draws a clipped
round rectangle with a thick 2-unit border and a semi-transparent white
background. It proceeds to finding a suitable text area by adjusting the
splash item's bounding rectangle with 10 units in each side. The text is
rendered inside this rectangle, with top-left alignment, and with word
wrapping enabled.
The main class now remains. We will proceed to reviewing \c PadNavigator.
\section1 PadNavigator Class Definition
\c PadNavigator represents the main window of our Pad Navigator Example
application. It creates and controls a somewhat complex state machine, and
several animations. Its class declaration is very simple:
\snippet examples/graphicsview/padnavigator/padnavigator.h 0
It inherits QGraphicsView and reimplements only one function:
\l{QGraphicsView::resizeEvent()}{resizeEvent()}, to ensure the scene is
scaled to fit inside the view when resizing the main window.
The \c PadNavigator constructor takes a QSize argument that determines the
number or rows and columns in the grid.
It also keeps a private member instance, \c form, which is the generated
code for the pad's back side item's QGraphicsProxyWidget-embedded form.
\snippet examples/graphicsview/padnavigator/padnavigator.cpp 0
\c PadNavigator's constructor is a bit long. In short, its job is to create
all items, including the \c FlippablePad, the \c SplashItem and the
QGraphicsProxyWidget \c backItem, and then to set up all animations, states
and transitions that control the behavior of the application.
It starts out simple, by forwarding to QGraphicsView's constructor.
\snippet examples/graphicsview/padnavigator/padnavigator.cpp 1
The first item to be created is \c SplashItem. This is going to be a top-level
item in the scene, next to \c FlippablePad, and stacked on top of it, so we
assign it a \l{QGraphicsItem::zValue()}{Z-value} of 1.
\snippet examples/graphicsview/padnavigator/padnavigator.cpp 2
Now we construct the \c FlippablePad item, passing its column-row count to
its constructor.
The pad is constrolled by three transformations, and we create one
QGraphicsRotation object for each of these.
\list
\o \c flipRotation: Rotates the grid around its Qt::YAxis. This rotation is
animated from 0 to 180, and eventually back, when enter is pressed on the
keyboard, flipping the pad around.
\o \c xRotation: Rotates the grid around its Qt::XAxis. This is used to
tilt the pad vertically corresponding to which item is currently selected.
This way, the selected item is always kept in front.
\o \c yRotation: Rotates the grid around its Qt::YAxis. This is used to
tilt the pad horizontally corresponding to which item is selected. This
way, the selected item is always kept in front.
\endlist
The combination of all three rotations is assigned via
QGraphicsItem::setTransformations().
\snippet examples/graphicsview/padnavigator/padnavigator.cpp 3
Now we construct the QGraphicsProxyWidget-embedded \c backItem. The proxy
widget is created as a child of the pad. We create a new QWidget and
populate it with the \c form member. To ensure the \c hostName line edit is
the first to receive input focus when this item is shown, we call
\l{QWidget::setFocus()}{setFocus()} immediately. This will not give the
widget focus right away; it will only prepare the item to automatically
receive focus once it is shown.
The QWidget based form is embedded into the proxy widget. The proxy is
hidden initially; we only want to show it when the pad is rotated at least
90 degrees, and we also rotate the proxy itself by 180 degrees. This way we
give the impression that the proxy widget is "behind" the flipped pad, when
in fact, it's actually \e{on top of it}.
We enable \l{QGraphicsItem::ItemCoordinateCache}{ItemCoordinateCache} to
ensure the flip animation can run smoothly.
\snippet examples/graphicsview/padnavigator/padnavigator.cpp 4
We now create the selection item. This is simply another instance of \c
RoundRectItem that is slightly larger than the icons on the pad. We create
it as an immediate child of the \c FlippablePad, so the selection item is a
sibling to all the icons. By giving it a
\l{QGraphicsItem::zValue()}{Z-value} of 0.5 we ensure it will slide beteen
the pad and its icons.
What follows now is a series of animation initializations.
\snippet examples/graphicsview/padnavigator/padnavigator.cpp 5
We begin with the animations that apply to the splash item. The first
animation, \c smoothSplashMove, ensures that the "y" property of \c splash
will be animated with a 250-millisecond duration
\l{QEasingCurve::InQuad}{InQuad} easing function. \c smoothSplashOpacity
ensures the opacity of \c splash eases in and out in 250 milliseconds.
The values are assigned by \c PadNavigator's state machine, which is
created later.
\snippet examples/graphicsview/padnavigator/padnavigator.cpp 6
These are the animations that control the selection item's movement and the
\c xRotation and \c yRotation QGraphicsRotation objects that tilt the pad.
All animations have a duration of 125 milliseconds, and they all use the
\l{QEasingCurve::InOutQuad}{InOutQuad} easing function.
\snippet examples/graphicsview/padnavigator/padnavigator.cpp 7
We now create the animations that control the flip-effect when you press
the enter key. The main goal is to rotate the pad by 180 degrees or back,
but we also need to make sure the selection item's tilt rotations are reset
back to 0 when the pad is flipped, and restored back to their original
values when flipped back:
\list
\o \c smoothFlipRotation: Animates the main 180 degree rotation of the pad.
\o \c smoothFlipScale: Scales the pad out and then in again while the pad is rotating.
\o \c smoothFlipXRotation: Animates the selection item's X-tilt to 0 and back.
\o \c smoothFlipYRotation: Animates the selection item's Y-tilt to 0 and back.
\o \c flipAnimation: A parallel animation group that ensures all the above animations are run in parallel.
\endlist
All animations are given a 500 millisecond duration and an
\l{QEasingCurve::InOutQuad}{InOutQuad} easing function.
It's worth taking a close look at \c smoothFlipScale. This animation's
start and end values are both 1.0, but at animation step 0.5 the
animation's value is 0.7. This means that after 50% of the animation's
duration, or 250 milliseconds, the pad will be scaled down to 0.7x of its
original size, which gives a great visual effect while flipping.
\snippet examples/graphicsview/padnavigator/padnavigator.cpp 8
This section uses a trick to ensure that certain properties are assigned
precisely when the flip animation passes 50%, or 90 degrees, rotation. In
short, the pad's icons and selection item are all hidden, the pad's \c fill
property is enabled, and \c backItem is shown when flipping over. When
flipping back, the reverse properties are applied.
The way this is achieved is by running a sequential animation in parallel
to the other animations. This sequence, dubbed \c setVariablesSequence,
starts with a 250 millisecond pause, and then executes several animations
with a duration of 0. Each animation will ensure that properties are set
immediate at this point.
This approach can also be used to call functions or set any other
properties at a specific time while an animation is running.
\snippet examples/graphicsview/padnavigator/padnavigator.cpp 9
We will now create the state machine. The whole \c PadNavigator state
machinery is controlled by one single state machine that has a
straight-forward state structure. The state engine itself is created
as a child of the \c PadNavigator itself. We then create three top level
states:
\list
\o \c splashState: The initial state where the splash item is visible.
\o \c frontState: The base state where the splash is gone and we can see
the front side of the pad, and navigate the selection item.
\o \c backState: The flipped state where the \c backItem is visible, and we
can interact with the QGraphicsProxyWidget-embedded form.
\endlist
\snippet examples/graphicsview/padnavigator/padnavigator.cpp 10
Each state assigns specific properties to objects on entry. Most
interesting perhaps is the assignment of the value 0.0 to the pad's \c
flipRotation angle property when in \c frontState, and 180.0 when in \c
backState. At the end of this section we register default animations with
the state engine; these animations will apply to their respective objects
and properties for any state transition. Otherwise it's common to assign
animations to specific transitions.
The \c splashState state is set as the initial state. This is required
before we start the state engine. We proceed with creating some
transitions.
\snippet examples/graphicsview/padnavigator/padnavigator.cpp 11
QEventTransition defines a very flexible transition type. You can use this
class to trigger a transition based on an object receiving an event of a
specific type. In this case, we would like to transition from \c
splashState into \c frontState if \c PadNavigator receives any key press
event (QEvent::KeyPress).
We register the \c splashItem's animations to this transition to ensure they
are used to animate the item's movement and opacity.
\snippet examples/graphicsview/padnavigator/padnavigator.cpp 12
We use QKeyEventTransition to capture specific key events. In this case, we
detect that the user presses Qt::Key_Return or Qt::Key_Enter, and use this
to trigger transitions between \c frontState and backState. We register \c
flipAnimation, our complex parallel animation group, with these
transitions.
We continue by defining the states for each of the icons in the grid.
\snippet examples/graphicsview/padnavigator/padnavigator.cpp 13
We will use state groups to control transitions between icons. Each icon
represents a \e substate of \c frontState. We will then define transitions
between the states by detecting key presses, using QKeyEventTransition.
We start by creating all the substates, and at the same time we create a
temporary grid structure for the states to make it easier to find which
states represents icons that are up, down, left and to the right each
other.
Once the first substate is known, we set this up as the initial substate of
\c frontState. We will use the (0, 0), or top-left, icon for the initial
substate. We initialze the selection item's position to be exactly where
the top-left icon is.
\snippet examples/graphicsview/padnavigator/padnavigator.cpp 14
We can now create four transitions for each icon. Each transition ensures
that we move to the state corresponding to which arrow key has been
pressed. It's clear from this techinique that we could design any other
specific transitions to and from each of the sub states depending on these
and other keys.
\snippet examples/graphicsview/padnavigator/padnavigator.cpp 15
Also, for each of the icons, we assign suitable values to the \c xRotation
and \c yRotation objects' "angle"-properties. If you recall, these
properties "tilt" the pad corresponding to which item is currently
selected. We ensure each icon is invisible when the pad is flipped, and
visible when the pad is not flipped. To ensure the visible property is
assigned at the right time, we add property-controlling animations to the
\c setVariableSequence animation defined earlier.
\snippet examples/graphicsview/padnavigator/padnavigator.cpp 16
We are now finished with all states, transitions, and animations. We now
create the scene that will contain all our items. The scene gets a defined
background pixmap, and we disable item indexing (as most items in this
scene are animated). We add our \c pad item to the scene, and use its
bounding rectangle to fixate the scene rectangle. This rectangle is used by
the view to find a suitable size for the application window.
Then the scene is assigned to the view, or in our case, \c PadNavigator
itself.
\snippet examples/graphicsview/padnavigator/padnavigator.cpp 17
Now that the scene has received its final size, we can position the splash
item at the very top, find its fade-out position, and add it to the scene.
\snippet examples/graphicsview/padnavigator/padnavigator.cpp 18
The view toggles a few necessary properties:
\list
\o It disables its scroll bars - this application has no use for scroll bars.
\o It assigns a minimum size. This is necessary to avoid numerical errors
in our fit-in-view \c resizeEvent() implementation.
\o It sets \l{QGraphicsView::FullViewportUpdate}{FullViewportUpdate}, to
ensure QGraphicsView doesn't spend time figuring out precisely what needs
to be redrawn. This application is very simple - if anything changes,
everything is updated.
\o It enables background caching - this makes no performance difference
with OpenGL, but without OpenGL it avoids unnecessary re-scaling of the
background pixmap.
\o It sets render hints that increase rendering quality.
\o If OpenGL is supported, a QGLWidget viewport is assigned to the view.
\endlist
Finally, we start the state engine.
\snippet examples/graphicsview/padnavigator/padnavigator.cpp 19
The \l{QGraphicsView::resizeEvent()}{resizeEvent()} implementation calls
the base implementation, and then calls QGraphicsView::fitInView() to scale
the scene so that it fits perfectly inside the view.
By resizing the main application window, you can see this effect yourself.
The scene contents grow when you make the window larger, and shrink when
you make it smaller, while keeping the aspect ratio intact.
\section1 The main() Function
\snippet examples/graphicsview/padnavigator/main.cpp 0
The \c main function creates the QApplication instance, uses
Q_INIT_RESOURCE to ensure our compiled-in resources aren't removed by the
linker, and then creates a 3x3 \c PadNavigator instance and shows it.
Our flippable pad shows up with a suitable splash item once control returns
to the event loop.
\section1 Performance Notes
The example uses OpenGL if this is available, to achieve optimal
performance; otherwise perspective tranformations can be quite costly.
Although this example does use QGraphicsProxyWidget to demonstrate
integration of Qt widget components integrated into Graphics View, using
QGraphicsProxyWidget comes with a performance penalty, and is therefore not
recommended for embedded development.
This example uses extensive item caching to avoid rerendering of static
elements, at the expense of graphics memory.
*/
|