Polish the screen shot example.
- Remove unneeded member variables. - Set window sizes depending on screen geometry for High DPI screens. - Flesh out code for saving the image, setting the supported mime types on the file dialog. - Streamline constructor code, remove create...() functions. - Use new connection syntax in createActions(), - Obtain the screen from the widget. - Adapt documentation. Remove note saying that widgets do not need the parent parameter (since creating parentless widgets can result in flicker in some cases), explain that QScreen pointers should be checked. Change-Id: I0332bbf10eafe861fe3fd5573522694ab5c0183a Reviewed-by: Topi Reiniö <topi.reinio@digia.com>
This commit is contained in:
parent
3363398802
commit
01c6f7200a
@ -39,13 +39,16 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDesktopWidget>
|
||||
|
||||
#include "screenshot.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
|
||||
Screenshot screenshot;
|
||||
screenshot.move(QApplication::desktop()->availableGeometry(&screenshot).topLeft() + QPoint(20, 20));
|
||||
screenshot.show();
|
||||
return app.exec();
|
||||
}
|
||||
|
@ -44,20 +44,48 @@
|
||||
|
||||
//! [0]
|
||||
Screenshot::Screenshot()
|
||||
: screenshotLabel(new QLabel(this))
|
||||
{
|
||||
screenshotLabel = new QLabel;
|
||||
screenshotLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
screenshotLabel->setAlignment(Qt::AlignCenter);
|
||||
screenshotLabel->setMinimumSize(240, 160);
|
||||
|
||||
createOptionsGroupBox();
|
||||
createButtonsLayout();
|
||||
const QRect screenGeometry = QApplication::desktop()->screenGeometry(this);
|
||||
screenshotLabel->setMinimumSize(screenGeometry.width() / 8, screenGeometry.height() / 8);
|
||||
|
||||
mainLayout = new QVBoxLayout;
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
||||
mainLayout->addWidget(screenshotLabel);
|
||||
|
||||
QGroupBox *optionsGroupBox = new QGroupBox(tr("Options"), this);
|
||||
delaySpinBox = new QSpinBox(optionsGroupBox);
|
||||
delaySpinBox->setSuffix(tr(" s"));
|
||||
delaySpinBox->setMaximum(60);
|
||||
|
||||
typedef void (QSpinBox::*QSpinBoxIntSignal)(int);
|
||||
connect(delaySpinBox, static_cast<QSpinBoxIntSignal>(&QSpinBox::valueChanged),
|
||||
this, &Screenshot::updateCheckBox);
|
||||
|
||||
hideThisWindowCheckBox = new QCheckBox(tr("Hide This Window"), optionsGroupBox);
|
||||
|
||||
QGridLayout *optionsGroupBoxLayout = new QGridLayout(optionsGroupBox);
|
||||
optionsGroupBoxLayout->addWidget(new QLabel(tr("Screenshot Delay:"), this), 0, 0);
|
||||
optionsGroupBoxLayout->addWidget(delaySpinBox, 0, 1);
|
||||
optionsGroupBoxLayout->addWidget(hideThisWindowCheckBox, 1, 0, 1, 2);
|
||||
|
||||
mainLayout->addWidget(optionsGroupBox);
|
||||
|
||||
QHBoxLayout *buttonsLayout = new QHBoxLayout;
|
||||
newScreenshotButton = new QPushButton(tr("New Screenshot"), this);
|
||||
connect(newScreenshotButton, &QPushButton::clicked, this, &Screenshot::newScreenshot);
|
||||
buttonsLayout->addWidget(newScreenshotButton);
|
||||
QPushButton *saveScreenshotButton = new QPushButton(tr("Save Screenshot"), this);
|
||||
connect(saveScreenshotButton, &QPushButton::clicked, this, &Screenshot::saveScreenshot);
|
||||
buttonsLayout->addWidget(saveScreenshotButton);
|
||||
QPushButton *quitScreenshotButton = new QPushButton(tr("Quit"), this);
|
||||
quitScreenshotButton->setShortcut(Qt::CTRL + Qt::Key_Q);
|
||||
connect(quitScreenshotButton, &QPushButton::clicked, this, &QWidget::close);
|
||||
buttonsLayout->addWidget(quitScreenshotButton);
|
||||
buttonsLayout->addStretch();
|
||||
mainLayout->addLayout(buttonsLayout);
|
||||
setLayout(mainLayout);
|
||||
|
||||
shootScreen();
|
||||
delaySpinBox->setValue(5);
|
||||
@ -84,44 +112,59 @@ void Screenshot::newScreenshot()
|
||||
hide();
|
||||
newScreenshotButton->setDisabled(true);
|
||||
|
||||
QTimer::singleShot(delaySpinBox->value() * 1000, this, SLOT(shootScreen()));
|
||||
QTimer::singleShot(delaySpinBox->value() * 1000, this, &Screenshot::shootScreen);
|
||||
}
|
||||
//! [2]
|
||||
|
||||
//! [3]
|
||||
void Screenshot::saveScreenshot()
|
||||
{
|
||||
QString format = "png";
|
||||
QString initialPath = QDir::currentPath() + tr("/untitled.") + format;
|
||||
const QString format = "png";
|
||||
QString initialPath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
|
||||
if (initialPath.isEmpty())
|
||||
initialPath = QDir::currentPath();
|
||||
initialPath += tr("/untitled.") + format;
|
||||
|
||||
QString fileName = QFileDialog::getSaveFileName(this, tr("Save As"), initialPath,
|
||||
tr("%1 Files (*.%2);;All Files (*)")
|
||||
.arg(format.toUpper())
|
||||
.arg(format));
|
||||
if (!fileName.isEmpty())
|
||||
originalPixmap.save(fileName, format.toLatin1().constData());
|
||||
QFileDialog fileDialog(this, tr("Save As"), initialPath);
|
||||
fileDialog.setAcceptMode(QFileDialog::AcceptSave);
|
||||
fileDialog.setFileMode(QFileDialog::AnyFile);
|
||||
fileDialog.setDirectory(initialPath);
|
||||
QStringList mimeTypes;
|
||||
foreach (const QByteArray &bf, QImageWriter::supportedMimeTypes())
|
||||
mimeTypes.append(QLatin1String(bf));
|
||||
fileDialog.setMimeTypeFilters(mimeTypes);
|
||||
fileDialog.selectMimeTypeFilter("image/" + format);
|
||||
fileDialog.setDefaultSuffix(format);
|
||||
if (fileDialog.exec() != QDialog::Accepted)
|
||||
return;
|
||||
const QString fileName = fileDialog.selectedFiles().first();
|
||||
if (!originalPixmap.save(fileName)) {
|
||||
QMessageBox::warning(this, tr("Save Error"), tr("The image could not be saved to \"%1\".")
|
||||
.arg(QDir::toNativeSeparators(fileName)));
|
||||
}
|
||||
}
|
||||
//! [3]
|
||||
|
||||
//! [4]
|
||||
void Screenshot::shootScreen()
|
||||
{
|
||||
if (delaySpinBox->value() != 0)
|
||||
qApp->beep();
|
||||
//! [4]
|
||||
originalPixmap = QPixmap(); // clear image for low memory situations
|
||||
// on embedded devices.
|
||||
//! [5]
|
||||
QScreen *screen = QGuiApplication::primaryScreen();
|
||||
if (screen)
|
||||
originalPixmap = screen->grabWindow(0);
|
||||
if (const QWindow *window = windowHandle())
|
||||
screen = window->screen();
|
||||
if (!screen)
|
||||
return;
|
||||
|
||||
if (delaySpinBox->value() != 0)
|
||||
QApplication::beep();
|
||||
|
||||
originalPixmap = screen->grabWindow(0);
|
||||
updateScreenshotLabel();
|
||||
|
||||
newScreenshotButton->setDisabled(false);
|
||||
if (hideThisWindowCheckBox->isChecked())
|
||||
show();
|
||||
}
|
||||
//! [5]
|
||||
//! [4]
|
||||
|
||||
//! [6]
|
||||
void Screenshot::updateCheckBox()
|
||||
@ -135,52 +178,6 @@ void Screenshot::updateCheckBox()
|
||||
}
|
||||
//! [6]
|
||||
|
||||
//! [7]
|
||||
void Screenshot::createOptionsGroupBox()
|
||||
{
|
||||
optionsGroupBox = new QGroupBox(tr("Options"));
|
||||
|
||||
delaySpinBox = new QSpinBox;
|
||||
delaySpinBox->setSuffix(tr(" s"));
|
||||
delaySpinBox->setMaximum(60);
|
||||
connect(delaySpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateCheckBox()));
|
||||
|
||||
delaySpinBoxLabel = new QLabel(tr("Screenshot Delay:"));
|
||||
|
||||
hideThisWindowCheckBox = new QCheckBox(tr("Hide This Window"));
|
||||
|
||||
optionsGroupBoxLayout = new QGridLayout;
|
||||
optionsGroupBoxLayout->addWidget(delaySpinBoxLabel, 0, 0);
|
||||
optionsGroupBoxLayout->addWidget(delaySpinBox, 0, 1);
|
||||
optionsGroupBoxLayout->addWidget(hideThisWindowCheckBox, 1, 0, 1, 2);
|
||||
optionsGroupBox->setLayout(optionsGroupBoxLayout);
|
||||
}
|
||||
//! [7]
|
||||
|
||||
//! [8]
|
||||
void Screenshot::createButtonsLayout()
|
||||
{
|
||||
newScreenshotButton = createButton(tr("New Screenshot"), this, SLOT(newScreenshot()));
|
||||
saveScreenshotButton = createButton(tr("Save Screenshot"), this, SLOT(saveScreenshot()));
|
||||
quitScreenshotButton = createButton(tr("Quit"), this, SLOT(close()));
|
||||
|
||||
buttonsLayout = new QHBoxLayout;
|
||||
buttonsLayout->addStretch();
|
||||
buttonsLayout->addWidget(newScreenshotButton);
|
||||
buttonsLayout->addWidget(saveScreenshotButton);
|
||||
buttonsLayout->addWidget(quitScreenshotButton);
|
||||
}
|
||||
//! [8]
|
||||
|
||||
//! [9]
|
||||
QPushButton *Screenshot::createButton(const QString &text, QWidget *receiver,
|
||||
const char *member)
|
||||
{
|
||||
QPushButton *button = new QPushButton(text);
|
||||
button->connect(button, SIGNAL(clicked()), receiver, member);
|
||||
return button;
|
||||
}
|
||||
//! [9]
|
||||
|
||||
//! [10]
|
||||
void Screenshot::updateScreenshotLabel()
|
||||
|
@ -73,25 +73,14 @@ private slots:
|
||||
void updateCheckBox();
|
||||
|
||||
private:
|
||||
void createOptionsGroupBox();
|
||||
void createButtonsLayout();
|
||||
QPushButton *createButton(const QString &text, QWidget *receiver, const char *member);
|
||||
void updateScreenshotLabel();
|
||||
|
||||
QPixmap originalPixmap;
|
||||
|
||||
QLabel *screenshotLabel;
|
||||
QGroupBox *optionsGroupBox;
|
||||
QSpinBox *delaySpinBox;
|
||||
QLabel *delaySpinBoxLabel;
|
||||
QCheckBox *hideThisWindowCheckBox;
|
||||
QPushButton *newScreenshotButton;
|
||||
QPushButton *saveScreenshotButton;
|
||||
QPushButton *quitScreenshotButton;
|
||||
|
||||
QVBoxLayout *mainLayout;
|
||||
QGridLayout *optionsGroupBoxLayout;
|
||||
QHBoxLayout *buttonsLayout;
|
||||
};
|
||||
//! [0]
|
||||
|
||||
|
@ -33,7 +33,7 @@
|
||||
desktop.
|
||||
|
||||
\brief The Screenshot example shows how to take a screenshot of the
|
||||
desktop using QApplication and QDesktopWidget. It also shows how
|
||||
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.
|
||||
@ -73,12 +73,9 @@
|
||||
\uicontrol {Hide This Window} option.
|
||||
\endlist
|
||||
|
||||
We also declare some private functions: We use the \c
|
||||
createOptionsGroupBox(), \c createButtonsLayout() and \c
|
||||
createButton() functions when we construct the widget. And we call
|
||||
the private \c updateScreenshotLabel() function whenever a new
|
||||
screenshot is taken or when a resize event changes the size of the
|
||||
screenshot preview label.
|
||||
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
|
||||
@ -100,11 +97,18 @@
|
||||
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.
|
||||
suitable size depending on the screen geometry.
|
||||
|
||||
\snippet desktop/screenshot/screenshot.cpp 1
|
||||
|
||||
@ -151,34 +155,37 @@
|
||||
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.
|
||||
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 path the application is run from. We
|
||||
create the file dialog using the static
|
||||
QFileDialog::getSaveFileName() function which returns a file name
|
||||
selected by the user. The file does not have to exist. If 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
|
||||
The \c shootScreen() slot is called to take the screenshot.
|
||||
|
||||
First, we find the instance of QScreen the window is located
|
||||
by retrieving the QWindow and its QScreen, defaulting
|
||||
to the primary screen. If no screen can be found, we return.
|
||||
Although this is unlikely to happen, applications should check
|
||||
for null pointers since there might be situations in which no
|
||||
screen is connected.
|
||||
|
||||
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.
|
||||
|
||||
The QApplication class manages the GUI application's control flow
|
||||
and main settings. It contains the main event loop, where all
|
||||
events from the window system and other sources are processed and
|
||||
dispatched.
|
||||
|
||||
\snippet desktop/screenshot/screenshot.cpp 5
|
||||
|
||||
Using the static function QApplication::primaryScreen(), we
|
||||
obtain the QScreen object for the application's main screen.
|
||||
|
||||
We take the screenshot using the QScreen::grabWindow()
|
||||
We then take the screenshot using the QScreen::grabWindow()
|
||||
function. 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().
|
||||
@ -200,37 +207,6 @@
|
||||
The \c updateCheckBox() slot is called whenever the user changes
|
||||
the delay using the \uicontrol {Screenshot Delay} option.
|
||||
|
||||
\snippet desktop/screenshot/screenshot.cpp 7
|
||||
|
||||
The private \c createOptionsGroupBox() function is called from the
|
||||
constructor.
|
||||
|
||||
First 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 and install the layout on the group box.
|
||||
|
||||
Note that we don't have to specify any parents for the widgets
|
||||
when we create them. The reason is that when we add a widget to a
|
||||
layout and install the layout on another widget, the layout's
|
||||
widgets are automatically reparented to the widget the layout is
|
||||
installed on.
|
||||
|
||||
\snippet desktop/screenshot/screenshot.cpp 8
|
||||
|
||||
The private \c createButtonsLayout() function is called from the
|
||||
constructor. We create the application's buttons using the private
|
||||
\c createButton() function, and add them to a QHBoxLayout.
|
||||
|
||||
\snippet desktop/screenshot/screenshot.cpp 9
|
||||
|
||||
The private \c createButton() function is called from the \c
|
||||
createButtonsLayout() function. It simply creates a QPushButton
|
||||
with the provided text, connects it to the provided receiver and
|
||||
slot, and returns a pointer to the button.
|
||||
|
||||
\snippet desktop/screenshot/screenshot.cpp 10
|
||||
|
||||
The private \c updateScreenshotLabel() function is called whenever
|
||||
|
Loading…
Reference in New Issue
Block a user