Move image viewer example to manual test
Change-Id: I4b64033f1a075681ce5b918fdf2e018ad05a7869 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io> (cherry picked from commit b8f588bea74aae0a890e1af18b936b0bfbf8c237) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
d6bf951b76
commit
f61c424919
Binary file not shown.
Before Width: | Height: | Size: 83 KiB |
Binary file not shown.
Before Width: | Height: | Size: 143 KiB |
Binary file not shown.
Before Width: | Height: | Size: 60 KiB |
Binary file not shown.
Before Width: | Height: | Size: 83 KiB |
Binary file not shown.
Before Width: | Height: | Size: 84 KiB |
@ -1,320 +0,0 @@
|
|||||||
// Copyright (C) 2016 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\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().isNull())
|
|
||||||
qFatal("ASSERT: "imageLabel->pixmap().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}).
|
|
||||||
*/
|
|
@ -5,7 +5,6 @@ qt_internal_add_example(analogclock)
|
|||||||
qt_internal_add_example(calculator)
|
qt_internal_add_example(calculator)
|
||||||
qt_internal_add_example(calendarwidget)
|
qt_internal_add_example(calendarwidget)
|
||||||
qt_internal_add_example(groupbox)
|
qt_internal_add_example(groupbox)
|
||||||
qt_internal_add_example(imageviewer)
|
|
||||||
qt_internal_add_example(lineedits)
|
qt_internal_add_example(lineedits)
|
||||||
if(QT_FEATURE_movie)
|
if(QT_FEATURE_movie)
|
||||||
qt_internal_add_example(movie)
|
qt_internal_add_example(movie)
|
||||||
|
@ -3,7 +3,6 @@ SUBDIRS = analogclock \
|
|||||||
calculator \
|
calculator \
|
||||||
calendarwidget \
|
calendarwidget \
|
||||||
groupbox \
|
groupbox \
|
||||||
imageviewer \
|
|
||||||
lineedits \
|
lineedits \
|
||||||
movie \
|
movie \
|
||||||
scribble \
|
scribble \
|
||||||
|
@ -91,11 +91,7 @@ QT_BEGIN_NAMESPACE
|
|||||||
cause the size of the scroll area to be updated whenever the
|
cause the size of the scroll area to be updated whenever the
|
||||||
contents of the layout changes.
|
contents of the layout changes.
|
||||||
|
|
||||||
For a complete example using the QScrollArea class, see the \l
|
\sa QAbstractScrollArea, QScrollBar
|
||||||
{widgets/imageviewer}{Image Viewer} example. The example shows how
|
|
||||||
to combine QLabel and QScrollArea to display an image.
|
|
||||||
|
|
||||||
\sa QAbstractScrollArea, QScrollBar, {Image Viewer Example}
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user