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