스크린샷 찍기
'스크린샷' 예제에서는 바탕화면의 스크린샷을 찍는 방법을 보여줍니다.

이 애플리케이션을 사용하면 사용자는 자신의 바탕화면 스크린샷을 찍을 수 있습니다. 사용자에게는 다음과 같은 몇 가지 옵션이 제공됩니다:
- 스크린샷 촬영을 잠시 지연시켜 사용자가 바탕화면을 정리할 시간을 주는 기능.
- 스크린샷을 찍는 동안 애플리케이션 창을 숨깁니다.
또한 이 애플리케이션을 통해 사용자는 원할 경우 스크린샷을 저장할 수 있습니다.
스크린샷 클래스 정의
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;
};Screenshot 클래스는 QWidget 를 상속받으며, 이 애플리케이션의 메인 위젯입니다. 이 클래스는 애플리케이션 옵션과 스크린샷 미리보기를 표시합니다.
사용자가 애플리케이션 위젯의 크기를 조정할 때 스크린샷 미리보기가 적절하게 크기가 조정되도록 하기 위해 ` QWidget::resizeEvent()` 함수를 재구현합니다. 또한 옵션을 처리하기 위해 몇 가지 비공개 슬롯이 필요합니다:
newScreenshot()슬롯은 새로운 스크린샷을 준비합니다.saveScreenshot()슬롯은 마지막 스크린샷을 저장합니다.shootScreen()슬롯은 스크린샷을 촬영합니다.updateCheckBox()슬롯은 ‘ Hide This Window ’ 옵션을 활성화하거나 비활성화합니다.
또한, 새로운 스크린샷이 촬영될 때마다 또는 크기 조정 이벤트로 인해 스크린샷 미리보기 레이블의 크기가 변경될 때마다 호출되는 비공개 함수 updateScreenshotLabel() 을 선언합니다.
또한 스크린샷의 원본 픽스맵을 저장해야 합니다. 스크린샷 미리보기를 표시할 때 픽스맵의 크기를 조정해야 하기 때문이며, 원본을 저장해 두면 이 과정에서 데이터가 손실되지 않도록 보장할 수 있습니다.
스크린샷 클래스 구현
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);
}생성자에서 먼저 스크린샷 미리보기를 표시하는 ` QLabel `를 생성합니다.
QLabel 의 크기 정책을 가로와 세로 모두 ‘ QSizePolicy::Expanding ’로 설정합니다. 이는 QLabel 의 크기 힌트가 적정한 크기이면서도, 위젯을 축소하더라도 여전히 유용하게 사용할 수 있음을 의미합니다. 또한, 위젯은 여유 공간을 활용할 수 있으므로 가능한 한 많은 공간을 할당받아야 합니다. 그런 다음 QLabel 가 Screenshot 위젯의 중앙에 정렬되도록 하고, 최소 크기를 설정합니다.
다음으로, 모든 옵션 위젯을 포함할 그룹 박스를 생성합니다. 그런 다음 ‘ Screenshot Delay ’ 옵션을 위한 ‘ QSpinBox ’와 ‘ QLabel ’를 생성하고, 스핀박스를 ‘ updateCheckBox() ’ 슬롯에 연결합니다. 마지막으로 ‘ Hide This Window ’ 옵션을 위한 ‘ QCheckBox ’를 생성하고, 그룹 박스에 설치된 ‘ QGridLayout ’에 모든 옵션 위젯을 추가합니다.
애플리케이션의 버튼과 애플리케이션 옵션을 포함하는 그룹 박스를 생성하고, 이 모든 요소를 메인 레이아웃에 배치합니다. 마지막으로 초기 스크린샷을 캡처하고, 초기 지연 시간과 창 제목을 설정한 후, 화면 구조에 따라 위젯의 크기를 적절한 크기로 조정합니다.
void Screenshot::resizeEvent(QResizeEvent * /* event */)
{
if (!originalPixmap.isNull()) {
QSize scaledSize = originalPixmap.size();
scaledSize.scale(screenshotLabel->size(), Qt::KeepAspectRatio);
if (scaledSize != screenshotLabel->pixmap().size())
updateScreenshotLabel();
}
}resizeEvent() 함수는 위젯으로 전송되는 크기 조정 이벤트를 수신하도록 재구현됩니다. 이는 미리보기 스크린샷 픽스맵의 내용이 왜곡되지 않도록 크기를 조정하고, 애플리케이션의 크기가 원활하게 조정될 수 있도록 보장하기 위함입니다.
첫 번째 목표를 달성하기 위해 ` Qt::KeepAspectRatio`를 사용하여 스크린샷 픽스맵을 크기를 조정합니다. 종횡비를 유지하면서 스크린샷 미리보기 레이블의 현재 크기 내에서 가능한 한 큰 직사각형으로 픽스맵을 조정합니다. 즉, 사용자가 애플리케이션 창을 한 방향으로만 크기를 조정하더라도 미리보기 스크린샷은 동일한 크기를 유지합니다.
두 번째 목표를 달성하기 위해, 미리보기 스크린샷의 크기가 실제로 변경될 때만( updateScreenshotLabel() 비공개 함수를 사용하여) 다시 그려지도록 합니다.
void Screenshot::newScreenshot()
{
if (hideThisWindowCheckBox->isChecked())
hide();
newScreenshotButton->setDisabled(true);
QTimer::singleShot(delaySpinBox->value() * 1000, this, &Screenshot::shootScreen);
}사용자가 새로운 스크린샷을 요청하면 비공개 ` newScreenshot() ` 슬롯이 호출되지만, 이 슬롯은 새로운 스크린샷을 준비할 뿐입니다.
먼저 ‘ Hide This Window ’ 옵션이 선택되어 있는지 확인하고, 선택되어 있다면 ‘ Screenshot ’ 위젯을 숨깁니다. 그런 다음 사용자가 한 번에 하나의 스크린샷만 요청할 수 있도록 ‘ New Screenshot ’ 버튼을 비활성화합니다.
반복 및 단일 실행 타이머 기능을 제공하는 ` QTimer ` 클래스를 사용하여 타이머를 생성합니다. ` QTimer::singleShot()` 정적 함수를 사용하여 타이머가 한 번만 타임아웃되도록 설정합니다. 이 함수는 ` Screenshot Delay ` 옵션으로 지정된 시간 간격이 지난 후 비공개 ` shootScreen() ` 슬롯을 호출합니다. 실제로 스크린샷을 수행하는 것은 ` shootScreen() `입니다.
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)));
}
}saveScreenshot() 슬롯은 사용자가 Save 버튼을 누를 때 호출되며, QFileDialog 클래스를 사용하여 파일 선택 대화 상자를 표시합니다.
QFileDialog 사용자는 이 대화 상자를 통해 파일 시스템을 탐색하여 하나 또는 여러 개의 파일이나 디렉터리를 선택할 수 있습니다. QFileDialog 를 생성하는 가장 쉬운 방법은 편리한 정적 함수를 사용하는 것입니다. 여기서는 QImageWriter 에서 지원하는 MIME 유형을 설정하여 사용자가 다양한 형식으로 저장할 수 있도록 하기 위해 스택에 대화 상자를 인스턴스화합니다.
기본 파일 형식을 png로 정의하고, 파일 대화 상자의 초기 경로를 QStandardPaths 에서 가져온 그림 파일의 위치로 설정하며, 이 경로는 기본적으로 애플리케이션이 실행된 경로로 지정됩니다.
QDialog::exec()를 호출하여 대화 상자를 실행하고, 사용자가 대화 상자를 취소한 경우 반환합니다. 대화 상자가 수락된 경우, QFileDialog::selectedFiles()를 호출하여 파일 이름을 가져옵니다. 파일이 반드시 존재할 필요는 없습니다. 파일 이름이 유효하면, QPixmap::save() 함수를 사용하여 스크린샷의 원본 픽스맵을 해당 파일에 저장합니다.
void Screenshot::shootScreen()
{
if (delaySpinBox->value() != 0)
QApplication::beep();
originalPixmap = screen()->grabWindow(0);
updateScreenshotLabel();
newScreenshotButton->setDisabled(false);
if (hideThisWindowCheckBox->isChecked())
show();
}shootScreen() 슬롯을 호출하여 스크린샷을 찍습니다.
사용자가 스크린샷 촬영을 지연하도록 설정한 경우, 정적 함수 QApplication::beep()을 사용하여 스크린샷이 촬영될 때 애플리케이션에서 신호음을 울리게 합니다.
그런 다음 QWidget::screen()이 반환한 화면에 대해 QScreen::grabWindow() 함수를 사용하여 스크린샷을 캡처합니다. 이 함수는 인수로 전달된 창의 내용을 캡처하여 픽스맵으로 생성한 후, 해당 픽스맵을 반환합니다. 창 ID는 ` QWidget::winId()` 또는 ` QWindow::winId()`를 통해 얻을 수 있습니다. 하지만 여기서는 창 ID로 0을 전달하여 전체 화면을 캡처할 것임을 나타냅니다.
비공개 함수인 ` updateScreenshotLabel() `을 사용하여 스크린샷 미리보기 레이블을 업데이트합니다. 그런 다음 ` New Screenshot ` 버튼을 활성화하고, 마지막으로 스크린샷 촬영 중에 숨겨져 있었다면 ` Screenshot ` 위젯을 다시 표시합니다.
void Screenshot::updateCheckBox()
{
if (delaySpinBox->value() == 0) {
hideThisWindowCheckBox->setDisabled(true);
hideThisWindowCheckBox->setChecked(false);
} else {
hideThisWindowCheckBox->setDisabled(false);
}
}Hide This Window 옵션은 스크린샷의 지연 시간에 따라 활성화되거나 비활성화됩니다. 지연 시간이 없으면 애플리케이션 창을 숨길 수 없으므로 해당 옵션의 체크박스가 비활성화됩니다.
사용자가 ‘ Screenshot Delay ’ 옵션을 통해 지연 시간을 변경할 때마다 ‘ updateCheckBox() ’ 슬롯이 호출됩니다.
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));
}
}스크린샷이 변경될 때마다, 또는 크기 조정 이벤트로 인해 스크린샷 미리보기 레이블의 크기가 변경될 때마다 비공개 함수 ` updateScreenshotLabel() `가 호출됩니다.
먼저, 실패 사례를 처리합니다. Wayland와 같은 일부 플랫폼에서는 화면 내용을 가져올 수 없습니다. 이 경우, QPixmap::isNull() 함수가 나타내듯이 픽스맵은 비어 있습니다. 레이블에 오류 문자열을 설정하고 저장 버튼을 비활성화합니다.
픽스맵을 가져온 경우, QLabel::setPixmap() 및 QPixmap::scaled() 함수를 사용하여 스크린샷 미리보기 레이블을 업데이트합니다.
QPixmap::scaled()는 주어진 Qt::AspectRatioMode 및 Qt::TransformationMode 에 따라 주어진 크기의 직사각형으로 크기 조정된 주어진 픽스맵의 복사본을 반환합니다.
원본 픽스맵을 현재 스크린샷 레이블의 크기에 맞게 크기를 조정하되, 종횡비는 유지하고 결과 픽스맵의 가장자리를 부드럽게 처리합니다.
© 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.