스크린샷 찍기
스크린샷 예시는 데스크톱의 스크린샷을 찍는 방법을 보여줍니다.
이 애플리케이션을 통해 사용자는 데스크톱의 스크린샷을 찍을 수 있습니다. 몇 가지 옵션이 제공됩니다:
- 스크린샷을 지연시켜 데스크톱을 재정비할 시간을 줍니다.
- 스크린샷을 찍는 동안 애플리케이션 창 숨기기.
또한 사용자가 원하는 경우 애플리케이션에서 스크린샷을 저장할 수 있습니다.
스크린샷 클래스 정의
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; };
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); 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); 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); 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 */) { 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 의 지원되는 밈 유형을 설정할 수 있도록 하여 사용자가 다양한 형식으로 저장할 수 있도록 합니다.
기본 파일 형식을 png로 정의하고 파일 대화 상자의 초기 경로를 QStandardPaths 에서 가져온 사진의 위치로 설정하여 애플리케이션이 실행되는 경로를 기본값으로 설정합니다.
QDialog::exec()를 호출하여 대화 상자를 실행하고 사용자가 대화 상자를 취소한 경우 반환합니다. 대화 상자가 수락된 경우 QFileDialog::selectedFiles()를 호출하여 파일 이름을 가져옵니다. 파일이 존재할 필요는 없습니다. 파일 이름이 유효하면 QPixmap::save() 함수를 사용하여 스크린샷의 원본 픽스맵을 해당 파일에 저장합니다.
void Screenshot::shootScreen() { QScreen *screen = QGuiApplication::primaryScreen(); 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(); }
shootScreen()
슬롯은 스크린샷을 찍기 위해 호출됩니다.
먼저 QWindow 및 기본 화면으로 설정된 QScreen 을 검색하여 창이 위치한 QScreen 의 인스턴스를 찾습니다. 화면을 찾을 수 없으면 되돌아갑니다. 이런 일이 발생할 가능성은 낮지만, 화면이 연결되지 않는 상황이 발생할 수 있으므로 애플리케이션은 널 포인터를 확인해야 합니다.
사용자가 스크린샷을 지연시키도록 선택한 경우 정적 QApplication::beep() 함수를 사용하여 스크린샷을 찍을 때 애플리케이션에서 경고음을 울립니다.
그런 다음 QScreen::grabWindow() 함수를 사용하여 스크린샷을 찍습니다. 이 함수는 인자로 전달된 창의 내용을 가져와서 픽셀맵을 만든 다음 해당 픽셀맵을 반환합니다. 창 ID는 QWidget::winId() 또는 QWindow::winId()로 얻을 수 있습니다. 하지만 여기서는 전체 화면을 가져오고 싶다는 의미로 0을 창 ID로 전달했습니다.
비공개 updateScreenshotLabel()
함수를 사용하여 스크린샷 미리보기 라벨을 업데이트합니다. 그런 다음 New Screenshot 버튼을 활성화하고 마지막으로 스크린샷을 찍는 동안 숨겨져 있던 Screenshot
위젯을 표시합니다.
void Screenshot::updateCheckBox() { if (delaySpinBox->value() == 0) { hideThisWindowCheckBox->setDisabled(true); hideThisWindowCheckBox->setChecked(false); } else { hideThisWindowCheckBox->setDisabled(false); } }
Hide This Window 옵션은 스크린샷의 지연 시간에 따라 활성화 또는 비활성화됩니다. 지연이 없으면 애플리케이션 창을 숨길 수 없으며 옵션의 확인란이 비활성화됩니다.
updateCheckBox()
슬롯은 사용자가 Screenshot Delay 옵션을 사용하여 지연을 변경할 때마다 호출됩니다.
void Screenshot::updateScreenshotLabel() { screenshotLabel->setPixmap(originalPixmap.scaled(screenshotLabel->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation)); }
비공개 updateScreenshotLabel()
함수는 스크린샷이 변경될 때마다 또는 크기 조정 이벤트로 인해 스크린샷 미리보기 레이블의 크기가 변경될 때마다 호출됩니다. QLabel::setPixmap () 및 QPixmap::scaled() 함수를 사용하여 스크린샷 미리보기의 레이블을 업데이트합니다.
QPixmap::scaled()는 주어진 Qt::AspectRatioMode 및 Qt::TransformationMode 에 따라 주어진 크기의 직사각형으로 크기가 조정된 주어진 픽셀맵의 사본을 반환합니다.
현재 스크린샷 라벨의 크기에 맞게 원본 픽셀맵의 크기를 조정하여 가로 세로 비율을 유지하고 결과 픽셀맵의 가장자리를 부드럽게 만듭니다.
© 2025 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.