blob: 0875bdada337245fe08802db442e43d8fb36e89b [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:FDL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Free Documentation License Usage
** 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. Please review the following information to ensure
** the GNU Free Documentation License version 1.3 requirements
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
** $QT_END_LICENSE$
**
****************************************************************************/
/*!
\example widgets/icons
\title Icons Example
\ingroup examples-widgets
\brief 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 \li Mode \li Description
\row
\li QIcon::Normal
\li Display the pixmap when the user is not interacting with the
icon, but the functionality represented by the icon is
available.
\row
\li QIcon::Active
\li 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
\li QIcon::Disabled
\li Display the pixmap when the functionality represented by
the icon is not available.
\row
\li QIcon::Selected
\li 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
\macos style differs by using 32 pixels instead of 16 pixels
for toolbar buttons. You can navigate between the available styles
using the \uicontrol View menu.
\image icons-view-menu.png Screenshot of the View menu
The \uicontrol View menu also provide the option to make the application
guess the icon state and mode from an image's file name. The \uicontrol
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 \uicontrol File menu provide an
\uicontrol Exit option, and the \uicontrol 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 \uicontrol {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 \uicontrol
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 \li{2,1} Requested Pixmap \li {8,1} Preferred Alternatives (mode/state)
\header \li Mode \li State \li 1 \li 2 \li 3 \li 4 \li 5 \li 6 \li 7 \li 8
\row \li{1,2} Normal \li Off \li \b N0 \li A0 \li N1 \li A1 \li D0 \li S0 \li D1 \li S1
\row \li On \li N1 \li \b A1 \li N0 \li A0 \li D1 \li S1 \li D0 \li S0
\row \li{1,2} Active \li Off \li A0 \li \b N0 \li A1 \li N1 \li D0 \li S0 \li D1 \li S1
\row \li On \li \b A1 \li N1 \li A0 \li N0 \li D1 \li S1 \li D0 \li S0
\row \li{1,2} Disabled \li Off \li D0 \li \b {N0'} \li A0' \li D1 \li N1' \li A1' \li S0' \li S1'
\row \li On \li D1 \li N1' \li \b {A1'} \li D0 \li N0' \li A0' \li S1' \li S0'
\row \li{1,2} Selected \li Off \li S0 \li \b {N0''} \li A0'' \li S1 \li N1'' \li A1'' \li D0'' \li D1''
\row \li On \li S1 \li N1'' \li \b {A1''} \li S0 \li N0'' \li A0'' \li D1'' \li 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
\li \inlineimage icons_monkey.png Screenshot of the Monkey Files
\li \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
\li
\li \inlineimage icons_qt_extended_8x8.png Qt Extended icon at 8 x 8
\li \inlineimage icons_qt_extended_16x16.png Qt Extended icon at 16 x 16
\li \inlineimage icons_qt_extended_17x17.png Qt Extended icon at 17 x 17
\row
\li
\li 8 x 8
\li \b {16 x 16}
\li 17 x 17
\row
\li \inlineimage icons_qt_extended_32x32.png Qt Extended icon at 32 x 32
\li \inlineimage icons_qt_extended_33x33.png Qt Extended icon at 33 x 33
\li \inlineimage icons_qt_extended_48x48.png Qt Extended icon at 48 x 48
\li \inlineimage icons_qt_extended_64x64.png Qt Extended icon at 64 x 64
\row
\li \b {32 x 32}
\li 33 x 33
\li \b {48 x 48}
\li 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
\li \c MainWindow inherits QMainWindow and is the main application
window.
\li \c IconPreviewArea is a custom widget that displays all
combinations of states and modes for a given icon.
\li \c IconSizeSpinBox is a subclass of QSpinBox that lets the
user enter icon sizes (e.g., "48 x 48").
\li \c ImageDelegate is a subclass of QStyledItemDelegate 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 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.
\snippet widgets/icons/iconpreviewarea.cpp 42
We would like the table columns to be in the order QIcon::Normal,
QIcon::Active, QIcon::Disabled, QIcon::Selected and the rows in the order
QIcon::Off, QIcon::On, which does not match the enumeration. The above code
provides arrays allowing to map from enumeration value to row/column
(by using QVector::indexOf()) and back by using the array index and lists
of the matching strings. Qt's containers can be easily populated by
using C++ 11 initializer lists.
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 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
\code
if (!condition)
qFatal("ASSERT: "condition" in file ...");
\endcode
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:
\code
qmake "CONFIG += debug" icons.pro
\endcode
or
\code
qmake "CONFIG += release" icons.pro
\endcode
Another approach is to add this line directly to the \c .pro
file.
\snippet widgets/icons/iconpreviewarea.cpp 1
\codeline
\snippet 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 widgets/icons/iconpreviewarea.cpp 3
\codeline
\snippet 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 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. We pass the QWindows instance
obtained by calling QWidget::windowHandle() on the top level
widget (QWidget::nativeParentWidget()) in order to retrieve
the pixmap that matches best.
We format a tooltip displaying size, actual size and device pixel
ratio.
\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 widgets/icons/mainwindow.h 0
The MainWindow class inherits from QMainWindow. We reimplement the
constructor, and declare several private slots:
\list
\li The \c about() slot simply provides information about the example.
\li The \c changeStyle() slot changes the application's GUI style and
adjust the style dependent size options.
\li The \c changeSize() slot changes the size of the preview area's icon.
\li The \c changeIcon() slot updates the set of pixmaps available to the
icon displayed in the preview area.
\li The \c addSampleImages() slot allows the user to load a new image
from the samples provided into the application.
\li The \c addOtherImages() slot allows the user to load a new image from
the directory obtained by calling
QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).
\li The \c screenChanged() updates the display in the \uicontrol{High DPI}
group box to correctly display the parameters of the current screen
the window is located on.
\endlist
In addition we declare several private functions to simplify the
constructor.
\section2 MainWindow Class Implementation
\snippet 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.
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 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 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 widgets/icons/mainwindow.cpp 3
\snippet 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 widgets/icons/mainwindow.cpp 5
The \c changeSize() slot sets the size for the preview area's
icon.
It is invoked by the QButtonGroup whose members are radio buttons for
controlling the icon size. In \c createIconSizeGroupBox(), each button is
assigned a QStyle::PixelMetric value as an id, which is passed as a
parameter to the slot.
The special value \c OtherSize indicates that the spin box is
enabled. If it is, we extract the extent of the new size from the
box. If it's not, we query the style for the metric. 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 widgets/icons/mainwindow.cpp 12
The function \c addImages() is called by the slot addSampleImages()
passing the samples directory, or by the slot addOtherImages()
passing the directory obtained by querying
QStandardPaths::standardLocations().
The first thing we do is to show a file dialog to the user.
We initialize it to show the filters returned by
QImageReader::supportedMimeTypes().
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 widgets/icons/mainwindow.cpp 13
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.
We check if a high resolution version of the image exists (identified by
the suffix \c @2x on the base name) and display that along with the size
in the tooltip.
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 widgets/icons/mainwindow.cpp 15
Then we create the second and third items in the row making the
default mode Normal and the default state Off. But if the \uicontrol
{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 convention.
\snippet widgets/icons/mainwindow.cpp 18
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 widgets/icons/mainwindow.cpp 6
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 widgets/icons/mainwindow.cpp 8
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 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 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 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 QStyledItemDelegate 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 QStyledItemDelegate.
QStyledItemDelegate usually provides line editors, while our subclass
\c ImageDelegate, provides comboboxes for the mode and state
fields.
\snippet widgets/icons/mainwindow.cpp 22
Then we customize the QTableWidget's horizontal header, and hide
the vertical header.
\snippet widgets/icons/mainwindow.cpp 24
At the end, we connect the QTableWidget::itemChanged() signal to
the \c changeIcon() slot to ensure 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 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. We add the
radio buttons to an instance of QButtonGroup, using the value
of the QStyle::PixelMetric they represent as an integer id.
\snippet widgets/icons/mainwindow.cpp 40
We introduce an enumeration constant \c OtherSize to represent
a custom size.
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 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 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" and "fusion". Depending on the platform,
"windowsvista" 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().
As we go along, we create the \uicontrol File, \uicontrol View and
\uicontrol Help menus and add the actions to them.
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 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 \uicontrol{Add Image} and \uicontrol{Remove All Images}
actions to the table widget. They will then appear in the table
widget's context menu.
\snippet 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.
\snippet widgets/icons/mainwindow.cpp 44
We overload the show() function to set up the updating of the
current screen in \c screenChanged(). After calling QWidget::show(),
the QWindow associated with the QWidget is created and we can
connect to its QWindow::screenChanged() signal.
\section2 IconSizeSpinBox Class Definition
\snippet 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 widgets/icons/iconsizespinbox.cpp 0
The constructor is trivial.
\snippet 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 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 QRegularExpression). 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 QRegularExpressionMatch::captured()
or QRegularExpressionMatch::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 \uicontrol 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 widgets/icons/imagedelegate.h 0
The \c ImageDelegate class is a subclass of QStyledItemDelegate. The
QStyledItemDelegate class provides display and editing facilities for
data items from a model. A single QStyledItemDelegate object is
responsible for all items displayed in a item view (in our case,
a QTableWidget).
A QStyledItemDelegate 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 widgets/icons/imagedelegate.h 1
The default implementation of QStyledItemDelegate creates a QLineEdit.
Since we want the editor to be a QComboBox, we need to subclass
QStyledItemDelegate and reimplement the QStyledItemDelegate::createEditor(),
QStyledItemDelegate::setEditorData() and QStyledItemDelegate::setModelData()
functions.
\snippet 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 widgets/icons/imagedelegate.cpp 0
The constructor is trivial.
\snippet widgets/icons/imagedelegate.cpp 1
The default QStyledItemDelegate::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 creates and populates 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 widgets/icons/imagedelegate.cpp 2
The QStyledItemDelegate::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 widgets/icons/imagedelegate.cpp 3
The QStyledItemDelegate::setEditorData() function is used by QTableWidget
to transfer data back from the editor to the \l{QTableWidgetItem}.
\snippet 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.
\section2 The Implementation of the Function main()
\snippet widgets/icons/main.cpp 45
We use QCommandLineParser to handle any command line options or parameters
passed to the application. Then, we resize the main window according
to the available screen geometry and show it.
*/