|
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 sql/drilldown |
|
44 \title Drill Down Example |
|
45 |
|
46 The Drill Down example shows how to read data from a database as |
|
47 well as submit changes, using the QSqlRelationalTableModel and |
|
48 QDataWidgetMapper classes. |
|
49 |
|
50 \image drilldown-example.png Screenshot of the Drill Down Example |
|
51 |
|
52 When running the example application, a user can retrieve |
|
53 information about each of Nokia's Qt offices by clicking the |
|
54 corresponding image. The application pops up an information window |
|
55 displaying the data, and allows the users to alter the location |
|
56 description as well as the image. The main view will be updated |
|
57 when the users submit their changes. |
|
58 |
|
59 The example consists of three classes: |
|
60 |
|
61 \list |
|
62 \o \c ImageItem is a custom graphics item class used to |
|
63 display the office images. |
|
64 |
|
65 \o \c View is the main application widget allowing the user to |
|
66 browse through the various locations. |
|
67 |
|
68 \o \c InformationWindow displays the requested information, |
|
69 allowing the users to alter it and submit their changes to the |
|
70 database. |
|
71 \endlist |
|
72 |
|
73 We will first take a look at the \c InformationWindow class to see |
|
74 how you can read and modify data from a database. Then we will |
|
75 review the main application widget, i.e., the \c View class, and |
|
76 the associated \c ImageItem class. |
|
77 |
|
78 \section1 InformationWindow Class Definition |
|
79 |
|
80 The \c InformationWindow class is a custom widget inheriting |
|
81 QWidget: |
|
82 |
|
83 \snippet examples/sql/drilldown/informationwindow.h 0 |
|
84 |
|
85 When we create an information window, we pass the associated |
|
86 location ID, a parent, and a pointer to the database, to the |
|
87 constructor. We will use the database pointer to populate our |
|
88 window with data, while passing the parent parameter on to the |
|
89 base class. The ID is stored for future reference. |
|
90 |
|
91 Once a window is created, we will use the public \c id() function |
|
92 to locate it whenever information for the given location is |
|
93 requested. We will also use the ID to update the main application |
|
94 widget when the users submit their changes to the database, i.e., |
|
95 we will emit a signal carrying the ID and file name as parameters |
|
96 whenever the users changes the associated image. |
|
97 |
|
98 \snippet examples/sql/drilldown/informationwindow.h 1 |
|
99 |
|
100 Since we allow the users to alter some of the location data, we |
|
101 must provide functionality for reverting and submitting their |
|
102 changes. The \c enableButtons() slot is provided for convenience |
|
103 to enable and disable the various buttons when required. |
|
104 |
|
105 \snippet examples/sql/drilldown/informationwindow.h 2 |
|
106 |
|
107 The \c createButtons() function is also a convenience function, |
|
108 provided to simplify the constructor. As mentioned above we store |
|
109 the location ID for future reference. We also store the name of |
|
110 the currently displayed image file to be able to determine when to |
|
111 emit the \c imageChanged() signal. |
|
112 |
|
113 The information window uses the QLabel class to display the office |
|
114 location and the country. The associated image file is displayed |
|
115 using a QComboBox instance while the description is displayed using |
|
116 QTextEdit. In addition, the window has three buttons to control |
|
117 the data flow and whether the window is shown or not. |
|
118 |
|
119 Finally, we declare a \e mapper. The QDataWidgetMapper class |
|
120 provides mapping between a section of a data model to widgets. We |
|
121 will use the mapper to extract data from the given database, |
|
122 updating the database whenever the user modifies the data. |
|
123 |
|
124 \section1 InformationWindow Class Implementation |
|
125 |
|
126 The constructor takes three arguments: a location ID, a database |
|
127 pointer and a parent widget. The database pointer is actually a |
|
128 pointer to a QSqlRelationalTableModel object providing an editable |
|
129 data model (with foreign key support) for our database table. |
|
130 |
|
131 \snippet examples/sql/drilldown/informationwindow.cpp 0 |
|
132 \snippet examples/sql/drilldown/informationwindow.cpp 1 |
|
133 |
|
134 First we create the various widgets required to display the data |
|
135 contained in the database. Most of the widgets are created in a |
|
136 straight forward manner. But note the combobox displaying the |
|
137 name of the image file: |
|
138 |
|
139 \snippet examples/sql/drilldown/informationwindow.cpp 2 |
|
140 |
|
141 In this example, the information about the offices are stored in a |
|
142 database table called "offices". When creating the model, |
|
143 we will use a foreign key to establish a relation between this |
|
144 table and a second data base table, "images", containing the names |
|
145 of the available image files. We will get back to how this is done |
|
146 when reviewing the \c View class. The rationale for creating such |
|
147 a relation though, is that we want to ensure that the user only |
|
148 can choose between predefined image files. |
|
149 |
|
150 The model corresponding to the "images" database table, is |
|
151 available through the QSqlRelationalTableModel's \l |
|
152 {QSqlRelationalTableModel::}{relationModel()} function, requiring |
|
153 the foreign key (in this case the "imagefile" column number) as |
|
154 argument. We use QComboBox's \l {QComboBox::}{setModel()} function |
|
155 to make the combobox use the "images" model. And, since this model |
|
156 has two columns ("locationid" and "file"), we also specify which |
|
157 column we want to be visible using the QComboBox::setModelColumn() |
|
158 function. |
|
159 |
|
160 \snippet examples/sql/drilldown/informationwindow.cpp 3 |
|
161 |
|
162 Then we create the mapper. The QDataWidgetMapper class allows us |
|
163 to create data-aware widgets by mapping them to sections of an |
|
164 item model. |
|
165 |
|
166 The \l {QDataWidgetMapper::}{addMapping()} function adds a mapping |
|
167 between the given widget and the specified section of the |
|
168 model. If the mapper's orientation is horizontal (the default) the |
|
169 section is a column in the model, otherwise it is a row. We call |
|
170 the \l {QDataWidgetMapper::}{setCurrentIndex()} function to |
|
171 initialize the widgets with the data associated with the given |
|
172 location ID. Every time the current index changes, all the widgets |
|
173 are updated with the contents from the model. |
|
174 |
|
175 We also set the mapper's submit policy to |
|
176 QDataWidgetMapper::ManualSubmit. This means that no data is |
|
177 submitted to the database until the user expliclity requests a |
|
178 submit (the alternative is QDataWidgetMapper::AutoSubmit, |
|
179 automatically submitting changes when the corresponding widget |
|
180 looses focus). Finally, we specify the item delegate the mapper |
|
181 view should use for its items. The QSqlRelationalDelegate class |
|
182 represents a delegate that unlike the default delegate, enables |
|
183 combobox functionality for fields that are foreign keys into other |
|
184 tables (like "imagefile" in our "trolltechoffices" table). |
|
185 |
|
186 \snippet examples/sql/drilldown/informationwindow.cpp 4 |
|
187 |
|
188 Finally, we connect the "something's changed" signals in the |
|
189 editors to our custom \c enableButtons() slot, enabling the users |
|
190 to either submit or revert their changes. We add all the widgets |
|
191 into a layout, store the location ID and the name of the displayed |
|
192 image file for future reference, and set the window title and |
|
193 initial size. |
|
194 |
|
195 Note that we also set the Qt::Window window flag to indicate that |
|
196 our widget is in fact a window, with a window system frame and a |
|
197 title bar. |
|
198 |
|
199 \snippet examples/sql/drilldown/informationwindow.cpp 5 |
|
200 |
|
201 When a window is created, it is not deleted until the main |
|
202 application exits (i.e., if the user closes the information |
|
203 window, it is only hidden). For this reason we do not want to |
|
204 create more than one \c InformationWindow object for each |
|
205 location, and we provide the public \c id() function to be able to |
|
206 determine whether a window already exists for a given location |
|
207 when the user requests information about it. |
|
208 |
|
209 \snippet examples/sql/drilldown/informationwindow.cpp 6 |
|
210 |
|
211 The \c revert() slot is triggered whenever the user hits the \gui |
|
212 Revert button. |
|
213 |
|
214 Since we set the QDataWidgetMapper::ManualSubmit submit policy, |
|
215 none of the user's changes are written back to the model unless |
|
216 the user expliclity choose to submit all of them. Nevertheless, we |
|
217 can use the QDataWidgetMapper's \l {QDataWidgetMapper::}{revert()} |
|
218 slot to reset the editor widgets, repopulating all widgets with |
|
219 the current data of the model. |
|
220 |
|
221 \snippet examples/sql/drilldown/informationwindow.cpp 7 |
|
222 |
|
223 Likewise, the \c submit() slot is triggered whenever the users |
|
224 decide to submit their changes by pressing the \gui Submit button. |
|
225 |
|
226 We use QDataWidgetMapper's \l {QDataWidgetMapper::}{submit()} slot |
|
227 to submit all changes from the mapped widgets to the model, |
|
228 i.e. to the database. For every mapped section, the item delegate |
|
229 will then read the current value from the widget and set it in the |
|
230 model. Finally, the \e model's \l {QAbstractItemModel::}{submit()} |
|
231 function is invoked to let the model know that it should submit |
|
232 whatever it has cached to the permanent storage. |
|
233 |
|
234 Note that before any data is submitted, we check if the user has |
|
235 chosen another image file using the previously stored \c |
|
236 displayedImage variable as reference. If the current and stored |
|
237 file names differ, we store the new file name and emit the \c |
|
238 imageChanged() signal. |
|
239 |
|
240 \snippet examples/sql/drilldown/informationwindow.cpp 8 |
|
241 |
|
242 The \c createButtons() function is provided for convenience, i.e., |
|
243 to simplify the constructor. |
|
244 |
|
245 We make the \gui Close button the default button, i.e., the button |
|
246 that is pressed when the user presses \gui Enter, and connect its |
|
247 \l {QPushButton::}{clicked()} signal to the widget's \l |
|
248 {QWidget::}{close()} slot. As mentioned above closing the window |
|
249 only hides the widget; it is not deleted. We also connect the \gui |
|
250 Submit and \gui Revert buttons to the corresponding \c submit() |
|
251 and \c revert() slots. |
|
252 |
|
253 \snippet examples/sql/drilldown/informationwindow.cpp 9 |
|
254 |
|
255 The QDialogButtonBox class is a widget that presents buttons in a |
|
256 layout that is appropriate to the current widget style. Dialogs |
|
257 like our information window, typically present buttons in a layout |
|
258 that conforms to the interface guidelines for that |
|
259 platform. Invariably, different platforms have different layouts |
|
260 for their dialogs. QDialogButtonBox allows us to add buttons, |
|
261 automatically using the appropriate layout for the user's desktop |
|
262 environment. |
|
263 |
|
264 Most buttons for a dialog follow certain roles. We give the \gui |
|
265 Submit and \gui Revert buttons the \l |
|
266 {QDialogButtonBox::ButtonRole}{reset} role, i.e., indicating that |
|
267 pressing the button resets the fields to the default values (in |
|
268 our case the information contained in the database). The \l |
|
269 {QDialogButtonBox::ButtonRole}{reject} role indicates that |
|
270 clicking the button causes the dialog to be rejected. On the other |
|
271 hand, since we only hide the information window, any changes that |
|
272 the user has made wil be preserved until the user expliclity |
|
273 revert or submit them. |
|
274 |
|
275 \snippet examples/sql/drilldown/informationwindow.cpp 10 |
|
276 |
|
277 The \c enableButtons() slot is called to enable the buttons |
|
278 whenever the user changes the presented data. Likewise, when the |
|
279 data the user choose to submit the changes, the buttons are |
|
280 disabled to indicate that the current data is stored in the |
|
281 database. |
|
282 |
|
283 This completes the \c InformationWindow class. Let's take a look |
|
284 at how we have used it in our example application. |
|
285 |
|
286 \section1 View Class Definition |
|
287 |
|
288 The \c View class represents the main application window and |
|
289 inherits QGraphicsView: |
|
290 |
|
291 \snippet examples/sql/drilldown/view.h 0 |
|
292 \codeline |
|
293 \snippet examples/sql/drilldown/view.h 1 |
|
294 |
|
295 The QGraphicsView class is part of the \l {The Graphics View |
|
296 Framework} which we will use to display the images of Nokia's |
|
297 Qt offices. To be able to respond to user interaction; |
|
298 i.e., showing the |
|
299 appropriate information window whenever the user clicks one of the |
|
300 office images, we reimplement QGraphicsView's \l |
|
301 {QGraphicsView::}{mouseReleaseEvent()} function. |
|
302 |
|
303 Note that the constructor expects the names of two database |
|
304 tables: One containing the detailed information about the offices, |
|
305 and another containing the names of the available image files. We |
|
306 also provide a private \c updateImage() slot to catch \c |
|
307 {InformationWindow}'s \c imageChanged() signal that is emitted |
|
308 whenever the user changes a location's image. |
|
309 |
|
310 \snippet examples/sql/drilldown/view.h 2 |
|
311 |
|
312 The \c addItems() function is a convenience function provided to |
|
313 simplify the constructor. It is called only once, creating the |
|
314 various items and adding them to the view. |
|
315 |
|
316 The \c findWindow() function, on the other hand, is frequently |
|
317 used. It is called from the \c showInformation() function to |
|
318 detemine whether a window is already created for the given |
|
319 location (whenever we create an \c InformationWindow object, we |
|
320 store a reference to it in the \c informationWindows list). The |
|
321 latter function is in turn called from our custom \c |
|
322 mouseReleaseEvent() implementation. |
|
323 |
|
324 \snippet examples/sql/drilldown/view.h 3 |
|
325 |
|
326 Finally we declare a QSqlRelationalTableModel pointer. As |
|
327 previously mentioned, the QSqlRelationalTableModel class provides |
|
328 an editable data model with foreign key support. There are a |
|
329 couple of things you should keep in mind when using the |
|
330 QSqlRelationalTableModel class: The table must have a primary key |
|
331 declared and this key cannot contain a relation to another table, |
|
332 i.e., it cannot be a foreign key. Note also that if a relational |
|
333 table contains keys that refer to non-existent rows in the |
|
334 referenced table, the rows containing the invalid keys will not be |
|
335 exposed through the model. It is the user's or the database's |
|
336 responsibility to maintain referential integrity. |
|
337 |
|
338 \section1 View Class Implementation |
|
339 |
|
340 Although the constructor requests the names of both the table |
|
341 containing office details as well as the table containing the |
|
342 names of the available image files, we only have to create a |
|
343 QSqlRelationalTableModel object for the office table: |
|
344 |
|
345 \snippet examples/sql/drilldown/view.cpp 0 |
|
346 |
|
347 The reason is that once we have a model with the office details, |
|
348 we can create a relation to the available image files using |
|
349 QSqlRelationalTableModel's \l |
|
350 {QSqlRelationalTableModel::}{setRelation()} function. This |
|
351 function creates a foreign key for the given model column. The key |
|
352 is specified by the provided QSqlRelation object constructed by |
|
353 the name of the table the key refers to, the field the key is |
|
354 mapping to and the field that should be presented to the user. |
|
355 |
|
356 Note that setting the table only specifies which table the model |
|
357 operates on, i.e., we must explicitly call the model's \l |
|
358 {QSqlRelationalTableModel::}{select()} function to populate our |
|
359 model. |
|
360 |
|
361 \snippet examples/sql/drilldown/view.cpp 1 |
|
362 |
|
363 Then we create the contents of our view, i.e., the scene and its |
|
364 items. The location labels are regular QGraphicsTextItem objects, |
|
365 and the "Qt" logo is represented by a QGraphicsPixmapItem |
|
366 object. The images, on the other hand, are instances of the \c |
|
367 ImageItem class (derived from QGraphicsPixmapItem). We will get |
|
368 back to this shortly when reviewing the \c addItems() function. |
|
369 |
|
370 Finally, we set the main application widget's size constraints and |
|
371 window title. |
|
372 |
|
373 \snippet examples/sql/drilldown/view.cpp 3 |
|
374 |
|
375 The \c addItems() function is called only once, i.e., when |
|
376 creating the main application window. For each row in the database |
|
377 table, we first extract the corresponding record using the model's |
|
378 \l {QSqlRelationalTableModel::}{record()} function. The QSqlRecord |
|
379 class encapsulates both the functionality and characteristics of a |
|
380 database record, and supports adding and removing fields as well |
|
381 as setting and retrieving field values. The QSqlRecord::value() |
|
382 function returns the value of the field with the given name or |
|
383 index as a QVariant object. |
|
384 |
|
385 For each record, we create a label item as well as an image item, |
|
386 calculate their position and add them to the scene. The image |
|
387 items are represented by instances of the \c ImageItem class. The |
|
388 reason we must create a custom item class is that we want to catch |
|
389 the item's hover events, animating the item when the mouse cursor |
|
390 is hovering over the image (by default, no items accept hover |
|
391 events). Please see the \l{The Graphics View Framework} |
|
392 documentation and the \l{Graphics View Examples} for more details. |
|
393 |
|
394 \snippet examples/sql/drilldown/view.cpp 5 |
|
395 |
|
396 We reimplement QGraphicsView's \l |
|
397 {QGraphicsView::}{mouseReleaseEvent()} event handler to respond to |
|
398 user interaction. If the user clicks any of the image items, this |
|
399 function calls the private \c showInformation() function to pop up |
|
400 the associated information window. |
|
401 |
|
402 \l {The Graphics View Framework} provides the qgraphicsitem_cast() |
|
403 function to determine whether the given QGraphicsItem instance is |
|
404 of a given type. Note that if the event is not related to any of |
|
405 our image items, we pass it on to the base class implementation. |
|
406 |
|
407 \snippet examples/sql/drilldown/view.cpp 6 |
|
408 |
|
409 The \c showInformation() function is given an \c ImageItem object |
|
410 as argument, and starts off by extracting the item's location |
|
411 ID. Then it determines if there already is created an information |
|
412 window for this location. If it is, and the window is visible, it |
|
413 ensures that the window is raised to the top of the widget stack |
|
414 and activated. If the window exists but is hidden, calling its \l |
|
415 {QWidget::}{show()} slot gives the same result. |
|
416 |
|
417 If no window for the given location exists, we create one by |
|
418 passing the location ID, a pointer to the model, and our view as a |
|
419 parent, to the \c InformationWindow constructor. Note that we |
|
420 connect the information window's \c imageChanged() signal to \e |
|
421 this widget's \c updateImage() slot, before we give it a suitable |
|
422 position and add it to the list of existing windows. |
|
423 |
|
424 \snippet examples/sql/drilldown/view.cpp 7 |
|
425 |
|
426 The \c updateImage() slot takes a location ID and the name of an |
|
427 image files as arguments. It filters out the image items, and |
|
428 updates the one that correspond to the given location ID, with the |
|
429 provided image file. |
|
430 |
|
431 \snippet examples/sql/drilldown/view.cpp 8 |
|
432 |
|
433 The \c findWindow() function simply searches through the list of |
|
434 existing windows, returning a pointer to the window that matches |
|
435 the given location ID, or 0 if the window doesn't exists. |
|
436 |
|
437 Finally, let's take a quick look at our custom \c ImageItem class: |
|
438 |
|
439 \section1 ImageItem Class Definition |
|
440 |
|
441 The \c ImageItem class is provided to facilitate animation of the |
|
442 image items. It inherits QGraphicsPixmapItem and reimplements its |
|
443 hover event handlers: |
|
444 |
|
445 \snippet examples/sql/drilldown/imageitem.h 0 |
|
446 |
|
447 In addition, we implement a public \c id() function to be able to |
|
448 identify the associated location and a public \c adjust() function |
|
449 that can be called to ensure that the image item is given the |
|
450 preferred size regardless of the original image file. |
|
451 |
|
452 The animation is implemented using the QTimeLine class together |
|
453 with the event handlers and the private \c setFrame() slot: The |
|
454 image item will expand when the mouse cursor hovers over it, |
|
455 returning back to its orignal size when the cursor leaves its |
|
456 borders. |
|
457 |
|
458 Finally, we store the location ID that this particular record is |
|
459 associated with as well as a z-value. In the \l {The Graphics View |
|
460 Framework}, an item's z-value determines its position in the item |
|
461 stack. An item of high Z-value will be drawn on top of an item |
|
462 with a lower z-value if they share the same parent item. We also |
|
463 provide an \c updateItemPosition() function to refresh the view |
|
464 when required. |
|
465 |
|
466 \section1 ImageItem Class Implementation |
|
467 |
|
468 The \c ImageItem class is really only a QGraphicsPixmapItem with |
|
469 some additional features, i.e., we can pass most of the |
|
470 constructor's arguments (the pixmap, parent and scene) on to the |
|
471 base class constructor: |
|
472 |
|
473 \snippet examples/sql/drilldown/imageitem.cpp 0 |
|
474 |
|
475 Then we store the ID for future reference, and ensure that our |
|
476 item will accept hover events. Hover events are delivered when |
|
477 there is no current mouse grabber item. They are sent when the |
|
478 mouse cursor enters an item, when it moves around inside the item, |
|
479 and when the cursor leaves an item. As we mentioned earlier, none |
|
480 of the \l {The Graphics View Framework}'s items accept hover |
|
481 event's by default. |
|
482 |
|
483 The QTimeLine class provides a timeline for controlling |
|
484 animations. Its \l {QTimeLine::}{duration} property holds the |
|
485 total duration of the timeline in milliseconds. By default, the |
|
486 time line runs once from the beginning and towards the end. The |
|
487 QTimeLine::setFrameRange() function sets the timeline's frame |
|
488 counter; when the timeline is running, the \l |
|
489 {QTimeLine::}{frameChanged()} signal is emitted each time the |
|
490 frame changes. We set the duration and frame range for our |
|
491 animation, and connect the time line's \l |
|
492 {QTimeLine::}{frameChanged()} and \l {QTimeLine::}{finished()} |
|
493 signals to our private \c setFrame() and \c updateItemPosition() |
|
494 slots. |
|
495 |
|
496 Finally, we call \c adjust() to ensure that the item is given the |
|
497 preferred size. |
|
498 |
|
499 \snippet examples/sql/drilldown/imageitem.cpp 1 |
|
500 \codeline |
|
501 \snippet examples/sql/drilldown/imageitem.cpp 2 |
|
502 |
|
503 Whenever the mouse cursor enters or leave the image item, the |
|
504 corresponding event handlers are triggered: We first set the time |
|
505 line's direction, making the item expand or shrink, |
|
506 respectively. Then we alter the item's z-value if it is not already |
|
507 set to the expected value. |
|
508 |
|
509 In the case of hover \e enter events, we immediately update the |
|
510 item's position since we want the item to appear on top of all |
|
511 other items as soon as it starts expanding. In the case of hover |
|
512 \e leave events, on the other hand, we postpone the actual update |
|
513 to achieve the same result. But remember that when we constructed |
|
514 our item, we connected the time line's \l |
|
515 {QTimeLine::}{finished()} signal to the \c updateItemPosition() |
|
516 slot. In this way the item is given the correct position in the |
|
517 item stack once the animation is completed. Finally, if the time |
|
518 line is not already running, we start it. |
|
519 |
|
520 \snippet examples/sql/drilldown/imageitem.cpp 3 |
|
521 |
|
522 When the time line is running, it triggers the \c setFrame() slot |
|
523 whenever the current frame changes due to the connection we |
|
524 created in the item constructor. It is this slot that controls the |
|
525 animation, expanding or shrinking the image item step by step. |
|
526 |
|
527 We first call the \c adjust() function to ensure that we start off |
|
528 with the item's original size. Then we scale the item with a |
|
529 factor depending on the animation's progress (using the \c frame |
|
530 parameter). Note that by default, the transformation will be |
|
531 relative to the item's top-left corner. Since we want the item to |
|
532 be transformed relative to its center, we must translate the |
|
533 coordinate system before we scale the item. |
|
534 |
|
535 In the end, only the following convenience functions remain: |
|
536 |
|
537 \snippet examples/sql/drilldown/imageitem.cpp 4 |
|
538 \codeline |
|
539 \snippet examples/sql/drilldown/imageitem.cpp 5 |
|
540 \codeline |
|
541 \snippet examples/sql/drilldown/imageitem.cpp 6 |
|
542 |
|
543 The \c adjust() function defines and applies a transformation |
|
544 matrix, ensuring that our image item appears with the preferred |
|
545 size regardless of the size of the source image. The \c id() |
|
546 function is trivial, and is simply provided to be able to identify |
|
547 the item. In the \c updateItemPosition() slot we call the |
|
548 QGraphicsItem::setZValue() function, setting the elevation (i.e., |
|
549 the position) of the item. |
|
550 */ |