summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Sutterud <lars.sutterud@qt.io>2022-12-20 15:23:03 +0100
committerLars Sutterud <lars.sutterud@qt.io>2022-12-22 12:09:30 +0100
commit758bb264f012e6352ab2a83154dfd3417f1785c5 (patch)
tree86498016255f0c8f5faac5e6daf1819df9426a1e
parent8e68840e9ba921b50ae240c2e04831a125811658 (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.txt1
-rw-r--r--examples/multimedia/multimedia.pro3
-rw-r--r--examples/multimedia/screencapture/CMakeLists.txt52
-rw-r--r--examples/multimedia/screencapture/doc/images/screencapture.jpgbin0 -> 42725 bytes
-rw-r--r--examples/multimedia/screencapture/doc/src/screencapture.qdoc45
-rw-r--r--examples/multimedia/screencapture/main.cpp14
-rw-r--r--examples/multimedia/screencapture/screencapture.pro18
-rw-r--r--examples/multimedia/screencapture/screencapturepreview.cpp122
-rw-r--r--examples/multimedia/screencapture/screencapturepreview.h66
-rw-r--r--examples/multimedia/screencapture/screenlistmodel.cpp35
-rw-r--r--examples/multimedia/screencapture/screenlistmodel.h30
-rw-r--r--examples/multimedia/screencapture/windowlistmodel.cpp37
-rw-r--r--examples/multimedia/screencapture/windowlistmodel.h30
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
new file mode 100644
index 000000000..fb61fcd73
--- /dev/null
+++ b/examples/multimedia/screencapture/doc/images/screencapture.jpg
Binary files differ
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