doc/src/examples/imageviewer.qdoc
changeset 0 1918ee327afb
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     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 */