Update copyright headers
[qt:qt.git] / doc / src / examples / imageviewer.qdoc
1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the documentation of the Qt Toolkit.
7 **
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.
16 **
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.
24 ** $QT_END_LICENSE$
25 **
26 ****************************************************************************/
27
28 /*!
29     \example widgets/imageviewer
30     \title Image Viewer Example
31
32     \brief The Image Viewer example shows how to combine QLabel and QScrollArea to
33     display an image.
34     
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
39     bars.
40
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.
46
47     \image imageviewer-example.png Screenshot of the Image Viewer example
48
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
51     to:
52
53     \list
54     \o \gui{Open...} - Open an image file
55     \o \gui{Print...} - Print an image
56     \o \gui{Exit} - Exit the application
57     \endlist
58
59     Once an image is loaded, the \gui View menu allows the users to:
60
61     \list
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
66     \endlist
67
68     In addition the \gui Help menu provides the users with information
69     about the Image Viewer example in particular, and about Qt in
70     general.
71
72     \section1 ImageViewer Class Definition
73
74     \snippet examples/widgets/imageviewer/imageviewer.h 0
75
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.
79
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
86     scaling an image.
87
88     \section1 ImageViewer Class Implementation
89
90     \snippet examples/widgets/imageviewer/imageviewer.cpp 0
91
92     In the constructor we first create the label and the scroll area.
93
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
100     hint.
101
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.
108
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.
113
114     \snippet examples/widgets/imageviewer/imageviewer.cpp 1
115     \snippet examples/widgets/imageviewer/imageviewer.cpp 2
116
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.
122
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.
127
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.
137
138     \snippet examples/widgets/imageviewer/imageviewer.cpp 3
139     \snippet examples/widgets/imageviewer/imageviewer.cpp 4
140
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.
146
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
153
154     \snippet doc/src/snippets/code/doc_src_examples_imageviewer.cpp 0
155
156     In the \c print() slot, we first make sure that an image has been
157     loaded into the application:
158
159     \snippet examples/widgets/imageviewer/imageviewer.cpp 5
160     \snippet examples/widgets/imageviewer/imageviewer.cpp 6
161
162     If the application is built in debug mode, the \c Q_ASSERT() macro
163     will expand to
164
165     \snippet doc/src/snippets/code/doc_src_examples_imageviewer.cpp 1
166
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:
170
171     \snippet doc/src/snippets/code/doc_src_examples_imageviewer.qdoc 2
172
173     or
174
175     \snippet doc/src/snippets/code/doc_src_examples_imageviewer.qdoc 3
176
177     Another approach is to add this line directly to the \c .pro
178     file.
179
180     \snippet examples/widgets/imageviewer/imageviewer.cpp 7
181     \snippet examples/widgets/imageviewer/imageviewer.cpp 8
182
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}.
189
190     In the end we draw the pixmap at position (0, 0).
191
192     \snippet examples/widgets/imageviewer/imageviewer.cpp 9
193     \snippet examples/widgets/imageviewer/imageviewer.cpp 10
194
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.
201
202     The screenshots below show an image in its normal size, and the
203     same image after zooming in:
204
205     \table
206     \row
207     \o \inlineimage imageviewer-original_size.png
208     \o \inlineimage imageviewer-zoom_in_1.png
209     \o \inlineimage imageviewer-zoom_in_2.png
210     \endtable
211
212     \snippet examples/widgets/imageviewer/imageviewer.cpp 11
213     \snippet examples/widgets/imageviewer/imageviewer.cpp 12
214
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.
221
222     \snippet examples/widgets/imageviewer/imageviewer.cpp 13
223     \snippet examples/widgets/imageviewer/imageviewer.cpp 14
224
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.
231
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.
243
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.
248
249     \table
250     \row
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
254     \endtable
255
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
260     menu entries.
261
262     \snippet examples/widgets/imageviewer/imageviewer.cpp 15
263     \snippet examples/widgets/imageviewer/imageviewer.cpp 16
264
265     We implement the \c about() slot to create a message box
266     describing what the example is designed to show.
267
268     \snippet examples/widgets/imageviewer/imageviewer.cpp 17
269     \snippet examples/widgets/imageviewer/imageviewer.cpp 18
270
271     In the private \c createAction() function, we create the
272     actions providing the application features.
273
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}.
279
280     \snippet examples/widgets/imageviewer/imageviewer.cpp 19
281     \snippet examples/widgets/imageviewer/imageviewer.cpp 20
282
283     In the private \c createMenu() function, we add the previously
284     created actions to the \gui File, \gui View and \gui Help menus.
285
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()
291     function.
292
293     \snippet examples/widgets/imageviewer/imageviewer.cpp 21
294     \snippet examples/widgets/imageviewer/imageviewer.cpp 22
295
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
299     turned on or off.
300
301     \snippet examples/widgets/imageviewer/imageviewer.cpp 23
302     \snippet examples/widgets/imageviewer/imageviewer.cpp 24
303
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.
311
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.
316
317     \snippet examples/widgets/imageviewer/imageviewer.cpp 25
318     \snippet examples/widgets/imageviewer/imageviewer.cpp 26
319
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
322
323     \snippet doc/src/snippets/code/doc_src_examples_imageviewer.cpp 4
324
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}).
328 */