| /**************************************************************************** |
| ** |
| ** 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/imageviewer |
| \title Image Viewer Example |
| \ingroup examples-widgets |
| \brief The example shows how to combine QLabel and QScrollArea to |
| display an image. |
| |
| QLabel is typically used for displaying text, |
| but it can also display an image. QScrollArea provides a |
| scrolling view around another widget. If the child widget exceeds |
| the size of the frame, QScrollArea automatically provides scroll |
| bars. |
| |
| The example demonstrates how QLabel's ability to scale its |
| contents (QLabel::scaledContents), and QScrollArea's ability to |
| automatically resize its contents (QScrollArea::widgetResizable), |
| can be used to implement zooming and scaling features. In |
| addition the example shows how to use QPainter to print an image. |
| |
| \borderedimage imageviewer-example.png |
| \caption Screenshot of the Image Viewer example |
| |
| With the Image Viewer application, the users can view an image of |
| their choice. The \uicontrol File menu gives the user the possibility |
| to: |
| |
| \list |
| \li \uicontrol{Open...} - Open an image file |
| \li \uicontrol{Print...} - Print an image |
| \li \uicontrol{Exit} - Exit the application |
| \endlist |
| |
| Once an image is loaded, the \uicontrol View menu allows the users to: |
| |
| \list |
| \li \uicontrol{Zoom In} - Scale the image up by 25% |
| \li \uicontrol{Zoom Out} - Scale the image down by 25% |
| \li \uicontrol{Normal Size} - Show the image at its original size |
| \li \uicontrol{Fit to Window} - Stretch the image to occupy the entire window |
| \endlist |
| |
| In addition the \uicontrol Help menu provides the users with information |
| about the Image Viewer example in particular, and about Qt in |
| general. |
| |
| \section1 ImageViewer Class Definition |
| |
| \snippet widgets/imageviewer/imageviewer.h 0 |
| |
| The \c ImageViewer class inherits from QMainWindow. We reimplement |
| the constructor, and create several private slots to facilitate |
| the menu entries. In addition we create four private functions. |
| |
| We use \c createActions() and \c createMenus() when constructing |
| the \c ImageViewer widget. We use the \c updateActions() function |
| to update the menu entries when a new image is loaded, or when |
| the \uicontrol {Fit to Window} option is toggled. The zoom slots use \c |
| scaleImage() to perform the zooming. In turn, \c |
| scaleImage() uses \c adjustScrollBar() to preserve the focal point after |
| scaling an image. |
| |
| \section1 ImageViewer Class Implementation |
| |
| \snippet widgets/imageviewer/imageviewer.cpp 0 |
| |
| In the constructor we first create the label and the scroll area. |
| |
| We set \c {imageLabel}'s size policy to \l |
| {QSizePolicy::Ignored}{ignored}, making the users able to scale |
| the image to whatever size they want when the \uicontrol {Fit to Window} |
| option is turned on. Otherwise, the default size polizy (\l |
| {QSizePolicy::Preferred}{preferred}) will make scroll bars appear |
| when the scroll area becomes smaller than the label's minimum size |
| hint. |
| |
| We ensure that the label will scale its contents to fill all |
| available space, to enable the image to scale properly when |
| zooming. If we omitted to set the \c {imageLabel}'s \l |
| {QLabel::scaledContents}{scaledContents} property, zooming in |
| would enlarge the QLabel, but leave the pixmap at |
| its original size, exposing the QLabel's background. |
| |
| We make \c imageLabel the scroll area's child widget, and we make |
| \c scrollArea the central widget of the QMainWindow. At the end |
| we create the associated actions and menus, and customize the \c |
| {ImageViewer}'s appearance. |
| |
| \snippet widgets/imageviewer/imageviewer.cpp 1 |
| |
| In the \c open() slot, we show a file dialog to the user. We compile |
| a list of mime types for use as a filter by querying QImageReader |
| for the available mime type names. |
| |
| We show the file dialog until a valid file name is entered or |
| the user cancels. |
| |
| The function \c loadFile() is used to load the image. |
| |
| \snippet widgets/imageviewer/imageviewer.cpp 2 |
| |
| In the \c loadFile() function, we instantiate a QImageReader |
| and enable automatic transformations by calling |
| QImageReader::setAutoTransform(). For files in JPEG format, |
| this ensures that portrait mode images of digital cameras are shown |
| correctly by applying the appropriate orientation read from the |
| EXIF meta data stored in the image file. |
| |
| We then load the image using QImageReader::read(). If this returns |
| a null image, indicating that the file is not an image file, |
| we use a QMessageBox to alert the user. |
| |
| The QMessageBox class provides a modal dialog with a short |
| message, an icon, and some buttons. As with QFileDialog the |
| easiest way to create a QMessageBox is to use its static |
| convenience functions. QMessageBox provides a range of different |
| messages arranged along two axes: severity (question, |
| information, warning and critical) and complexity (the number of |
| necessary response buttons). In this particular example an |
| information message with an \uicontrol OK button (the default) is |
| sufficient, since the message is part of a normal operation. |
| |
| \snippet widgets/imageviewer/imageviewer.cpp 4 |
| |
| If the format is supported, we display the image in \c imageLabel |
| by setting the label's \l {QLabel::pixmap}{pixmap}. Then we enable |
| the \uicontrol Print and \uicontrol {Fit to Window} menu entries and update |
| the rest of the view menu entries. The \uicontrol Open and \uicontrol Exit |
| entries are enabled by default. |
| |
| If the \uicontrol {Fit to Window} option is turned off, the |
| QScrollArea::widgetResizable property is \c false and it is |
| our responsibility (not QScrollArea's) to give the QLabel a |
| reasonable size based on its contents. We call |
| \{QWidget::adjustSize()}{adjustSize()} to achieve this, which is |
| essentially the same as |
| |
| \code |
| imageLabel->resize(imageLabel->pixmap()->size()); |
| \endcode |
| |
| In the \c print() slot, we first make sure that an image has been |
| loaded into the application: |
| |
| \snippet widgets/imageviewer/imageviewer.cpp 5 |
| \snippet widgets/imageviewer/imageviewer.cpp 6 |
| |
| If the application is built in debug mode, the \c Q_ASSERT() macro |
| will expand to |
| |
| \code |
| if (imageLabel->pixmap(Qt::ReturnByValue).isNull()) |
| qFatal("ASSERT: "imageLabel->pixmap(Qt::ReturnByValue).isNull()" 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 \uicontrol qmake when building the application: |
| |
| \code |
| qmake "CONFIG += debug" foo.pro |
| \endcode |
| |
| or |
| |
| \code |
| qmake "CONFIG += release" foo.pro |
| \endcode |
| |
| Another approach is to add this line directly to the \c .pro |
| file. |
| |
| \snippet widgets/imageviewer/imageviewer.cpp 7 |
| \snippet widgets/imageviewer/imageviewer.cpp 8 |
| |
| Then we present a print dialog allowing the user to choose a |
| printer and to set a few options. We construct a painter with a |
| QPrinter as the paint device. We set the painter's window |
| and viewport in such a way that the image is as large as possible |
| on the paper, but without altering its |
| \l{Qt::KeepAspectRatio}{aspect ratio}. |
| |
| In the end we draw the pixmap at position (0, 0). |
| |
| \snippet widgets/imageviewer/imageviewer.cpp 9 |
| \snippet widgets/imageviewer/imageviewer.cpp 10 |
| |
| We implement the zooming slots using the private \c scaleImage() |
| function. We set the scaling factors to 1.25 and 0.8, |
| respectively. These factor values ensure that a \uicontrol {Zoom In} |
| action and a \uicontrol {Zoom Out} action will cancel each other (since |
| 1.25 * 0.8 == 1), and in that way the normal image size can be |
| restored using the zooming features. |
| |
| The screenshots below show an image in its normal size, and the |
| same image after zooming in: |
| |
| \table |
| \row |
| \li \inlineimage imageviewer-original_size.png |
| \li \inlineimage imageviewer-zoom_in_1.png |
| \li \inlineimage imageviewer-zoom_in_2.png |
| \endtable |
| |
| \snippet widgets/imageviewer/imageviewer.cpp 11 |
| \snippet widgets/imageviewer/imageviewer.cpp 12 |
| |
| When zooming, we use the QLabel's ability to scale its contents. |
| Such scaling doesn't change the actual size hint of the contents. |
| And since the \l {QLabel::adjustSize()}{adjustSize()} function |
| use those size hint, the only thing we need to do to restore the |
| normal size of the currently displayed image is to call \c |
| adjustSize() and reset the scale factor to 1.0. |
| |
| \snippet widgets/imageviewer/imageviewer.cpp 13 |
| \snippet widgets/imageviewer/imageviewer.cpp 14 |
| |
| The \c fitToWindow() slot is called each time the user toggled |
| the \uicontrol {Fit to Window} option. If the slot is called to turn on |
| the option, we tell the scroll area to resize its child widget |
| with the QScrollArea::setWidgetResizable() function. Then we |
| disable the \uicontrol {Zoom In}, \uicontrol {Zoom Out} and \uicontrol {Normal |
| Size} menu entries using the private \c updateActions() function. |
| |
| If the \l {QScrollArea::widgetResizable} property is set to \c |
| false (the default), the scroll area honors the size of its child |
| widget. If this property is set to \c true, the scroll area will |
| automatically resize the widget in order to avoid scroll bars |
| where they can be avoided, or to take advantage of extra space. |
| But the scroll area will honor the minimum size hint of its child |
| widget independent of the widget resizable property. So in this |
| example we set \c {imageLabel}'s size policy to \l |
| {QSizePolicy::Ignored}{ignored} in the constructor, to avoid that |
| scroll bars appear when the scroll area becomes smaller than the |
| label's minimum size hint. |
| |
| The screenshots below shows an image in its normal size, and the |
| same image with the \uicontrol {Fit to window} option turned on. |
| Enlarging the window will stretch the image further, as shown in |
| the third screenshot. |
| |
| \table |
| \row |
| \li \inlineimage imageviewer-original_size.png |
| \li \inlineimage imageviewer-fit_to_window_1.png |
| \li \inlineimage imageviewer-fit_to_window_2.png |
| \endtable |
| |
| If the slot is called to turn off the option, the |
| {QScrollArea::setWidgetResizable} property is set to \c false. We |
| also restore the image pixmap to its normal size by adjusting the |
| label's size to its content. And in the end we update the view |
| menu entries. |
| |
| \snippet widgets/imageviewer/imageviewer.cpp 15 |
| \snippet widgets/imageviewer/imageviewer.cpp 16 |
| |
| We implement the \c about() slot to create a message box |
| describing what the example is designed to show. |
| |
| \snippet widgets/imageviewer/imageviewer.cpp 17 |
| \snippet widgets/imageviewer/imageviewer.cpp 18 |
| |
| In the private \c createAction() function, we create the |
| actions providing the application features and populate |
| a menu with them. |
| |
| We assign a short-cut key to each action and connect them to the |
| appropriate slots. We only enable the \c openAct and \c exitAct at |
| the time of creation, the others are updated once an image has |
| been loaded into the application. In addition we make the \c |
| fitToWindowAct \l {QAction::checkable}{checkable}. |
| |
| The QMenu class provides a menu widget for use in menu bars, |
| context menus, and other popup menus. The QMenuBar class provides |
| a horizontal menu bar that consists of a list of pull-down menu |
| items. So we put the menus in the \c {ImageViewer}'s |
| menu bar which we retrieve with the QMainWindow::menuBar() |
| function. |
| |
| \snippet widgets/imageviewer/imageviewer.cpp 21 |
| \snippet widgets/imageviewer/imageviewer.cpp 22 |
| |
| The private \c updateActions() function enables or disables the |
| \uicontrol {Zoom In}, \uicontrol {Zoom Out} and \uicontrol {Normal Size} menu |
| entries depending on whether the \uicontrol {Fit to Window} option is |
| turned on or off. |
| |
| \snippet widgets/imageviewer/imageviewer.cpp 23 |
| \snippet widgets/imageviewer/imageviewer.cpp 24 |
| |
| In \c scaleImage(), we use the \c factor parameter to calculate |
| the new scaling factor for the displayed image, and resize \c |
| imageLabel. Since we set the |
| \l{QLabel::scaledContents}{scaledContents} property to \c true in |
| the constructor, the call to QWidget::resize() will scale the |
| image displayed in the label. We also adjust the scroll bars to |
| preserve the focal point of the image. |
| |
| At the end, if the scale factor is less than 33.3% or greater |
| than 300%, we disable the respective menu entry to prevent the |
| image pixmap from becoming too large, consuming too much |
| resources in the window system. |
| |
| \snippet widgets/imageviewer/imageviewer.cpp 25 |
| \snippet widgets/imageviewer/imageviewer.cpp 26 |
| |
| Whenever we zoom in or out, we need to adjust the scroll bars in |
| consequence. It would have been tempting to simply call |
| |
| \code |
| scrollBar->setValue(int(factor * scrollBar->value())); |
| \endcode |
| |
| but this would make the top-left corner the focal point, not the |
| center. Therefore we need to take into account the scroll bar |
| handle's size (the \l{QScrollBar::pageStep}{page step}). |
| */ |