Revision control
++ // Copyright (C) 2016 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
++
++ /*!
++ \example desktop/screenshot
++ \title Taking a Screenshot
++ \examplecategory {Desktop}
++ \ingroup examples-desktop
++ \brief The Screenshot example shows how to take a screenshot of the
++ desktop.
++
++ \brief The Screenshot example shows how to take a screenshot of the
++ desktop using QScreen. It also shows how
++ to use QTimer to provide a single-shot timer, and how to
++ reimplement the QWidget::resizeEvent() event handler to make sure
++ that an application resizes smoothly and without data loss.
++
++ \image screenshot-example.png
++ {Application with options for taking desktop screenshots}
++
++ With the application the users can take a screenshot of their
++ desktop. They are provided with a couple of options:
++
++ \list
++ \li Delaying the screenshot, giving them time to rearrange
++ their desktop.
++ \li Hiding the application's window while the screenshot is taken.
++ \endlist
++
++ In addition the application allows the users to save their
++ screenshot if they want to.
++
++ \section1 Screenshot Class Definition
++
++ \snippet desktop/screenshot/screenshot.h 0
++
++ The \c Screenshot class inherits QWidget and is the application's
++ main widget. It displays the application options and a preview of
++ the screenshot.
++
++ We reimplement the QWidget::resizeEvent() function to make sure
++ that the preview of the screenshot scales properly when the user
++ resizes the application widget. We also need several private slots
++ to facilitate the options:
++
++ \list
++ \li The \c newScreenshot() slot prepares a new screenshot.
++ \li The \c saveScreenshot() slot saves the last screenshot.
++ \li The \c shootScreen() slot takes the screenshot.
++ \li The \c updateCheckBox() slot enables or disables the
++ \uicontrol {Hide This Window} option.
++ \endlist
++
++ We also declare the private function \c updateScreenshotLabel() which
++ is called whenever a new screenshot is taken or when a resize event
++ changes the size of the screenshot preview label.
++
++ In addition we need to store the screenshot's original pixmap. The
++ reason is that when we display the preview of the screenshot, we
++ need to scale its pixmap, storing the original we make sure that
++ no data are lost in that process.
++
++ \section1 Screenshot Class Implementation
++
++ \snippet desktop/screenshot/screenshot.cpp 0
++
++ In the constructor we first create the QLabel displaying the
++ screenshot preview.
++
++ We set the QLabel's size policy to be QSizePolicy::Expanding both
++ horizontally and vertically. This means that the QLabel's size
++ hint is a sensible size, but the widget can be shrunk and still be
++ useful. Also, the widget can make use of extra space, so it should
++ get as much space as possible. Then we make sure the QLabel is
++ aligned in the center of the \c Screenshot widget, and set its
++ minimum size.
++
++ Next, we create a group box that will contain all of the options'
++ widgets. Then we create a QSpinBox and a QLabel for the \uicontrol
++ {Screenshot Delay} option, and connect the spinbox to the \c
++ updateCheckBox() slot. Finally, we create a QCheckBox for the \uicontrol
++ {Hide This Window} option, add all the options' widgets to a
++ QGridLayout installed on the group box.
++
++ We create the applications's buttons and the group box containing
++ the application's options, and put it all into a main
++ layout. Finally we take the initial screenshot, and set the initial
++ delay and the window title, before we resize the widget to a
++ suitable size depending on the screen geometry.
++
++ \snippet desktop/screenshot/screenshot.cpp 1
++
++ The \c resizeEvent() function is reimplemented to receive the
++ resize events dispatched to the widget. The purpose is to scale
++ the preview screenshot pixmap without deformation of its content,
++ and also make sure that the application can be resized smoothly.
++
++ To achieve the first goal, we scale the screenshot pixmap using
++ Qt::KeepAspectRatio. We scale the pixmap to a rectangle as large
++ as possible inside the current size of the screenshot preview
++ label, preserving the aspect ratio. This means that if the user
++ resizes the application window in only one direction, the preview
++ screenshot keeps the same size.
++
++ To reach our second goal, we make sure that the preview screenshot
++ only is repainted (using the private \c updateScreenshotLabel()
++ function) when it actually changes its size.
++
++ \snippet desktop/screenshot/screenshot.cpp 2
++
++ The private \c newScreenshot() slot is called when the user
++ requests a new screenshot; but the slot only prepares a new
++ screenshot.
++
++ First we see if the \uicontrol {Hide This Window} option is checked, if
++ it is we hide the \c Screenshot widget. Then we disable the \uicontrol
++ {New Screenshot} button, to make sure the user only can request
++ one screenshot at a time.
++
++ We create a timer using the QTimer class which provides repetitive
++ and single-shot timers. We set the timer to time out only once,
++ using the static QTimer::singleShot() function. This function
++ calls the private \c shootScreen() slot after the time interval
++ specified by the \uicontrol {Screenshot Delay} option. It is \c
++ shootScreen() that actually performs the screenshot.
++
++ \snippet desktop/screenshot/screenshot.cpp 3
++
++ The \c saveScreenshot() slot is called when the user push the \uicontrol
++ Save button, and it presents a file dialog using the QFileDialog
++ class.
++
++ QFileDialog enables a user to traverse the file system in order to
++ select one or many files or a directory. The easiest way to create
++ a QFileDialog is to use the convenience static
++ functions. Here, we instantiate the dialog on the stack in order
++ to be able to set up the supported mime types of QImageWriter,
++ allowing the user to save in a variety of formats.
++
++ We define the default file format to be png, and we make the file
++ dialog's initial path the location of pictures as obtained from
++ QStandardPaths, defaulting to the path the application is run from.
++
++ We run the dialog by invoking QDialog::exec() and return if the
++ user canceled the dialog. If the dialog has been accepted, we
++ obtain a file name by calling QFileDialog::selectedFiles().
++ The file does not have to exist. If the file
++ name is valid, we use the QPixmap::save() function to save the
++ screenshot's original pixmap in that file.
++
++ \snippet desktop/screenshot/screenshot.cpp 4
++
++ The \c shootScreen() slot is called to take the screenshot.
++
++ If the user has chosen to delay the screenshot, we make the application
++ beep when the screenshot is taken using the static
++ QApplication::beep() function.
++
++ We then take the screenshot using the QScreen::grabWindow()
++ function on the screen returned by QWidget::screen().
++ The function grabs the contents of the window passed as
++ an argument, makes a pixmap out of it and returns that pixmap.
++ The window id can be obtained with QWidget::winId() or QWindow::winId().
++ Here, however, we just pass 0 as the window id, indicating that we
++ want to grab the entire screen.
++
++ We update the screenshot preview label using the private \c
++ updateScreenshotLabel() function. Then we enable the \uicontrol {New
++ Screenshot} button, and finally we make the \c Screenshot widget
++ visible if it was hidden during the screenshot.
++
++ \snippet desktop/screenshot/screenshot.cpp 6
++
++ The \uicontrol {Hide This Window} option is enabled or disabled
++ depending on the delay of the screenshot. If there is no delay,
++ the application window cannot be hidden and the option's checkbox
++ is disabled.
++
++ The \c updateCheckBox() slot is called whenever the user changes
++ the delay using the \uicontrol {Screenshot Delay} option.
++
++ \snippet desktop/screenshot/screenshot.cpp 10
++
++ The private \c updateScreenshotLabel() function is called whenever
++ the screenshot changes, or when a resize event changes the size of
++ the screenshot preview label.
++
++ First, we handle the failure case. On some platforms, namely
++ Wayland, it is not possible to retrieve the screen content.
++ In this case, the pixmap is empty as indicated by QPixmap::isNull().
++ We set an error string on the label and disable the button for
++ saving.
++
++ If a pixmap was obtained, we update the screenshot preview's
++ label using the QLabel::setPixmap() and QPixmap::scaled()
++ functions.
++
++ QPixmap::scaled() returns a copy of the given pixmap scaled to a
++ rectangle of the given size according to the given
++ Qt::AspectRatioMode and Qt::TransformationMode.
++
++ We scale the original pixmap to fit the current screenshot label's
++ size, preserving the aspect ratio and giving the resulting pixmap
++ smoothed edges.
++ */
++