summaryrefslogtreecommitdiffstats
path: root/doc/src/examples/icons.qdoc
blob: 3966bf4b8de5eb57f4be5269ed8ba1e3b23eb426 (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
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
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
/****************************************************************************
**
** 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$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** 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.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
** $QT_END_LICENSE$
**
****************************************************************************/

/*!
    \example widgets/icons
    \title Icons Example

    The Icons example shows how QIcon can generate pixmaps reflecting
    an icon's state, mode and size. These pixmaps are generated from
    the set of pixmaps made available to the icon, and are used by Qt
    widgets to show an icon representing a particular action.

    \image icons-example.png Screenshot of the Icons example

    Contents:

    \tableofcontents

    \section1 QIcon Overview

    The QIcon class provides scalable icons in different modes and
    states. An icon's state and mode are depending on the intended use
    of the icon. Qt currently defines four modes:

    \table
    \header \o Mode \o Description
    \row
    \o QIcon::Normal
    \o Display the pixmap when the user is not interacting with the
       icon, but the functionality represented by the icon is
       available.
    \row
    \o QIcon::Active
    \o Display the pixmap when the functionality represented by the
       icon is available and the user is interacting with the icon,
       for example, moving the mouse over it or clicking it.
    \row
    \o QIcon::Disabled
    \o Display the pixmap when the functionality represented by
       the icon is not available.
    \row
    \o QIcon::Selected
    \o Display the pixmap when the icon is selected.
    \endtable

    QIcon's states are QIcon::On and QIcon::Off, which will display
    the pixmap when the widget is in the respective state. The most
    common usage of QIcon's states are when displaying checkable tool
    buttons or menu entries (see QAbstractButton::setCheckable() and
    QAction::setCheckable()). When a tool button or menu entry is
    checked, the QIcon's state is \l{QIcon::}{On}, otherwise it's
    \l{QIcon::}{Off}. You can, for example, use the QIcon's states to
    display differing pixmaps depending on whether the tool button or
    menu entry is checked or not.

    A QIcon can generate smaller, larger, active, disabled, and
    selected pixmaps from the set of pixmaps it is given. Such
    pixmaps are used by Qt widgets to show an icon representing a
    particular action.

    \section1 Overview of the Icons Application

    With the Icons application you get a preview of an icon's
    generated pixmaps reflecting its different states, modes and size.

    When an image is loaded into the application, it is converted into
    a pixmap and becomes a part of the set of pixmaps available to the
    icon. An image can be excluded from this set by checking off the
    related checkbox. The application provides a sub directory
    containing sets of images explicitly designed to illustrate how Qt
    renders an icon in different modes and states.

    The application allows you to manipulate the icon size with some
    predefined sizes and a spin box. The predefined sizes are style
    dependent, but most of the styles have the same values: Only the
    Macintosh style differ by using 32 pixels, instead of 16 pixels,
    for toolbar buttons. You can navigate between the available styles
    using the \gui View menu.

    \image icons-view-menu.png Screenshot of the View menu

    The \gui View menu also provide the option to make the application
    guess the icon state and mode from an image's file name. The \gui
    File menu provide the options of adding an image and removing all
    images. These last options are also available through a context
    menu that appears if you press the right mouse button within the
    table of image files. In addition, the \gui File menu provide an
    \gui Exit option, and the \gui Help menu provide information about
    the example and about Qt.

    \image icons_find_normal.png Screenshot of the Find Files

    The screenshot above shows the application with one image file
    loaded. The \gui {Guess Image Mode/State} is enabled and the
    style is Plastique.

    When QIcon is provided with only one available pixmap, that
    pixmap is used for all the states and modes. In this case the
    pixmap's icon mode is set to normal, and the generated pixmaps
    for the normal and active modes will look the same. But in
    disabled and selected mode, Qt will generate a slightly different
    pixmap.

    The next screenshot shows the application with an additional file
    loaded, providing QIcon with two available pixmaps. Note that the
    new image file's mode is set to disabled. When rendering the \gui
    Disabled mode pixmaps, Qt will now use the new image. We can see
    the difference: The generated disabled pixmap in the first
    screenshot is slightly darker than the pixmap with the originally
    set disabled mode in the second screenshot.

    \image icons_find_normal_disabled.png Screenshot of the Find Files

    When Qt renders the icon's pixmaps it searches through the set of
    available pixmaps following a particular algorithm. The algorithm
    is documented in QIcon, but we will describe some particular cases
    below.

    \image icons_monkey_active.png Screenshot of the Find Files

    In the screenshot above, we have set \c monkey_on_32x32 to be an
    Active/On pixmap and \c monkey_off_64x64 to be Normal/Off. To
    render the other six mode/state combinations, QIcon uses the
    search algorithm described in the table below:

    \table 100%
    \header \o{2,1} Requested Pixmap \o {8,1} Preferred Alternatives (mode/state)
    \header \o Mode \o State \o 1  \o 2 \o 3 \o 4 \o 5 \o 6 \o 7 \o 8
    \row \o{1,2} Normal \o Off \o \bold N0 \o A0 \o N1 \o A1 \o D0 \o S0 \o D1 \o S1
    \row \o On \o N1 \o \bold A1 \o N0 \o A0 \o D1 \o S1 \o D0 \o S0
    \row \o{1,2} Active \o Off \o A0 \o \bold N0 \o A1 \o N1 \o D0 \o S0 \o D1 \o S1
    \row \o On \o \bold A1 \o N1 \o A0 \o N0 \o D1 \o S1 \o D0 \o S0
    \row \o{1,2} Disabled \o Off \o D0 \o \bold {N0'} \o A0' \o D1 \o N1' \o A1' \o S0' \o S1'
    \row \o On \o D1 \o N1' \o \bold {A1'} \o D0 \o N0' \o A0' \o S1' \o S0'
    \row \o{1,2} Selected \o Off \o S0 \o \bold {N0''} \o A0'' \o S1 \o N1'' \o A1'' \o D0'' \o D1''
    \row \o On \o S1 \o N1'' \o \bold {A1''} \o S0 \o N0'' \o A0'' \o D1'' \o D0''
    \endtable

    In the table, "0" and "1" stand for Off" and "On", respectively.
    Single quotes indicates that QIcon generates a disabled ("grayed
    out") version of the pixmap; similarly, double quuote indicate
    that QIcon generates a selected ("blued out") version of the
    pixmap.

    The alternatives used in the screenshot above are shown in bold.
    For example, the Disabled/Off pixmap is derived by graying out
    the Normal/Off pixmap (\c monkey_off_64x64).

    In the next screenshots, we loaded the whole set of monkey
    images. By checking or unchecking file names from the image list,
    we get different results:

    \table
    \row
    \o \inlineimage icons_monkey.png Screenshot of the Monkey Files
    \o \inlineimage icons_monkey_mess.png Screenshot of the Monkey Files
    \endtable

    For any given mode/state combination, it is possible to specify
    several images at different resolutions. When rendering an
    icon, QIcon will automatically pick the most suitable image
    and scale it down if necessary. (QIcon never scales up images,
    because this rarely looks good.)

    The screenshots below shows what happens when we provide QIcon
    with three images (\c qt_extended_16x16.png, \c qt_extended_32x32.png, \c
    qt_extended_48x48.png) and try to render the QIcon at various
    resolutions:

    \table
    \row
    \o
    \o \inlineimage icons_qt_extended_8x8.png Qt Extended icon at 8 x 8
    \o \inlineimage icons_qt_extended_16x16.png Qt Extended icon at 16 x 16
    \o \inlineimage icons_qt_extended_17x17.png Qt Extended icon at 17 x 17
    \row
    \o
    \o 8 x 8
    \o \bold {16 x 16}
    \o 17 x 17
    \row
    \o \inlineimage icons_qt_extended_32x32.png Qt Extended icon at 32 x 32
    \o \inlineimage icons_qt_extended_33x33.png Qt Extended icon at 33 x 33
    \o \inlineimage icons_qt_extended_48x48.png Qt Extended icon at 48 x 48
    \o \inlineimage icons_qt_extended_64x64.png Qt Extended icon at 64 x 64
    \row
    \o \bold {32 x 32}
    \o 33 x 33
    \o \bold {48 x 48}
    \o 64 x 64
    \endtable

    For sizes up to 16 x 16, QIcon uses \c qt_extended_16x16.png and
    scales it down if necessary. For sizes between 17 x 17 and 32 x
    32, it uses \c qt_extended_32x32.png. For sizes above 32 x 32, it uses
    \c qt_extended_48x48.png.

    \section1 Line-by-Line Walkthrough

    The Icons example consists of four classes:

    \list
    \o \c MainWindow inherits QMainWindow and is the main application
       window.
    \o \c IconPreviewArea is a custom widget that displays all
       combinations of states and modes for a given icon.
    \o \c IconSizeSpinBox is a subclass of QSpinBox that lets the
       user enter icon sizes (e.g., "48 x 48").
    \o \c ImageDelegate is a subclass of QItemDelegate that provides
       comboboxes for letting the user set the mode and state
       associated with an image.
    \endlist

    We will start by reviewing the \c IconPreviewArea class before we
    take a look at the \c MainWindow class. Finally, we will review the
    \c IconSizeSpinBox and \c ImageDelegate classes.

    \section2 IconPreviewArea Class Definition

    An \c IconPreviewArea widget consists of a group box containing a grid of
    QLabel widgets displaying headers and pixmaps.

    \image icons_preview_area.png Screenshot of IconPreviewArea.

    \snippet examples/widgets/icons/iconpreviewarea.h 0

    The \c IconPreviewArea class inherits QWidget. It displays the
    generated pixmaps corresponding to an icon's possible states and
    modes at a given size.

    We need two public functions to set the current icon and the
    icon's size. In addition the class has three private functions: We
    use the \c createHeaderLabel() and \c createPixmapLabel()
    functions when constructing the preview area, and we need the \c
    updatePixmapLabels() function to update the preview area when
    the icon or the icon's size has changed.

    The \c NumModes and \c NumStates constants reflect \l{QIcon}'s
    number of currently defined modes and states.

    \section2 IconPreviewArea Class Implementation

    \snippet examples/widgets/icons/iconpreviewarea.cpp 0

    In the constructor we create the labels displaying the headers and
    the icon's generated pixmaps, and add them to a grid layout.

    When creating the header labels, we make sure the enums \c
    NumModes and \c NumStates defined in the \c .h file, correspond
    with the number of labels that we create. Then if the enums at
    some point are changed, the \c Q_ASSERT() macro will alert that this
    part of the \c .cpp file needs to be updated as well.

    If the application is built in debug mode, the \c Q_ASSERT()
    macro will expand to

    \snippet doc/src/snippets/code/doc_src_examples_icons.cpp 0

    In release mode, the macro simply disappear. The mode can be set
    in the application's \c .pro file. One way to do so is to add an
    option to \c qmake when building the application:

    \snippet doc/src/snippets/code/doc_src_examples_icons.qdoc 1

    or

    \snippet doc/src/snippets/code/doc_src_examples_icons.qdoc 2

    Another approach is to add this line directly to the \c .pro
    file.

    \snippet examples/widgets/icons/iconpreviewarea.cpp 1
    \codeline
    \snippet examples/widgets/icons/iconpreviewarea.cpp 2

    The public \c setIcon() and \c setSize() functions change the icon
    or the icon size, and make sure that the generated pixmaps are
    updated.

    \snippet examples/widgets/icons/iconpreviewarea.cpp 3
    \codeline
    \snippet examples/widgets/icons/iconpreviewarea.cpp 4

    We use the \c createHeaderLabel() and \c createPixmapLabel()
    functions to create the preview area's labels displaying the
    headers and the icon's generated pixmaps. Both functions return
    the QLabel that is created.

    \snippet examples/widgets/icons/iconpreviewarea.cpp 5

    We use the private \c updatePixmapLabel() function to update the
    generated pixmaps displayed in the preview area.

    For each mode, and for each state, we retrieve a pixmap using the
    QIcon::pixmap() function, which generates a pixmap corresponding
    to the given state, mode and size.

    \section2 MainWindow Class Definition

    The \c MainWindow widget consists of three main elements: an
    images group box, an icon size group box and a preview area.

    \image icons-example.png Screenshot of the Icons example

    \snippet examples/widgets/icons/mainwindow.h 0

    The MainWindow class inherits from QMainWindow. We reimplement the
    constructor, and declare several private slots:

    \list
    \o The \c about() slot simply provides information about the example.
    \o The \c changeStyle() slot changes the application's GUI style and
       adjust the style dependent size options.
    \o The \c changeSize() slot changes the size of the preview area's icon.
    \o The \c changeIcon() slot updates the set of pixmaps available to the
       icon displayed in the preview area.
    \o The \c addImage() slot allows the user to load a new image into the
       application.
    \endlist

    In addition we declare several private functions to simplify the
    constructor.

    \section2 MainWindow Class Implementation

    \snippet examples/widgets/icons/mainwindow.cpp 0

    In the constructor we first create the main window's central
    widget and its child widgets, and put them in a grid layout. Then
    we create the menus with their associated entries and actions.

    Before we resize the application window to a suitable size, we set
    the window title and determine the current style for the
    application. We also enable the icon size spin box by clicking the
    associated radio button, making the current value of the spin box
    the icon's initial size.

    \snippet examples/widgets/icons/mainwindow.cpp 1

    The \c about() slot displays a message box using the static
    QMessageBox::about() function. In this example it displays a
    simple box with information about the example.

    The \c about() function looks for a suitable icon in four
    locations: It prefers its parent's icon if that exists. If it
    doesn't, the function tries the top-level widget containing
    parent, and if that fails, it tries the active window. As a last
    resort it uses the QMessageBox's Information icon.

    \snippet examples/widgets/icons/mainwindow.cpp 2

    In the \c changeStyle() slot we first check the slot's
    parameter. If it is false we immediately return, otherwise we find
    out which style to change to, i.e. which action that triggered the
    slot, using the QObject::sender() function.

    This function returns the sender as a QObject pointer. Since we
    know that the sender is a QAction object, we can safely cast the
    QObject. We could have used a C-style cast or a C++ \c
    static_cast(), but as a defensive programming technique we use a
    \l qobject_cast(). The advantage is that if the object has the
    wrong type, a null pointer is returned. Crashes due to null
    pointers are much easier to diagnose than crashes due to unsafe
    casts.

    \snippet examples/widgets/icons/mainwindow.cpp 3
    \snippet examples/widgets/icons/mainwindow.cpp 4

    Once we have the action, we extract the style name using
    QAction::data(). Then we create a QStyle object using the static
    QStyleFactory::create() function.

    Although we can assume that the style is supported by the
    QStyleFactory: To be on the safe side, we use the \c Q_ASSERT()
    macro to check if the created style is valid before we use the
    QApplication::setStyle() function to set the application's GUI
    style to the new style. QApplication will automatically delete
    the style object when a new style is set or when the application
    exits.

    The predefined icon size options provided in the application are
    style dependent, so we need to update the labels in the icon size
    group box and in the end call the \c changeSize() slot to update
    the icon's size.

    \snippet examples/widgets/icons/mainwindow.cpp 5

    The \c changeSize() slot sets the size for the preview area's
    icon.

    To determine the new size we first check if the spin box is
    enabled. If it is, we extract the extent of the new size from the
    box. If it's not, we search through the predefined size options,
    extract the QStyle::PixelMetric and use the QStyle::pixelMetric()
    function to determine the extent. Then we create a QSize object
    based on the extent, and use that object to set the size of the
    preview area's icon.

    \snippet examples/widgets/icons/mainwindow.cpp 12

    The first thing we do when the \c addImage() slot is called, is to
    show a file dialog to the user. The easiest way to create a file
    dialog is to use QFileDialog's static functions. Here we use the
    \l {QFileDialog::getOpenFileNames()}{getOpenFileNames()} function
    that will return one or more existing files selected by the user.

    For each of the files the file dialog returns, we add a row to the
    table widget. The table widget is listing the images the user has
    loaded into the application.

    \snippet examples/widgets/icons/mainwindow.cpp 13
    \snippet examples/widgets/icons/mainwindow.cpp 14

    We retrieve the image name using the QFileInfo::baseName()
    function that returns the base name of the file without the path,
    and create the first table widget item in the row. Then we add the
    file's complete name to the item's data. Since an item can hold
    several information pieces, we need to assign the file name a role
    that will distinguish it from other data. This role can be Qt::UserRole
    or any value above it.

    We also make sure that the item is not editable by removing the
    Qt::ItemIsEditable flag. Table items are editable by default.

    \snippet examples/widgets/icons/mainwindow.cpp 15
    \snippet examples/widgets/icons/mainwindow.cpp 16
    \snippet examples/widgets/icons/mainwindow.cpp 17

    Then we create the second and third items in the row making the
    default mode Normal and the default state Off. But if the \gui
    {Guess Image Mode/State} option is checked, and the file name
    contains "_act", "_dis", or "_sel", the modes are changed to
    Active, Disabled, or Selected. And if the file name contains
    "_on", the state is changed to On. The sample files in the
    example's \c images subdirectory respect this naming convension.

    \snippet examples/widgets/icons/mainwindow.cpp 18
    \snippet examples/widgets/icons/mainwindow.cpp 19

    In the end we add the items to the associated row, and use the
    QTableWidget::openPersistentEditor() function to create
    comboboxes for the mode and state columns of the items.

    Due to the connection between the table widget's \l
    {QTableWidget::itemChanged()}{itemChanged()} signal and the \c
    changeIcon() slot, the new image is automatically converted into a
    pixmap and made part of the set of pixmaps available to the icon
    in the preview area. So, corresponding to this fact, we need to
    make sure that the new image's check box is enabled.

    \snippet examples/widgets/icons/mainwindow.cpp 6
    \snippet examples/widgets/icons/mainwindow.cpp 7

    The \c changeIcon() slot is called when the user alters the set
    of images listed in the QTableWidget, to update the QIcon object
    rendered by the \c IconPreviewArea.

    We first create a QIcon object, and then we run through the
    QTableWidget, which lists the images the user has loaded into the
    application.

    \snippet examples/widgets/icons/mainwindow.cpp 8
    \snippet examples/widgets/icons/mainwindow.cpp 9
    \snippet examples/widgets/icons/mainwindow.cpp 10

    We also extract the image file's name using the
    QTableWidgetItem::data() function. This function takes a
    Qt::DataItemRole as an argument to retrieve the right data
    (remember that an item can hold several pieces of information)
    and returns it as a QVariant. Then we use the
    QVariant::toString() function to get the file name as a QString.

    To create a pixmap from the file, we need to first create an
    image and then convert this image into a pixmap using
    QPixmap::fromImage(). Once we have the final pixmap, we add it,
    with its associated mode and state, to the QIcon's set of
    available pixmaps.

    \snippet examples/widgets/icons/mainwindow.cpp 11

    After running through the entire list of images, we change the
    icon of the preview area to the one we just created.

    \snippet examples/widgets/icons/mainwindow.cpp 20

    In the \c removeAllImages() slot, we simply set the table widget's
    row count to zero, automatically removing all the images the user
    has loaded into the application. Then we update the set of pixmaps
    available to the preview area's icon using the \c changeIcon()
    slot.

    \image icons_images_groupbox.png Screenshot of the images group box

    The \c createImagesGroupBox() function is implemented to simplify
    the constructor. The main purpose of the function is to create a
    QTableWidget that will keep track of the images the user has
    loaded into the application.

    \snippet examples/widgets/icons/mainwindow.cpp 21

    First we create a group box that will contain the table widget.
    Then we create a QTableWidget and customize it to suit our
    purposes.

    We call QAbstractItemView::setSelectionMode() to prevent the user
    from selecting items.

    The QAbstractItemView::setItemDelegate() call sets the item
    delegate for the table widget. We create a \c ImageDelegate that
    we make the item delegate for our view.

    The QItemDelegate class can be used to provide an editor for an item view
    class that is subclassed from QAbstractItemView. Using a delegate
    for this purpose allows the editing mechanism to be customized and
    developed independently from the model and view.

    In this example we derive \c ImageDelegate from QItemDelegate.
    QItemDelegate usually provides line editors, while our subclass
    \c ImageDelegate, provides comboboxes for the mode and state
    fields.

    \snippet examples/widgets/icons/mainwindow.cpp 22
    \snippet examples/widgets/icons/mainwindow.cpp 23

    Then we customize the QTableWidget's horizontal header, and hide
    the vertical header.

    \snippet examples/widgets/icons/mainwindow.cpp 24
    \snippet examples/widgets/icons/mainwindow.cpp 25

    At the end, we connect the QTableWidget::itemChanged() signal to
    the \c changeIcon() slot to ensuret that the preview area is in
    sync with the image table.

    \image icons_size_groupbox.png Screenshot of the icon size group box

    The \c createIconSizeGroupBox() function is called from the
    constructor. It creates the widgets controlling the size of the
    preview area's icon.

    \snippet examples/widgets/icons/mainwindow.cpp 26

    First we create a group box that will contain all the widgets;
    then we create the radio buttons and the spin box.

    The spin box is not a regular QSpinBox but an \c IconSizeSpinBox.
    The \c IconSizeSpinBox class inherits QSpinBox and reimplements
    two functions: QSpinBox::textFromValue() and
    QSpinBox::valueFromText(). The \c IconSizeSpinBox is designed to
    handle icon sizes, e.g., "32 x 32", instead of plain integer
    values.

    \snippet examples/widgets/icons/mainwindow.cpp 27

    Then we connect all of the radio buttons
    \l{QRadioButton::toggled()}{toggled()} signals and the spin box's
    \l {QSpinBox::valueChanged()}{valueChanged()} signal to the \c
    changeSize() slot to make sure that the size of the preview
    area's icon is updated whenever the user changes the icon size.
    In the end we put the widgets in a layout that we install on the
    group box.

    \snippet examples/widgets/icons/mainwindow.cpp 28

    In the \c createActions() function we create and customize all the
    actions needed to implement the functionality associated with the
    menu entries in the application.

    In particular we create the \c styleActionGroup based on the
    currently available GUI styles using
    QStyleFactory. QStyleFactory::keys() returns a list of valid keys,
    typically including "windows", "motif", "cde", and
    "plastique". Depending on the platform, "windowsxp" and
    "macintosh" may be available.

    We create one action for each key, and adds the action to the
    action group. Also, for each action, we call QAction::setData()
    with the style name. We will retrieve it later using
    QAction::data().

    \snippet examples/widgets/icons/mainwindow.cpp 29

    In the \c createMenu() function, we add the previously created
    actions to the \gui File, \gui View and \gui Help menus.

    The QMenu class provides a menu widget for use in menu bars,
    context menus, and other popup menus. We put each menu in the
    application's menu bar, which we retrieve using
    QMainWindow::menuBar().

    \snippet examples/widgets/icons/mainwindow.cpp 30

    QWidgets have a \l{QWidget::contextMenuPolicy}{contextMenuPolicy}
    property that controls how the widget should behave when the user
    requests a context menu (e.g., by right-clicking). We set the
    QTableWidget's context menu policy to Qt::ActionsContextMenu,
    meaning that the \l{QAction}s associated with the widget should
    appear in its context menu.

    Then we add the \gui{Add Image} and \gui{Remove All Images}
    actions to the table widget. They will then appear in the table
    widget's context menu.

    \snippet examples/widgets/icons/mainwindow.cpp 31

    In the \c checkCurrentStyle() function we go through the group of
    style actions, looking for the current GUI style.

    For each action, we first extract the style name using
    QAction::data(). Since this is only a QStyleFactory key (e.g.,
    "macintosh"), we cannot compare it directly to the current
    style's class name. We need to create a QStyle object using the
    static QStyleFactory::create() function and compare the class
    name of the created QStyle object with that of the current style.
    As soon as we are done with a QStyle candidate, we delete it.

    For all QObject subclasses that use the \c Q_OBJECT macro, the
    class name of an object is available through its
    \l{QObject::metaObject()}{meta-object}.

    We can assume that the style is supported by
    QStyleFactory, but to be on the safe side we use the \c
    Q_ASSERT() macro to make sure that QStyleFactory::create()
    returned a valid pointer.

    \section2 IconSizeSpinBox Class Definition

    \snippet examples/widgets/icons/iconsizespinbox.h 0

    The \c IconSizeSpinBox class is a subclass of QSpinBox. A plain
    QSpinBox can only handle integers. But since we want to display
    the spin box's values in a more sophisticated way, we need to
    subclass QSpinBox and reimplement the QSpinBox::textFromValue()
    and QSpinBox::valueFromText() functions.

    \image icons_size_spinbox.png Screenshot of the icon size spinbox

    \section2 IconSizeSpinBox Class Implementation

    \snippet examples/widgets/icons/iconsizespinbox.cpp 0

    The constructor is trivial.

    \snippet examples/widgets/icons/iconsizespinbox.cpp 2

    QSpinBox::textFromValue() is used by the spin box whenever it
    needs to display a value. The default implementation returns a
    base 10 representation of the \c value parameter.

    Our reimplementation returns a QString of the form "32 x 32".

    \snippet examples/widgets/icons/iconsizespinbox.cpp 1

    The QSpinBox::valueFromText() function is used by the spin box
    whenever it needs to interpret text typed in by the user. Since
    we reimplement the \c textFromValue() function we also need to
    reimplement the \c valueFromText() function to interpret the
    parameter text and return the associated int value.

    We parse the text using a regular expression (a QRegExp). We
    define an expression that matches one or several digits,
    optionally followed by whitespace, an "x" or the times symbol,
    whitespace and one or several digits again.

    The first digits of the regular expression are captured using
    parentheses. This enables us to use the QRegExp::cap() or
    QRegExp::capturedTexts() functions to extract the matched
    characters. If the first and second numbers of the spin box value
    differ (e.g., "16 x 24"), we use the first number.

    When the user presses \key Enter, QSpinBox first calls
    QSpinBox::valueFromText() to interpret the text typed by the
    user, then QSpinBox::textFromValue() to present it in a canonical
    format (e.g., "16 x 16").

    \section2 ImageDelegate Class Definition

    \snippet examples/widgets/icons/imagedelegate.h 0

    The \c ImageDelegate class is a subclass of QItemDelegate. The
    QItemDelegate class provides display and editing facilities for
    data items from a model. A single QItemDelegate object is
    responsible for all items displayed in a item view (in our case,
    a QTableWidget).

    A QItemDelegate can be used to provide an editor for an item view
    class that is subclassed from QAbstractItemView. Using a delegate
    for this purpose allows the editing mechanism to be customized and
    developed independently from the model and view.

    \snippet examples/widgets/icons/imagedelegate.h 1

    The default implementation of QItemDelegate creates a QLineEdit.
    Since we want the editor to be a QComboBox, we need to subclass
    QItemDelegate and reimplement the QItemDelegate::createEditor(),
    QItemDelegate::setEditorData() and QItemDelegate::setModelData()
    functions.

    \snippet examples/widgets/icons/imagedelegate.h 2

    The \c emitCommitData() slot is used to emit the
    QImageDelegate::commitData() signal with the appropriate
    argument.

    \section2 ImageDelegate Class Implementation

    \snippet examples/widgets/icons/imagedelegate.cpp 0

    The constructor is trivial.

    \snippet examples/widgets/icons/imagedelegate.cpp 1

    The default QItemDelegate::createEditor() implementation returns
    the widget used to edit the item specified by the model and item
    index for editing. The parent widget and style option are used to
    control the appearance of the editor widget.

    Our reimplementation create and populate a combobox instead of
    the default line edit. The contents of the combobox depends on
    the column in the table for which the editor is requested. Column
    1 contains the QIcon modes, whereas column 2 contains the QIcon
    states.

    In addition, we connect the combobox's \l
    {QComboBox::activated()}{activated()} signal to the \c
    emitCommitData() slot to emit the
    QAbstractItemDelegate::commitData() signal whenever the user
    chooses an item using the combobox. This ensures that the rest of
    the application notices the change and updates itself.

    \snippet examples/widgets/icons/imagedelegate.cpp 2

    The QItemDelegate::setEditorData() function is used by
    QTableWidget to transfer data from a QTableWidgetItem to the
    editor. The data is stored as a string; we use
    QComboBox::findText() to locate it in the combobox.

    Delegates work in terms of models, not items. This makes it
    possible to use them with any item view class (e.g., QListView,
    QListWidget, QTreeView, etc.). The transition between model and
    items is done implicitly by QTableWidget; we don't need to worry
    about it.

    \snippet examples/widgets/icons/imagedelegate.cpp 3

    The QItemDelegate::setEditorData() function is used by QTableWidget
    to transfer data back from the editor to the \l{QTableWidgetItem}.

    \snippet examples/widgets/icons/imagedelegate.cpp 4

    The \c emitCommitData() slot simply emit the
    QAbstractItemDelegate::commitData() signal for the editor that
    triggered the slot. This signal must be emitted when the editor
    widget has completed editing the data, and wants to write it back
    into the model.
*/