Hacer una captura de pantalla
El ejemplo Captura de pantalla muestra cómo hacer una captura de pantalla del escritorio.

Con la aplicación los usuarios pueden hacer una captura de pantalla de su escritorio. Se les ofrecen un par de opciones:
- Retrasar la captura de pantalla, dándoles tiempo para reorganizar su escritorio.
- Ocultar la ventana de la aplicación mientras se realiza la captura de pantalla.
Además, la aplicación permite a los usuarios guardar la captura de pantalla si lo desean.
Definición de la Clase Captura de Pantalla
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 clase Screenshot hereda de QWidget y es el widget principal de la aplicación. Muestra las opciones de la aplicación y una vista previa de la captura de pantalla.
Reimplementamos la función QWidget::resizeEvent() para asegurarnos de que la vista previa de la captura de pantalla se escala correctamente cuando el usuario cambia el tamaño del widget de la aplicación. También necesitamos varias ranuras privadas para facilitar las opciones:
- La ranura
newScreenshot()prepara una nueva captura de pantalla. - La ranura
saveScreenshot()guarda la última captura de pantalla. - La ranura
shootScreen()toma la captura de pantalla. - La ranura
updateCheckBox()activa o desactiva la opción Hide This Window.
También declaramos la función privada updateScreenshotLabel() que es llamada cada vez que se toma una nueva captura de pantalla o cuando un evento de redimensionamiento cambia el tamaño de la etiqueta de previsualización de la captura de pantalla.
Además necesitamos almacenar el pixmap original de la captura de pantalla. La razón es que cuando mostramos la vista previa de la captura de pantalla, necesitamos escalar su pixmap, almacenando el original nos aseguramos de que no se pierden datos en ese proceso.
Implementación de la Clase Captura de Pantalla
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); }
En el constructor primero creamos el QLabel mostrando la vista previa de la captura de pantalla.
Establecemos la política de tamaño de QLabel para que sea QSizePolicy::Expanding tanto horizontal como verticalmente. Esto significa que el QLabel's size hint es un tamaño razonable, pero el widget puede ser encogido y seguir siendo útil. Además, el widget puede hacer uso de espacio extra, por lo que debe tener tanto espacio como sea posible. A continuación, nos aseguramos de que QLabel está alineado en el centro del widget Screenshot y establecemos su tamaño mínimo.
A continuación, creamos un cuadro de grupo que contendrá todos los widgets de las opciones. A continuación, creamos un QSpinBox y un QLabel para la opción Screenshot Delay, y conectamos el spinbox a la ranura updateCheckBox(). Por último, creamos un QCheckBox para la opción Hide This Window, añadimos todos los widgets de las opciones a un QGridLayout instalado en la caja de grupo.
Creamos los botones de la aplicación y la caja de grupo que contiene las opciones de la aplicación, y lo ponemos todo en un layout principal. Por último, tomamos la captura de pantalla inicial y establecemos el retardo inicial y el título de la ventana, antes de redimensionar el widget a un tamaño adecuado en función de la geometría de la pantalla.
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 función resizeEvent() se reimplementa para recibir los eventos de redimensionamiento enviados al widget. El propósito es escalar el pixmap de la captura de pantalla de previsualización sin deformar su contenido, y también asegurarnos de que la aplicación puede redimensionarse suavemente.
Para conseguir el primer objetivo, escalamos el pixmap de la captura de pantalla usando Qt::KeepAspectRatio. Escalamos el pixmap a un rectángulo lo más grande posible dentro del tamaño actual de la etiqueta de vista previa de la captura de pantalla, preservando la relación de aspecto. Esto significa que si el usuario cambia el tamaño de la ventana de la aplicación en una sola dirección, la captura de pantalla de previsualización mantiene el mismo tamaño.
Para alcanzar nuestro segundo objetivo, nos aseguramos de que la captura de pantalla de previsualización sólo se vuelve a pintar (utilizando la función privada updateScreenshotLabel() ) cuando realmente cambia su tamaño.
void Screenshot::newScreenshot() { if (hideThisWindowCheckBox->isChecked()) hide(); newScreenshotButton->setDisabled(true); QTimer::singleShot(delaySpinBox->value() * 1000, this, &Screenshot::shootScreen); }
La ranura privada newScreenshot() es llamada cuando el usuario solicita una nueva captura de pantalla; pero la ranura sólo prepara una nueva captura de pantalla.
Primero vemos si la opción Hide This Window está marcada, si lo está ocultamos el widget Screenshot. Después desactivamos el botón New Screenshot, para asegurarnos de que el usuario sólo puede solicitar una captura de pantalla cada vez.
Creamos un temporizador utilizando la clase QTimer que proporciona temporizadores repetitivos y de una sola captura. Configuramos el temporizador para que se agote sólo una vez, usando la función estática QTimer::singleShot(). Esta función llama a la ranura privada shootScreen() después del intervalo de tiempo especificado por la opción Screenshot Delay. Es shootScreen() el que realmente realiza la captura de pantalla.
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))); } }
La ranura saveScreenshot() es llamada cuando el usuario pulsa el botón Save, y presenta un diálogo de archivo utilizando la clase QFileDialog.
QFileDialog permite al usuario recorrer el sistema de archivos para seleccionar uno o varios archivos o un directorio. La forma más sencilla de crear un QFileDialog es utilizar las funciones estáticas de conveniencia. Aquí, instanciamos el diálogo en la pila para poder configurar los tipos mime soportados de QImageWriter, permitiendo al usuario guardar en una variedad de formatos.
Definimos que el formato de archivo por defecto sea png, y hacemos que la ruta inicial del diálogo de archivos sea la ubicación de las imágenes obtenida de QStandardPaths, por defecto la ruta desde la que se ejecuta la aplicación.
Ejecutamos el diálogo invocando QDialog::exec() y devolvemos si el usuario canceló el diálogo. Si el diálogo ha sido aceptado, obtenemos un nombre de archivo llamando a QFileDialog::selectedFiles(). No es necesario que el archivo exista. Si el nombre del archivo es válido, usamos la función QPixmap::save() para guardar el pixmap original de la captura de pantalla en ese archivo.
void Screenshot::shootScreen() { if (delaySpinBox->value() != 0) QApplication::beep(); originalPixmap = screen()->grabWindow(0); updateScreenshotLabel(); newScreenshotButton->setDisabled(false); if (hideThisWindowCheckBox->isChecked()) show(); }
Se llama a la ranura shootScreen() para tomar la captura de pantalla.
Si el usuario ha elegido retrasar la captura de pantalla, hacemos que la aplicación emita un pitido cuando se toma la captura de pantalla utilizando la función estática QApplication::beep().
A continuación, tomamos la captura de pantalla utilizando la función QScreen::grabWindow() en la pantalla devuelta por QWidget::screen(). La función toma el contenido de la ventana pasada como argumento, hace un pixmap de él y devuelve ese pixmap. El id de la ventana se puede obtener con QWidget::winId() o QWindow::winId(). Aquí, sin embargo, sólo pasamos 0 como id de ventana, indicando que queremos capturar toda la pantalla.
Actualizamos la etiqueta de vista previa de la captura de pantalla utilizando la función privada updateScreenshotLabel(). Después habilitamos el botón New Screenshot, y finalmente hacemos visible el widget Screenshot si estaba oculto durante la captura de pantalla.
void Screenshot::updateCheckBox() { if (delaySpinBox->value() == 0) { hideThisWindowCheckBox->setDisabled(true); hideThisWindowCheckBox->setChecked(false); } else { hideThisWindowCheckBox->setDisabled(false); } }
La opción Hide This Window se activa o desactiva dependiendo del retardo de la captura de pantalla. Si no hay retardo, la ventana de la aplicación no se puede ocultar y la casilla de la opción está desactivada.
La función updateCheckBox() es llamada cada vez que el usuario cambia el retardo utilizando la opción 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 función privada updateScreenshotLabel() es llamada cada vez que la captura de pantalla cambia, o cuando un evento de redimensionamiento cambia el tamaño de la etiqueta de previsualización de la captura de pantalla.
En primer lugar, manejamos el caso de fallo. En algunas plataformas, concretamente Wayland, no es posible recuperar el contenido de la pantalla. En este caso, el pixmap está vacío como indica QPixmap::isNull(). Establecemos una cadena de error en la etiqueta y desactivamos el botón para guardar.
Si se obtuvo un pixmap, actualizamos la etiqueta de la vista previa de la pantalla utilizando las funciones QLabel::setPixmap() y QPixmap::scaled().
QPixmap::scaled() devuelve una copia del pixmap dado escalado a un rectángulo del tamaño dado de acuerdo con las funciones Qt::AspectRatioMode y Qt::TransformationMode.
Escalamos el pixmap original para ajustarlo al tamaño de la etiqueta de la captura de pantalla actual, preservando la relación de aspecto y dando al pixmap resultante bordes suavizados.
© 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.