1 /****************************************************************************
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
6 ** This file is part of the documentation of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:FDL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
17 ** GNU Free Documentation License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Free
19 ** Documentation License version 1.3 as published by the Free Software
20 ** Foundation and appearing in the file included in the packaging of
21 ** this file. Please review the following information to ensure
22 ** the GNU Free Documentation License version 1.3 requirements
23 ** will be met: http://www.gnu.org/copyleft/fdl.html.
26 ****************************************************************************/
29 \example widgets/imageviewer
30 \title Image Viewer Example
32 \brief The Image Viewer example shows how to combine QLabel and QScrollArea to
35 QLabel is typically used for displaying text,
36 but it can also display an image. QScrollArea provides a
37 scrolling view around another widget. If the child widget exceeds
38 the size of the frame, QScrollArea automatically provides scroll
41 The example demonstrates how QLabel's ability to scale its
42 contents (QLabel::scaledContents), and QScrollArea's ability to
43 automatically resize its contents (QScrollArea::widgetResizable),
44 can be used to implement zooming and scaling features. In
45 addition the example shows how to use QPainter to print an image.
47 \image imageviewer-example.png Screenshot of the Image Viewer example
49 With the Image Viewer application, the users can view an image of
50 their choice. The \gui File menu gives the user the possibility
54 \o \gui{Open...} - Open an image file
55 \o \gui{Print...} - Print an image
56 \o \gui{Exit} - Exit the application
59 Once an image is loaded, the \gui View menu allows the users to:
62 \o \gui{Zoom In} - Scale the image up by 25%
63 \o \gui{Zoom Out} - Scale the image down by 25%
64 \o \gui{Normal Size} - Show the image at its original size
65 \o \gui{Fit to Window} - Stretch the image to occupy the entire window
68 In addition the \gui Help menu provides the users with information
69 about the Image Viewer example in particular, and about Qt in
72 \section1 ImageViewer Class Definition
74 \snippet examples/widgets/imageviewer/imageviewer.h 0
76 The \c ImageViewer class inherits from QMainWindow. We reimplement
77 the constructor, and create several private slots to facilitate
78 the menu entries. In addition we create four private functions.
80 We use \c createActions() and \c createMenus() when constructing
81 the \c ImageViewer widget. We use the \c updateActions() function
82 to update the menu entries when a new image is loaded, or when
83 the \gui {Fit to Window} option is toggled. The zoom slots use \c
84 scaleImage() to perform the zooming. In turn, \c
85 scaleImage() uses \c adjustScrollBar() to preserve the focal point after
88 \section1 ImageViewer Class Implementation
90 \snippet examples/widgets/imageviewer/imageviewer.cpp 0
92 In the constructor we first create the label and the scroll area.
94 We set \c {imageLabel}'s size policy to \l
95 {QSizePolicy::Ignored}{ignored}, making the users able to scale
96 the image to whatever size they want when the \gui {Fit to Window}
97 option is turned on. Otherwise, the default size polizy (\l
98 {QSizePolicy::Preferred}{preferred}) will make scroll bars appear
99 when the scroll area becomes smaller than the label's minimum size
102 We ensure that the label will scale its contents to fill all
103 available space, to enable the image to scale properly when
104 zooming. If we omitted to set the \c {imageLabel}'s \l
105 {QLabel::scaledContents}{scaledContents} property, zooming in
106 would enlarge the QLabel, but leave the pixmap at
107 its original size, exposing the QLabel's background.
109 We make \c imageLabel the scroll area's child widget, and we make
110 \c scrollArea the central widget of the QMainWindow. At the end
111 we create the associated actions and menus, and customize the \c
112 {ImageViewer}'s appearance.
114 \snippet examples/widgets/imageviewer/imageviewer.cpp 1
115 \snippet examples/widgets/imageviewer/imageviewer.cpp 2
117 In the \c open() slot, we show a file dialog to the user. The
118 easiest way to create a QFileDialog is to use the static
119 convenience functions. QFileDialog::getOpenFileName() returns an
120 existing file selected by the user. If the user presses \gui
121 Cancel, QFileDialog returns an empty string.
123 Unless the file name is a empty string, we check if the file's
124 format is an image format by constructing a QImage which tries to
125 load the image from the file. If the constructor returns a null
126 image, we use a QMessageBox to alert the user.
128 The QMessageBox class provides a modal dialog with a short
129 message, an icon, and some buttons. As with QFileDialog the
130 easiest way to create a QMessageBox is to use its static
131 convenience functions. QMessageBox provides a range of different
132 messages arranged along two axes: severity (question,
133 information, warning and critical) and complexity (the number of
134 necessary response buttons). In this particular example an
135 information message with an \gui OK button (the default) is
136 sufficient, since the message is part of a normal operation.
138 \snippet examples/widgets/imageviewer/imageviewer.cpp 3
139 \snippet examples/widgets/imageviewer/imageviewer.cpp 4
141 If the format is supported, we display the image in \c imageLabel
142 by setting the label's \l {QLabel::pixmap}{pixmap}. Then we enable
143 the \gui Print and \gui {Fit to Window} menu entries and update
144 the rest of the view menu entries. The \gui Open and \gui Exit
145 entries are enabled by default.
147 If the \gui {Fit to Window} option is turned off, the
148 QScrollArea::widgetResizable property is \c false and it is
149 our responsibility (not QScrollArea's) to give the QLabel a
150 reasonable size based on its contents. We call
151 \{QWidget::adjustSize()}{adjustSize()} to achieve this, which is
152 essentially the same as
154 \snippet doc/src/snippets/code/doc_src_examples_imageviewer.cpp 0
156 In the \c print() slot, we first make sure that an image has been
157 loaded into the application:
159 \snippet examples/widgets/imageviewer/imageviewer.cpp 5
160 \snippet examples/widgets/imageviewer/imageviewer.cpp 6
162 If the application is built in debug mode, the \c Q_ASSERT() macro
165 \snippet doc/src/snippets/code/doc_src_examples_imageviewer.cpp 1
167 In release mode, the macro simply disappear. The mode can be set
168 in the application's \c .pro file. One way to do so is to add an
169 option to \gui qmake when building the appliction:
171 \snippet doc/src/snippets/code/doc_src_examples_imageviewer.qdoc 2
175 \snippet doc/src/snippets/code/doc_src_examples_imageviewer.qdoc 3
177 Another approach is to add this line directly to the \c .pro
180 \snippet examples/widgets/imageviewer/imageviewer.cpp 7
181 \snippet examples/widgets/imageviewer/imageviewer.cpp 8
183 Then we present a print dialog allowing the user to choose a
184 printer and to set a few options. We construct a painter with a
185 QPrinter as the paint device. We set the painter's window
186 and viewport in such a way that the image is as large as possible
187 on the paper, but without altering its
188 \l{Qt::KeepAspectRatio}{aspect ratio}.
190 In the end we draw the pixmap at position (0, 0).
192 \snippet examples/widgets/imageviewer/imageviewer.cpp 9
193 \snippet examples/widgets/imageviewer/imageviewer.cpp 10
195 We implement the zooming slots using the private \c scaleImage()
196 function. We set the scaling factors to 1.25 and 0.8,
197 respectively. These factor values ensure that a \gui {Zoom In}
198 action and a \gui {Zoom Out} action will cancel each other (since
199 1.25 * 0.8 == 1), and in that way the normal image size can be
200 restored using the zooming features.
202 The screenshots below show an image in its normal size, and the
203 same image after zooming in:
207 \o \inlineimage imageviewer-original_size.png
208 \o \inlineimage imageviewer-zoom_in_1.png
209 \o \inlineimage imageviewer-zoom_in_2.png
212 \snippet examples/widgets/imageviewer/imageviewer.cpp 11
213 \snippet examples/widgets/imageviewer/imageviewer.cpp 12
215 When zooming, we use the QLabel's ability to scale its contents.
216 Such scaling doesn't change the actual size hint of the contents.
217 And since the \l {QLabel::adjustSize()}{adjustSize()} function
218 use those size hint, the only thing we need to do to restore the
219 normal size of the currently displayed image is to call \c
220 adjustSize() and reset the scale factor to 1.0.
222 \snippet examples/widgets/imageviewer/imageviewer.cpp 13
223 \snippet examples/widgets/imageviewer/imageviewer.cpp 14
225 The \c fitToWindow() slot is called each time the user toggled
226 the \gui {Fit to Window} option. If the slot is called to turn on
227 the option, we tell the scroll area to resize its child widget
228 with the QScrollArea::setWidgetResizable() function. Then we
229 disable the \gui {Zoom In}, \gui {Zoom Out} and \gui {Normal
230 Size} menu entries using the private \c updateActions() function.
232 If the \l {QScrollArea::widgetResizable} property is set to \c
233 false (the default), the scroll area honors the size of its child
234 widget. If this property is set to \c true, the scroll area will
235 automatically resize the widget in order to avoid scroll bars
236 where they can be avoided, or to take advantage of extra space.
237 But the scroll area will honor the minimum size hint of its child
238 widget independent of the widget resizable property. So in this
239 example we set \c {imageLabel}'s size policy to \l
240 {QSizePolicy::Ignored}{ignored} in the constructor, to avoid that
241 scroll bars appear when the scroll area becomes smaller than the
242 label's minimum size hint.
244 The screenshots below shows an image in its normal size, and the
245 same image with the \gui {Fit to window} option turned on.
246 Enlarging the window will stretch the image further, as shown in
247 the third screenshot.
251 \o \inlineimage imageviewer-original_size.png
252 \o \inlineimage imageviewer-fit_to_window_1.png
253 \o \inlineimage imageviewer-fit_to_window_2.png
256 If the slot is called to turn off the option, the
257 {QScrollArea::setWidgetResizable} property is set to \c false. We
258 also restore the image pixmap to its normal size by adjusting the
259 label's size to its content. And in the end we update the view
262 \snippet examples/widgets/imageviewer/imageviewer.cpp 15
263 \snippet examples/widgets/imageviewer/imageviewer.cpp 16
265 We implement the \c about() slot to create a message box
266 describing what the example is designed to show.
268 \snippet examples/widgets/imageviewer/imageviewer.cpp 17
269 \snippet examples/widgets/imageviewer/imageviewer.cpp 18
271 In the private \c createAction() function, we create the
272 actions providing the application features.
274 We assign a short-cut key to each action and connect them to the
275 appropiate slots. We only enable the \c openAct and \c exitAxt at
276 the time of creation, the others are updated once an image has
277 been loaded into the application. In addition we make the \c
278 fitToWindowAct \l {QAction::checkable}{checkable}.
280 \snippet examples/widgets/imageviewer/imageviewer.cpp 19
281 \snippet examples/widgets/imageviewer/imageviewer.cpp 20
283 In the private \c createMenu() function, we add the previously
284 created actions to the \gui File, \gui View and \gui Help menus.
286 The QMenu class provides a menu widget for use in menu bars,
287 context menus, and other popup menus. The QMenuBar class provides
288 a horizontal menu bar that consists of a list of pull-down menu
289 items. So at the end we put the menus in the \c {ImageViewer}'s
290 menu bar which we retrieve with the QMainWindow::menuBar()
293 \snippet examples/widgets/imageviewer/imageviewer.cpp 21
294 \snippet examples/widgets/imageviewer/imageviewer.cpp 22
296 The private \c updateActions() function enables or disables the
297 \gui {Zoom In}, \gui {Zoom Out} and \gui {Normal Size} menu
298 entries depending on whether the \gui {Fit to Window} option is
301 \snippet examples/widgets/imageviewer/imageviewer.cpp 23
302 \snippet examples/widgets/imageviewer/imageviewer.cpp 24
304 In \c scaleImage(), we use the \c factor parameter to calculate
305 the new scaling factor for the displayed image, and resize \c
306 imageLabel. Since we set the
307 \l{QLabel::scaledContents}{scaledContents} property to \c true in
308 the constructor, the call to QWidget::resize() will scale the
309 image displayed in the label. We also adjust the scroll bars to
310 preserve the focal point of the image.
312 At the end, if the scale factor is less than 33.3% or greater
313 than 300%, we disable the respective menu entry to prevent the
314 image pixmap from becoming too large, consuming too much
315 resources in the window system.
317 \snippet examples/widgets/imageviewer/imageviewer.cpp 25
318 \snippet examples/widgets/imageviewer/imageviewer.cpp 26
320 Whenever we zoom in or out, we need to adjust the scroll bars in
321 consequence. It would have been tempting to simply call
323 \snippet doc/src/snippets/code/doc_src_examples_imageviewer.cpp 4
325 but this would make the top-left corner the focal point, not the
326 center. Therefore we need to take into account the scroll bar
327 handle's size (the \l{QScrollBar::pageStep}{page step}).