Faire une capture d'écran
L'exemple « Capture d'écran » montre comment réaliser une capture d'écran du bureau.

Grâce à cette application, les utilisateurs peuvent réaliser une capture d'écran de leur bureau. Plusieurs options s'offrent à eux :
- Retarder la capture d'écran, ce qui leur laisse le temps de réorganiser leur bureau.
- Masquer la fenêtre de l'application pendant la prise de capture d'écran.
De plus, l'application permet aux utilisateurs d'enregistrer leur capture d'écran s'ils le souhaitent.
Définition de la classe Screenshot
class Screenshot : public QWidget
{
Q_OBJECT
public:
Screenshot();
protected:
void resizeEvent(QResizeEvent *event) override;
private slots:
void newScreenshot();
void saveScreenshot();
void shootScreen();
void updateCheckBox();
private:
void updateScreenshotLabel();
QPixmap originalPixmap;
QLabel *screenshotLabel;
QSpinBox *delaySpinBox;
QCheckBox *hideThisWindowCheckBox;
QPushButton *newScreenshotButton;
QPushButton *saveScreenshotButton;
};La classe ` Screenshot ` hérite de ` QWidget ` et constitue le widget principal de l'application. Elle affiche les options de l'application ainsi qu'un aperçu de la capture d'écran.
Nous réimplémentons la fonction ` QWidget::resizeEvent()` pour nous assurer que l’aperçu de la capture d’écran s’adapte correctement lorsque l’utilisateur redimensionne le widget de l’application. Nous avons également besoin de plusieurs slots privés pour gérer les options :
- Le slot `
newScreenshot()` prépare une nouvelle capture d’écran. - Le slot `
saveScreenshot()` enregistre la dernière capture d’écran. - Le slot `
shootScreen()` prend la capture d’écran. - Le slot
updateCheckBox()active ou désactive l’option « Hide This Window ».
Nous déclarons également la fonction privée updateScreenshotLabel(), qui est appelée chaque fois qu’une nouvelle capture d’écran est prise ou lorsqu’un événement de redimensionnement modifie la taille de l’étiquette d’aperçu de la capture d’écran.
De plus, nous devons stocker le pixmap d’origine de la capture d’écran. En effet, lorsque nous affichons l’aperçu de la capture d’écran, nous devons redimensionner son pixmap ; en conservant l’original, nous nous assurons qu’aucune donnée n’est perdue au cours de ce processus.
Implémentation de la classe Screenshot
Screenshot::Screenshot()
: screenshotLabel(new QLabel(this))
{
screenshotLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
screenshotLabel->setAlignment(Qt::AlignCenter);
const QRect screenGeometry = screen()->geometry();
screenshotLabel->setMinimumSize(screenGeometry.width() / 8, screenGeometry.height() / 8);
screenshotLabel->setFrameShape(QFrame::Box);
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);
connect(delaySpinBox, &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);
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);
shootScreen();
delaySpinBox->setValue(5);
setWindowTitle(tr("Screenshot"));
resize(300, 200);
}Dans le constructeur, nous créons d’abord l’ QLabel qui affiche l’aperçu de la capture d’écran.
Nous définissons la politique de taille de l’ QLabel sur « QSizePolicy::Expanding » (adaptable) à la fois horizontalement et verticalement. Cela signifie que la taille suggérée de l’ QLabel est raisonnable, mais que le widget peut être réduit tout en restant utile. De plus, le widget peut tirer parti de l’espace supplémentaire, il doit donc disposer d’autant d’espace que possible. Nous nous assurons ensuite que l’ QLabel est centré dans le widget Screenshot, puis nous définissons sa taille minimale.
Ensuite, nous créons une zone de groupe (group box) qui contiendra tous les widgets des options. Puis nous créons une zone de sélection ( QSpinBox ) et une zone de saisie ( QLabel ) pour l’option « Screenshot Delay », et nous connectons la zone de saisie à l’emplacement (slot) « updateCheckBox() ». Enfin, nous créons une zone de saisie ( QCheckBox ) pour l’option « Hide This Window », et ajoutons tous les widgets des options à une zone de contrôle ( QGridLayout ) installée sur la zone de groupe.
Nous créons les boutons de l’application ainsi que la zone de groupe contenant les options de l’application, puis nous intégrons le tout dans une disposition principale. Enfin, nous capturons la capture d’écran initiale, définissons le délai initial et le titre de la fenêtre, avant de redimensionner le widget à une taille adaptée en fonction de la géométrie de l’écran.
void Screenshot::resizeEvent(QResizeEvent * /* event */)
{
if (!originalPixmap.isNull()) {
QSize scaledSize = originalPixmap.size();
scaledSize.scale(screenshotLabel->size(), Qt::KeepAspectRatio);
if (scaledSize != screenshotLabel->pixmap().size())
updateScreenshotLabel();
}
}La fonction ` resizeEvent() ` est réimplémentée pour recevoir les événements de redimensionnement envoyés au widget. L’objectif est de mettre à l’échelle le pixmap de la capture d’écran d’aperçu sans déformer son contenu, et de s’assurer que l’application puisse être redimensionnée en douceur.
Pour atteindre le premier objectif, nous redimensionnons l’image de la capture d’écran à l’aide de ` Qt::KeepAspectRatio`. Nous redimensionnons l’image en un rectangle aussi grand que possible dans les limites de la taille actuelle de l’étiquette d’aperçu de la capture d’écran, tout en conservant le rapport d’aspect. Cela signifie que si l’utilisateur redimensionne la fenêtre de l’application dans une seule direction, la capture d’écran d’aperçu conserve la même taille.
Pour atteindre notre deuxième objectif, nous veillons à ce que la capture d’écran d’aperçu ne soit redessinée (à l’aide de la fonction privée ` updateScreenshotLabel() `) que lorsqu’elle change réellement de taille.
void Screenshot::newScreenshot()
{
if (hideThisWindowCheckBox->isChecked())
hide();
newScreenshotButton->setDisabled(true);
QTimer::singleShot(delaySpinBox->value() * 1000, this, &Screenshot::shootScreen);
}Le slot privé ` newScreenshot() ` est appelé lorsque l’utilisateur demande une nouvelle capture d’écran ; mais ce slot se contente de préparer une nouvelle capture d’écran.
Nous vérifions d’abord si l’option « Hide This Window » est cochée ; si c’est le cas, nous masquons le widget « Screenshot ». Ensuite, nous désactivons le bouton « New Screenshot », afin de nous assurer que l’utilisateur ne puisse demander qu’une seule capture d’écran à la fois.
Nous créons un minuteur à l’aide de la classe ` QTimer `, qui fournit des minuteurs répétitifs et à déclenchement unique. Nous configurons le minuteur pour qu’il ne se déclenche qu’une seule fois, à l’aide de la fonction statique ` QTimer::singleShot()`. Cette fonction appelle le slot privé ` shootScreen() ` après l’intervalle de temps spécifié par l’option ` Screenshot Delay `. C’est ` shootScreen() ` qui effectue effectivement la capture d’écran.
void Screenshot::saveScreenshot()
{
const QString format = "png";
QString initialPath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
if (initialPath.isEmpty())
initialPath = QDir::currentPath();
initialPath += tr("/untitled.") + format;
QFileDialog fileDialog(this, tr("Save As"), initialPath);
fileDialog.setAcceptMode(QFileDialog::AcceptSave);
fileDialog.setFileMode(QFileDialog::AnyFile);
fileDialog.setDirectory(initialPath);
QStringList mimeTypes;
const QList<QByteArray> baMimeTypes = QImageWriter::supportedMimeTypes();
for (const QByteArray &bf : baMimeTypes)
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)));
}
}Le slot saveScreenshot() est appelé lorsque l’utilisateur appuie sur le bouton Save; il affiche alors une boîte de dialogue de sélection de fichiers à l’aide de la classe QFileDialog.
QFileDialog permet à l’utilisateur de parcourir le système de fichiers afin de sélectionner un ou plusieurs fichiers, ou encore un répertoire. La manière la plus simple de créer une instance de ` QFileDialog ` consiste à utiliser les fonctions statiques de commodité. Ici, nous instancions la boîte de dialogue sur la pile afin de pouvoir configurer les types MIME pris en charge par ` QImageWriter`, ce qui permet à l’utilisateur d’enregistrer dans divers formats.
QStandardPathsNous définissons le format de fichier par défaut comme étant le format png, et nous fixons le chemin d’accès initial de la boîte de dialogue de fichier à l’emplacement des images tel qu’il est obtenu à partir de , par défaut le chemin à partir duquel l’application est exécutée.
Nous lançons la boîte de dialogue en appelant QDialog::exec() et nous quittons la fonction si l’utilisateur a annulé la boîte de dialogue. Si la boîte de dialogue a été acceptée, nous récupérons un nom de fichier en appelant QFileDialog::selectedFiles(). Le fichier n’a pas besoin d’exister. Si le nom de fichier est valide, nous utilisons la fonction QPixmap::save() pour enregistrer le pixmap original de la capture d’écran dans ce fichier.
void Screenshot::shootScreen()
{
if (delaySpinBox->value() != 0)
QApplication::beep();
originalPixmap = screen()->grabWindow(0);
updateScreenshotLabel();
newScreenshotButton->setDisabled(false);
if (hideThisWindowCheckBox->isChecked())
show();
}Le slot shootScreen() est appelé pour réaliser la capture d’écran.
Si l’utilisateur a choisi de différer la capture d’écran, nous faisons émettre un bip par l’application lorsque la capture est effectuée à l’aide de la fonction statique QApplication::beep().
Nous réalisons ensuite la capture d’écran à l’aide de la fonction ` QScreen::grabWindow()` sur la fenêtre renvoyée par ` QWidget::screen()`. Cette fonction capture le contenu de la fenêtre passée en argument, en crée une image bitmap et renvoie cette image. L’identifiant de la fenêtre peut être obtenu à l’aide de ` QWidget::winId()` ou ` QWindow::winId()`. Ici, cependant, nous passons simplement 0 comme identifiant de fenêtre, ce qui indique que nous souhaitons capturer l’intégralité de l’écran.
Nous mettons à jour le libellé d’aperçu de la capture d’écran à l’aide de la fonction privée ` updateScreenshotLabel() `. Ensuite, nous activons le bouton « New Screenshot », puis nous rendons le widget ` Screenshot ` visible s’il avait été masqué pendant la capture d’écran.
void Screenshot::updateCheckBox()
{
if (delaySpinBox->value() == 0) {
hideThisWindowCheckBox->setDisabled(true);
hideThisWindowCheckBox->setChecked(false);
} else {
hideThisWindowCheckBox->setDisabled(false);
}
}L’option « Hide This Window » est activée ou désactivée en fonction du délai de la capture d’écran. S’il n’y a pas de délai, la fenêtre de l’application ne peut pas être masquée et la case à cocher de l’option est désactivée.
Le slot « updateCheckBox() » est appelé chaque fois que l’utilisateur modifie le délai à l’aide de l’option « Screenshot Delay ».
void Screenshot::updateScreenshotLabel()
{
if (originalPixmap.isNull()) {
saveScreenshotButton->setEnabled(false);
screenshotLabel->setText(tr("Grabbing \"%1\" failed.").arg(screen()->name()));
} else {
saveScreenshotButton->setEnabled(true);
screenshotLabel->setPixmap(originalPixmap.scaled(screenshotLabel->size(),
Qt::KeepAspectRatio,
Qt::SmoothTransformation));
}
}La fonction privée ` updateScreenshotLabel() ` est appelée chaque fois que la capture d’écran change, ou lorsqu’un événement de redimensionnement modifie la taille de l’étiquette d’aperçu de la capture d’écran.
Nous traitons d’abord le cas d’échec. Sur certaines plateformes, notamment Wayland, il n’est pas possible de récupérer le contenu de l’écran. Dans ce cas, la carte de pixels est vide, comme l’indique la fonction QPixmap::isNull(). Nous affichons un message d’erreur sur l’étiquette et désactivons le bouton d’enregistrement.
Si une image pixmap a été obtenue, nous mettons à jour l'étiquette de l’aperçu de la capture d’écran à l’aide des fonctions ` QLabel::setPixmap()` et ` QPixmap::scaled()`.
QPixmap::scaled() renvoie une copie de l’image fournie, redimensionnée en un rectangle de la taille indiquée, conformément aux paramètres fournis par Qt::AspectRatioMode et Qt::TransformationMode.
Nous redimensionnons l’image d’origine pour l’adapter à la taille actuelle de l’étiquette de la capture d’écran, en conservant le rapport d’aspect et en lissant les bords de l’image obtenue.
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.