diff options
author | Lars Sutterud <lars.sutterud@qt.io> | 2022-12-20 15:23:03 +0100 |
---|---|---|
committer | Lars Sutterud <lars.sutterud@qt.io> | 2022-12-22 12:09:30 +0100 |
commit | 758bb264f012e6352ab2a83154dfd3417f1785c5 (patch) | |
tree | 86498016255f0c8f5faac5e6daf1819df9426a1e | |
parent | 8e68840e9ba921b50ae240c2e04831a125811658 (diff) |
Add ScreenCapture example
This example demonstrates use of the QScreenCapture class by
previewing the chosen source (screen/window/window ID) in a Video Widget.
The example should be able to:
- select one of the existing screens for capturing
- select one of the existing windows
- enter any window id manually
- start/stop capturing (should be started by default)
- display occurring errors
Task-number: QTBUG-109131
Change-Id: I05a3da03576818f5b9f0c617caa77a3e3c215407
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
-rw-r--r-- | examples/multimedia/CMakeLists.txt | 1 | ||||
-rw-r--r-- | examples/multimedia/multimedia.pro | 3 | ||||
-rw-r--r-- | examples/multimedia/screencapture/CMakeLists.txt | 52 | ||||
-rw-r--r-- | examples/multimedia/screencapture/doc/images/screencapture.jpg | bin | 0 -> 42725 bytes | |||
-rw-r--r-- | examples/multimedia/screencapture/doc/src/screencapture.qdoc | 45 | ||||
-rw-r--r-- | examples/multimedia/screencapture/main.cpp | 14 | ||||
-rw-r--r-- | examples/multimedia/screencapture/screencapture.pro | 18 | ||||
-rw-r--r-- | examples/multimedia/screencapture/screencapturepreview.cpp | 122 | ||||
-rw-r--r-- | examples/multimedia/screencapture/screencapturepreview.h | 66 | ||||
-rw-r--r-- | examples/multimedia/screencapture/screenlistmodel.cpp | 35 | ||||
-rw-r--r-- | examples/multimedia/screencapture/screenlistmodel.h | 30 | ||||
-rw-r--r-- | examples/multimedia/screencapture/windowlistmodel.cpp | 37 | ||||
-rw-r--r-- | examples/multimedia/screencapture/windowlistmodel.h | 30 |
13 files changed, 452 insertions, 1 deletions
diff --git a/examples/multimedia/CMakeLists.txt b/examples/multimedia/CMakeLists.txt index 77e9ed820..fb5d62383 100644 --- a/examples/multimedia/CMakeLists.txt +++ b/examples/multimedia/CMakeLists.txt @@ -17,6 +17,7 @@ if(TARGET Qt::Widgets) qt_internal_add_example(spectrum) qt_internal_add_example(videographicsitem) qt_internal_add_example(videowidget) + qt_internal_add_example(screencapture) endif() if(TARGET Qt::Quick) qt_internal_add_example(declarative-camera) diff --git a/examples/multimedia/multimedia.pro b/examples/multimedia/multimedia.pro index cf631bb2c..7267630b5 100644 --- a/examples/multimedia/multimedia.pro +++ b/examples/multimedia/multimedia.pro @@ -15,7 +15,8 @@ qtHaveModule(widgets) { player \ spectrum \ videographicsitem \ - videowidget + videowidget \ + screencapture } qtHaveModule(quick) { diff --git a/examples/multimedia/screencapture/CMakeLists.txt b/examples/multimedia/screencapture/CMakeLists.txt new file mode 100644 index 000000000..cb979565f --- /dev/null +++ b/examples/multimedia/screencapture/CMakeLists.txt @@ -0,0 +1,52 @@ +cmake_minimum_required(VERSION 3.5) + +project(screencapture VERSION 0.1 LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOUIC ON) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets) +find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS MultimediaWidgets Widgets) + +set(PROJECT_SOURCES + screencapture.pro + main.cpp + screencapturepreview.cpp + screencapturepreview.h + screenlistmodel.h + screenlistmodel.cpp + windowlistmodel.h + windowlistmodel.cpp +) + +qt_add_executable(screencapture + MANUAL_FINALIZATION + ${PROJECT_SOURCES} + ) + +target_link_libraries(screencapture PRIVATE + Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::Gui + Qt${QT_VERSION_MAJOR}::Widgets + Qt${QT_VERSION_MAJOR}::Multimedia + Qt${QT_VERSION_MAJOR}::MultimediaWidgets) + +set_target_properties(screencapture PROPERTIES + MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com + MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} + MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} + MACOSX_BUNDLE TRUE + WIN32_EXECUTABLE TRUE +) + +install(TARGETS screencapture + BUNDLE DESTINATION . + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +qt_finalize_executable(screencapture) diff --git a/examples/multimedia/screencapture/doc/images/screencapture.jpg b/examples/multimedia/screencapture/doc/images/screencapture.jpg Binary files differnew file mode 100644 index 000000000..fb61fcd73 --- /dev/null +++ b/examples/multimedia/screencapture/doc/images/screencapture.jpg diff --git a/examples/multimedia/screencapture/doc/src/screencapture.qdoc b/examples/multimedia/screencapture/doc/src/screencapture.qdoc new file mode 100644 index 000000000..e0c73863f --- /dev/null +++ b/examples/multimedia/screencapture/doc/src/screencapture.qdoc @@ -0,0 +1,45 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only + +/*! + \example screencapture + \title Screen Capture Example + \ingroup multimedia_examples + \brief Capturing a screen or window. + \meta {tag} {widgets} + + \e{Screen Capture} demonstrates how to capture a screen or window using QScreenCapture. + The example shows a list of screens and windows and displays a live preview of the + selected item using a QMediaCaptureSession and a QVideoWidget. There is also a field + for inputting a window ID manually including a confirm button, and a button + to start and stop the capturing. + + \image screencapture.jpg + + \include examples-run.qdocinc + + \section1 Application Structure + + The example consists of three custom classes. The UI and all screen capture functionality + is implemented in the class ScreenCapturePreview. The classes ScreenlListModel and + WindowListModel only serves as models behind the two QListView widgets. The main function + creates a ScreenCapturePreview object, which in turn creates an instance of QScreenCapture, + QMediaCaptureSession and QVideoWidget in addition to all the UI widgets. + + The lists are populated with the return values of \l QGuiApplication::screens() and + \l QGuiApplication::allWindows(). The input field is prefilled with a window ID from the latter. + + When a list item is selected or a window ID is input, it is connected to the QScreenCapture object with + \l QScreenCapture::setScreen(), \l QScreenCapture::setWindow() or \l QScreenCapture::setWindowId(). + The QScreenCapture object is connected to the QMediaCaptureSession object with + \l QMediaCaptureSession::setScreenCapture(), which in turn is connected to the + QVideoWidget object with \l QMediaCaptureSession::setVideoOutput(). Thus the + screen capture output is previewed in the video widget on the right hand side of the UI. + + The Window ID input field is a QLineEdit object that handles both HEX and + decimal numbers. + + The start/stop button calls \l QScreenCapture::start() and \l QScreenCapture::stop(). + + A QMessageBox pops up if the QScreenCapture::errorOccurred signal is emitted. +*/ diff --git a/examples/multimedia/screencapture/main.cpp b/examples/multimedia/screencapture/main.cpp new file mode 100644 index 000000000..6ed104f3e --- /dev/null +++ b/examples/multimedia/screencapture/main.cpp @@ -0,0 +1,14 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include "screencapturepreview.h" + +#include <QApplication> + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + ScreenCapturePreview screenCapturePreview; + screenCapturePreview.show(); + return app.exec(); +} diff --git a/examples/multimedia/screencapture/screencapture.pro b/examples/multimedia/screencapture/screencapture.pro new file mode 100644 index 000000000..d18f556ee --- /dev/null +++ b/examples/multimedia/screencapture/screencapture.pro @@ -0,0 +1,18 @@ +TEMPLATE = app +TARGET = screencapture + +QT += multimedia multimediawidgets + +HEADERS = \ + screencapturepreview.h \ + screenlistmodel.h \ + windowlistmodel.h + +SOURCES = \ + main.cpp \ + screencapturepreview.cpp \ + screenlistmodel.cpp \ + windowlistmodel.cpp + +target.path = $$[QT_INSTALL_EXAMPLES]/multimedia/screencapture +INSTALLS += target diff --git a/examples/multimedia/screencapture/screencapturepreview.cpp b/examples/multimedia/screencapture/screencapturepreview.cpp new file mode 100644 index 000000000..36b107285 --- /dev/null +++ b/examples/multimedia/screencapture/screencapturepreview.cpp @@ -0,0 +1,122 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include "screencapturepreview.h" +#include "screenlistmodel.h" +#include "windowlistmodel.h" + +#include <QGuiApplication> +#include <QGridLayout> +#include <QListWidget> +#include <QMediaCaptureSession> +#include <QPushButton> +#include <QScreenCapture> +#include <QLineEdit> +#include <QVideoWidget> +#include <QMessageBox> +#include <QLabel> + +ScreenCapturePreview::ScreenCapturePreview(QWidget *parent) + : QWidget(parent) + , screenCapture(new QScreenCapture(this)) + , mediaCaptureSession(new QMediaCaptureSession(this)) + , videoWidget(new QVideoWidget(this)) + , screenListView(new QListView(this)) + , windowListView(new QListView(this)) + , lineEdit(new QLineEdit(this)) + , screenLabel(new QLabel("Double-click screen to capture:", this)) + , windowLabel(new QLabel("Double-click window to capture:", this)) + , windowIdLabel( + new QLabel("Enter window ID: (e.g. 0x13C009E10 or 5301640720)", this)) + , videoWidgetLabel(new QLabel("QScreenCapture output:", this)) + , wIdButton(new QPushButton("Confirm", this)) + , startStopButton(new QPushButton("Stop screencapture", this)) + , gridLayout(new QGridLayout(this)) + , hBoxLayout(new QHBoxLayout(this)) +{ + // Get lists of screens and windows: + + screens = QGuiApplication::screens(); + windows = QGuiApplication::allWindows(); + screenListModel = new ScreenListModel(screens, this); + windowListModel = new WindowListModel(windows, this); + qDebug() << "return value from QGuiApplication::screens(): " << screens; + qDebug() << "return value from QGuiApplication::allWindows(): " << windows; + + // Setup QScreenCapture with initial source: + + screenCapture->setScreen((!screens.isEmpty()) ? screens.first() : nullptr); + screenCapture->start(); + mediaCaptureSession->setScreenCapture(screenCapture); + mediaCaptureSession->setVideoOutput(videoWidget); + + // Setup UI: + + screenListView->setModel(screenListModel); + windowListView->setModel(windowListModel); + // Sets initial lineEdit text to the WId of the second QWindow from QGuiApplication::allWindows() + if (windows.count() > 1) + lineEdit->setText(QString::number(windows[1]->winId())); + + gridLayout->addWidget(screenLabel, 0, 0); + gridLayout->addWidget(screenListView, 1, 0); + gridLayout->addWidget(windowLabel, 2, 0); + gridLayout->addWidget(windowListView, 3, 0); + gridLayout->addWidget(windowIdLabel, 4, 0); + hBoxLayout->addWidget(lineEdit); + hBoxLayout->addWidget(wIdButton); + gridLayout->addLayout(hBoxLayout, 5, 0); + gridLayout->addWidget(startStopButton, 6, 0); + gridLayout->addWidget(videoWidgetLabel, 0, 1); + gridLayout->addWidget(videoWidget, 1, 1, 6, 1); + + gridLayout->setColumnStretch(1, 1); + gridLayout->setRowStretch(1, 1); + gridLayout->setColumnMinimumWidth(0, 400); + gridLayout->setColumnMinimumWidth(1, 400); + gridLayout->setRowMinimumHeight(3, 1); + + connect(screenListView, &QAbstractItemView::activated, this, &ScreenCapturePreview::onScreenSelectionChanged); + connect(windowListView, &QAbstractItemView::activated, this, &ScreenCapturePreview::onWindowSelectionChanged); + connect(wIdButton, &QPushButton::clicked, this, &ScreenCapturePreview::onWindowIdSelectionChanged); + connect(startStopButton, &QPushButton::clicked, this, &ScreenCapturePreview::onStartStopButtonClicked); + connect(lineEdit, &QLineEdit::returnPressed, this, &ScreenCapturePreview::onWindowIdSelectionChanged); + connect(screenCapture, &QScreenCapture::errorOccurred, this, &ScreenCapturePreview::onScreenCaptureErrorOccured); + +} + +ScreenCapturePreview::~ScreenCapturePreview() +{ +} + +void ScreenCapturePreview::onScreenSelectionChanged(QModelIndex index) +{ + screenCapture->setScreen(screenListModel->screen(index)); +} + +void ScreenCapturePreview::onWindowSelectionChanged(QModelIndex index) +{ + screenCapture->setWindow(windowListModel->window(index)); +} + +void ScreenCapturePreview::onWindowIdSelectionChanged() +{ + unsigned long long input = lineEdit->text().toULongLong(nullptr, 0); + screenCapture->setWindowId(input); +} + +void ScreenCapturePreview::onScreenCaptureErrorOccured(QScreenCapture::Error error, const QString &errorString) +{ + QMessageBox::warning(this, "QScreenCapture: Error occurred", errorString); +} + +void ScreenCapturePreview::onStartStopButtonClicked() +{ + if (screenCapture->isActive()) { + screenCapture->stop(); + startStopButton->setText("Start screencapture"); + } else { + screenCapture->start(); + startStopButton->setText("Stop screencapture"); + } +} diff --git a/examples/multimedia/screencapture/screencapturepreview.h b/examples/multimedia/screencapture/screencapturepreview.h new file mode 100644 index 000000000..e3ae60711 --- /dev/null +++ b/examples/multimedia/screencapture/screencapturepreview.h @@ -0,0 +1,66 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#ifndef SCREENCAPTUREPREVIEW_H +#define SCREENCAPTUREPREVIEW_H + +#include <QScreenCapture> +#include <QWidget> +#include <QModelIndex> + +class ScreenListModel; +class WindowListModel; + +QT_BEGIN_NAMESPACE +class QListView; +class QMediaCaptureSession; +class QVideoWidget; +class QGridLayout; +class QHBoxLayout; +class QLineEdit; +class QPushButton; +class QLabel; +QT_END_NAMESPACE + +QT_USE_NAMESPACE + +class ScreenCapturePreview : public QWidget +{ + Q_OBJECT + +public: + + ScreenCapturePreview(QWidget *parent = nullptr); + ~ScreenCapturePreview(); + +public slots: + + void onScreenSelectionChanged(QModelIndex index); + void onWindowSelectionChanged(QModelIndex index); + void onWindowIdSelectionChanged(); + void onScreenCaptureErrorOccured(QScreenCapture::Error error, const QString &errorString); + void onStartStopButtonClicked(); + +private: + + ScreenListModel *screenListModel = nullptr; + WindowListModel *windowListModel = nullptr; + QListView *screenListView = nullptr; + QListView *windowListView = nullptr; + QScreenCapture *screenCapture = nullptr; + QList<QScreen *> screens = QList<QScreen *>(); + QList<QWindow *> windows = QList<QWindow *>(); + QMediaCaptureSession *mediaCaptureSession = nullptr; + QVideoWidget *videoWidget = nullptr; + QGridLayout *gridLayout = nullptr; + QHBoxLayout *hBoxLayout = nullptr; + QLineEdit *lineEdit = nullptr; + QPushButton *wIdButton = nullptr; + QPushButton *startStopButton = nullptr; + QLabel *screenLabel = nullptr; + QLabel *windowLabel = nullptr; + QLabel *windowIdLabel = nullptr; + QLabel *videoWidgetLabel = nullptr; + +}; +#endif // SCREENCAPTUREPREVIEW_H diff --git a/examples/multimedia/screencapture/screenlistmodel.cpp b/examples/multimedia/screencapture/screenlistmodel.cpp new file mode 100644 index 000000000..3dc455aed --- /dev/null +++ b/examples/multimedia/screencapture/screenlistmodel.cpp @@ -0,0 +1,35 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include "screenlistmodel.h" + +#include <QScreen> + +ScreenListModel::ScreenListModel(QList<QScreen *> data, QObject *parent) + : QAbstractListModel(parent), screenList(data) +{ +} + +int ScreenListModel::rowCount(const QModelIndex &parent) const +{ + return screenList.count(); +} + +QVariant ScreenListModel::data(const QModelIndex &index, int role) const +{ + Q_ASSERT(index.isValid()); + Q_ASSERT(index.row() <= screenList.count()); + + if (role == Qt::DisplayRole) { + auto screen = screenList.at(index.row()); + return QString("%1: %2").arg(screen->metaObject()->className(), + screen->name()); + } else { + return QVariant(); + } +} + +QScreen *ScreenListModel::screen(const QModelIndex &index) const +{ + return screenList.at(index.row()); +} diff --git a/examples/multimedia/screencapture/screenlistmodel.h b/examples/multimedia/screencapture/screenlistmodel.h new file mode 100644 index 000000000..4069a1f3f --- /dev/null +++ b/examples/multimedia/screencapture/screenlistmodel.h @@ -0,0 +1,30 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#ifndef SCREENLISTMODEL_H +#define SCREENLISTMODEL_H + +#include <QAbstractListModel> + +QT_BEGIN_NAMESPACE +class QScreen; +QT_END_NAMESPACE + +QT_USE_NAMESPACE + +class ScreenListModel : public QAbstractListModel +{ + Q_OBJECT + +public: + explicit ScreenListModel(QList<QScreen *> data = QList<QScreen *>(), QObject *parent = nullptr); + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QScreen *screen(const QModelIndex &index) const; + +private: + QList<QScreen *> screenList; +}; + +#endif // SCREENLISTMODEL_H diff --git a/examples/multimedia/screencapture/windowlistmodel.cpp b/examples/multimedia/screencapture/windowlistmodel.cpp new file mode 100644 index 000000000..6d8728e7c --- /dev/null +++ b/examples/multimedia/screencapture/windowlistmodel.cpp @@ -0,0 +1,37 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include "windowlistmodel.h" + +#include <QWindow> + +WindowListModel::WindowListModel(QList<QWindow *> data, QObject *parent) + : QAbstractListModel(parent), windowList(data) +{ +} + +int WindowListModel::rowCount(const QModelIndex &parent) const +{ + return windowList.count(); +} + +QVariant WindowListModel::data(const QModelIndex &index, int role) const +{ + Q_ASSERT(index.isValid()); + Q_ASSERT(index.row() <= windowList.count()); + + if (role == Qt::DisplayRole) { + auto window = windowList.at(index.row()); + return QString("%1: %2, %3") + .arg(window->metaObject()->className()) + .arg(window->winId()) + .arg(window->objectName()); + } else { + return QVariant(); + } +} + +QWindow *WindowListModel::window(const QModelIndex &index) const +{ + return windowList.at(index.row()); +} diff --git a/examples/multimedia/screencapture/windowlistmodel.h b/examples/multimedia/screencapture/windowlistmodel.h new file mode 100644 index 000000000..885f29afd --- /dev/null +++ b/examples/multimedia/screencapture/windowlistmodel.h @@ -0,0 +1,30 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#ifndef WINDOWLISTMODEL_H +#define WINDOWLISTMODEL_H + +#include <QAbstractListModel> + +QT_BEGIN_NAMESPACE +class QWindow; +QT_END_NAMESPACE + +QT_USE_NAMESPACE + +class WindowListModel : public QAbstractListModel +{ + Q_OBJECT + +public: + explicit WindowListModel(QList<QWindow *> data = QList<QWindow *>(), QObject *parent = nullptr); + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QWindow *window(const QModelIndex &index) const; + +private: + QList<QWindow *> windowList; +}; + +#endif // WINDOWLISTMODEL_H |