aboutsummaryrefslogtreecommitdiffstats
path: root/examples/multimedia/screencapture
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2023-08-02 08:52:31 +0200
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2023-08-04 09:52:45 +0200
commit39e65f1719b98d58408a5b7c0dddfb6664a41afb (patch)
treece5cac95ea78b5e425fff122485556f39705ed08 /examples/multimedia/screencapture
parent40ec55c2606892848f8b4855d8e761cdf2e49656 (diff)
Multimedia screen capture example: Add window capture
Port from qtmultimedia/3edff8e367b9060dd138a2b67cb87d2246a4a3e6. Task-number: PYSIDE-2206 Change-Id: Ia702faf47946a0f656b1546b205dfb442cf2f56a Reviewed-by: Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io> Reviewed-by: Shyamnath Premnadh <Shyamnath.Premnadh@qt.io> Reviewed-by: Adrian Herrmann <adrian.herrmann@qt.io>
Diffstat (limited to 'examples/multimedia/screencapture')
-rw-r--r--examples/multimedia/screencapture/doc/screencapture.rst57
-rw-r--r--examples/multimedia/screencapture/doc/screencapture.webpbin20604 -> 53592 bytes
-rw-r--r--examples/multimedia/screencapture/main.py3
-rw-r--r--examples/multimedia/screencapture/screencapture.pyproject2
-rw-r--r--examples/multimedia/screencapture/screencapturepreview.py132
-rw-r--r--examples/multimedia/screencapture/windowlistmodel.py30
6 files changed, 171 insertions, 53 deletions
diff --git a/examples/multimedia/screencapture/doc/screencapture.rst b/examples/multimedia/screencapture/doc/screencapture.rst
index 69b1ec166..116d7773b 100644
--- a/examples/multimedia/screencapture/doc/screencapture.rst
+++ b/examples/multimedia/screencapture/doc/screencapture.rst
@@ -1,35 +1,42 @@
Screen Capture Example
======================
-The Screen Capture Example demonstrates how to capture a screen or window using
-QScreenCapture. It shows a list of screens and and displays a live preview of
-the selected item using a ``QMediaCaptureSession`` and a ``QVideoWidget``.
-There is a button to start and stop the capturing.
+Screen Capture demonstrates how to capture a screen or window using
+``QScreenCapture`` and ``QWindowCapture``. The example shows a list of screens
+and windows and displays a live preview of the selected item using a
+``QMediaCaptureSession`` and a ``QVideoWidget``. Capturing can be started and
+stopped with a ``QPushButton``.
Application Structure
+++++++++++++++++++++
-The example consists of two custom classes. The UI and all screen capture
+The example consists of three custom classes. The UI and all screen capture
functionality is implemented in the class ``ScreenCapturePreview``. The classes
-``ScreenListModel`` serves as model behind the ``QListView``. 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 list model is populated with the return values of ``QGuiApplication.screens()``.
-
-When a list item is selected it is connected to the ``QScreenCapture`` object
-with ``QScreenCapture.setScreen()``. The ``QScreenCapture`` object is connected
-to the ``QMediaCaptureSession`` object with
-``QMediaCaptureSession.setScreenCapture()``, which in turn is connected to the
-``QVideoWidget`` object with ``QMediaCaptureSession.setVideoOutput()`` Thus the
-screen capture output is previewed in the video widget on the right hand side
-of the UI.
-
-The start/stop button calls ``QScreenCapture.start()`` and ``QScreenCapture.stop()``.
-
-A ``QMessageBox`` pops up if the ``QScreenCapture.errorOccurred()`` signal is emitted.
-
-.. image:: screencapture.webp
+``ScreenListModel`` and ``WindowListModel`` only serve as models behind the two
+``QListView`` widgets. The main function creates a ``ScreenCapturePreview``
+object, which in turn creates instances of ``QScreenCapture`` and
+``QWindowCapture``, and a ``QMediaCaptureSession`` and ``QVideoWidget``, in
+addition to all the UI widgets.
+
+The screen and window models are populated with the return values of
+``QGuiApplication.screens()`` and ``QWindowCapture.capturableWindows()``,
+respectively.
+
+When a list item is selected, it is connected to the ``QScreenCapture`` object
+with ``QScreenCapture.setScreen()``, or to the ``QWindowCapture`` object with
+``QWindowCapture.setWindow().`` The capture object is connected to the
+``QMediaCaptureSession`` object with
+``QMediaCaptureSession.setScreenCapture()`` and
+``QMediaCaptureSession.setWindowCapture()``, respectively. The capture session
+in turn is connected to the ``QVideoWidget`` object with
+``QMediaCaptureSession.setVideoOutput()``. Thus, the capture output is
+previewed in the video widget on the right hand side of the UI.
+
+The start/stop button calls ``QScreenCapture.start()`` and ``QScreenCapture.stop()``,
+or ``QWindowCapture.start()`` and ``QWindowCapture.stop()``.
+
+A QMessageBox pops up if an ``errorOccurred`` signal is emitted.
+
+.. image. screencapture.webp
:width: 600
:alt: screen capture example
diff --git a/examples/multimedia/screencapture/doc/screencapture.webp b/examples/multimedia/screencapture/doc/screencapture.webp
index 2723b1d53..58ad36c7f 100644
--- a/examples/multimedia/screencapture/doc/screencapture.webp
+++ b/examples/multimedia/screencapture/doc/screencapture.webp
Binary files differ
diff --git a/examples/multimedia/screencapture/main.py b/examples/multimedia/screencapture/main.py
index dce30186c..f445bac03 100644
--- a/examples/multimedia/screencapture/main.py
+++ b/examples/multimedia/screencapture/main.py
@@ -5,6 +5,7 @@
import sys
+from PySide6.QtCore import QCoreApplication
from PySide6.QtWidgets import QApplication
from screencapturepreview import ScreenCapturePreview
@@ -12,6 +13,8 @@ from screencapturepreview import ScreenCapturePreview
if __name__ == "__main__":
app = QApplication(sys.argv)
+ QCoreApplication.setApplicationName("screencapture")
+ QCoreApplication.setOrganizationName("QtProject")
screen_capture_preview = ScreenCapturePreview()
screen_capture_preview.show()
sys.exit(app.exec())
diff --git a/examples/multimedia/screencapture/screencapture.pyproject b/examples/multimedia/screencapture/screencapture.pyproject
index 9b18fa093..dfec6c901 100644
--- a/examples/multimedia/screencapture/screencapture.pyproject
+++ b/examples/multimedia/screencapture/screencapture.pyproject
@@ -1,3 +1,3 @@
{
- "files": ["main.py", "screencapturepreview.py", "screenlistmodel.py"]
+ "files": ["main.py", "screencapturepreview.py", "screenlistmodel.py", "windowlistmodel.py"]
}
diff --git a/examples/multimedia/screencapture/screencapturepreview.py b/examples/multimedia/screencapture/screencapturepreview.py
index 72fe77c64..3f75a0601 100644
--- a/examples/multimedia/screencapture/screencapturepreview.py
+++ b/examples/multimedia/screencapture/screencapturepreview.py
@@ -1,14 +1,23 @@
# Copyright (C) 2023 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+from enum import Enum, auto
+
from PySide6.QtMultimediaWidgets import QVideoWidget
-from PySide6.QtMultimedia import QScreenCapture, QMediaCaptureSession
+from PySide6.QtMultimedia import (QCapturableWindow, QMediaCaptureSession,
+ QScreenCapture, QWindowCapture)
from PySide6.QtWidgets import (QGridLayout, QLabel, QListView,
QMessageBox, QPushButton, QWidget)
-from PySide6.QtGui import QGuiApplication
-from PySide6.QtCore import Slot
+from PySide6.QtGui import QAction, QGuiApplication
+from PySide6.QtCore import QItemSelection, Qt, Slot
from screenlistmodel import ScreenListModel
+from windowlistmodel import WindowListModel
+
+
+class SourceType(Enum):
+ Screen = auto()
+ Window = auto()
class ScreenCapturePreview(QWidget):
@@ -16,58 +25,127 @@ class ScreenCapturePreview(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
+ self._source = SourceType.Screen
+
self._screen_capture = QScreenCapture(self)
self._media_capture_session = QMediaCaptureSession(self)
self._video_widget = QVideoWidget(self)
self._screen_list_view = QListView(self)
- self._screen_label = QLabel("Double-click screen to capture:", self)
- self._video_widget_label = QLabel("QScreenCapture output:", self)
- self._start_stop_button = QPushButton("Stop screencapture", self)
+ self._screen_label = QLabel("Select screen to capture:", self)
+ self._video_widget_label = QLabel("Capture output:", self)
+ self._start_stop_button = QPushButton(self)
self._screen_list_model = ScreenListModel(self)
# Setup QScreenCapture with initial source:
- self.set_screen(QGuiApplication.primaryScreen())
+ self.setScreen(QGuiApplication.primaryScreen())
self._screen_capture.start()
self._media_capture_session.setScreenCapture(self._screen_capture)
self._media_capture_session.setVideoOutput(self._video_widget)
self._screen_list_view.setModel(self._screen_list_model)
+ self._window_list_view = QListView(self)
+ self._window_capture = QWindowCapture(self)
+ self._media_capture_session.setWindowCapture(self._window_capture)
+ self._window_label = QLabel("Select window to capture:", self)
+
+ self._window_list_model = WindowListModel(self)
+ self._window_list_view.setModel(self._window_list_model)
+ update_action = QAction("Update windows List", self)
+ update_action.triggered.connect(self._window_list_model.populate)
+ self._window_list_view.addAction(update_action)
+ self._window_list_view.setContextMenuPolicy(Qt.ActionsContextMenu)
+
grid_layout = QGridLayout(self)
grid_layout.addWidget(self._screen_label, 0, 0)
grid_layout.addWidget(self._screen_list_view, 1, 0)
- grid_layout.addWidget(self._start_stop_button, 2, 0)
+ grid_layout.addWidget(self._start_stop_button, 4, 0)
grid_layout.addWidget(self._video_widget_label, 0, 1)
- grid_layout.addWidget(self._video_widget, 1, 1, 2, 1)
+ grid_layout.addWidget(self._video_widget, 1, 1, 4, 1)
+ grid_layout.addWidget(self._window_label, 2, 0)
+ grid_layout.addWidget(self._window_list_view, 3, 0)
grid_layout.setColumnStretch(1, 1)
grid_layout.setRowStretch(1, 1)
grid_layout.setColumnMinimumWidth(0, 400)
grid_layout.setColumnMinimumWidth(1, 400)
+ grid_layout.setRowMinimumHeight(3, 1)
- self._screen_list_view.activated.connect(self.on_screen_selection_changed)
- self._start_stop_button.clicked.connect(self.on_start_stop_button_clicked)
- self._screen_capture.errorOccurred.connect(self.on_screen_capture_error_occured)
+ selection_model = self._screen_list_view.selectionModel()
+ selection_model.selectionChanged.connect(self.on_current_screen_selection_changed)
+ selection_model = self._window_list_view.selectionModel()
+ selection_model.selectionChanged.connect(self.on_current_window_selection_changed)
- def set_screen(self, screen):
- self._screen_capture.setScreen(screen)
- self.setWindowTitle(f"Capturing {screen.name()}")
+ self._start_stop_button.clicked.connect(self.on_start_stop_button_clicked)
+ self._screen_capture.errorOccurred.connect(self.on_screen_capture_error_occured,
+ Qt.QueuedConnection)
+ self._window_capture.errorOccurred.connect(self.on_window_capture_error_occured,
+ Qt.QueuedConnection)
+ self.update_active(SourceType.Screen, True)
+
+ @Slot(QItemSelection)
+ def on_current_screen_selection_changed(self, selection):
+ indexes = selection.indexes()
+ if indexes:
+ self._screen_capture.setScreen(self._screen_list_model.screen(indexes[0]))
+ self.update_active(SourceType.Screen, self.is_active())
+ self._window_list_view.clearSelection()
+ else:
+ self._screen_capture.setScreen(None)
+
+ @Slot(QItemSelection)
+ def on_current_window_selection_changed(self, selection):
+ indexes = selection.indexes()
+ if indexes:
+ window = self._window_list_model.window(indexes[0])
+ if not window.isValid():
+ m = "The window is no longer valid. Update the list of windows?"
+ answer = QMessageBox.question(self, "Invalid window", m)
+ if answer == QMessageBox.Yes:
+ self.update_active(SourceType.Window, False)
+ self._window_list_view.clearSelection()
+ self._window_list_model.populate()
+ return
+ self._window_capture.setWindow(window)
+ self.update_active(SourceType.Window, self.is_active())
+ self._screen_list_view.clearSelection()
+ else:
+ self._window_capture.setWindow(QCapturableWindow())
- @Slot()
- def on_screen_selection_changed(self, index):
- self.set_screen(self._screen_list_model.screen(index))
+ @Slot(QWindowCapture.Error, str)
+ def on_window_capture_error_occured(self, error, error_string):
+ QMessageBox.warning(self, "QWindowCapture: Error occurred",
+ error_string)
- @Slot()
- def on_screen_capture_error_occured(self, error, errorString):
+ @Slot(QScreenCapture.Error, str)
+ def on_screen_capture_error_occured(self, error, error_string):
QMessageBox.warning(self, "QScreenCapture: Error occurred",
- errorString)
+ error_string)
@Slot()
def on_start_stop_button_clicked(self):
- if self._screen_capture.isActive():
- self._screen_capture.stop()
- self._start_stop_button.setText("Start screencapture")
- else:
- self._screen_capture.start()
- self._start_stop_button.setText("Stop screencapture")
+ self.update_active(self._source_type, not self.is_active())
+
+ def update_start_stop_button_text(self):
+ active = self.is_active()
+ if self._source_type == SourceType.Window:
+ m = "Stop window capture" if active else "Start window capture"
+ self._start_stop_button.setText(m)
+ elif self._source_type == SourceType.Screen:
+ m = "Stop screen capture" if active else "Start screen capture"
+ self._start_stop_button.setText(m)
+
+ def update_active(self, source_type, active):
+ self._source_type = source_type
+ self._screen_capture.setActive(active and source_type == SourceType.Screen)
+ self._window_capture.setActive(active and source_type == SourceType.Window)
+
+ self.update_start_stop_button_text()
+
+ def is_active(self):
+ if self._source_type == SourceType.Window:
+ return self._window_capture.isActive()
+ if self._source_type == SourceType.Screen:
+ return self._screen_capture.isActive()
+ return False
diff --git a/examples/multimedia/screencapture/windowlistmodel.py b/examples/multimedia/screencapture/windowlistmodel.py
new file mode 100644
index 000000000..079040ec2
--- /dev/null
+++ b/examples/multimedia/screencapture/windowlistmodel.py
@@ -0,0 +1,30 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+from PySide6.QtCore import QAbstractListModel, Qt, Slot
+from PySide6.QtMultimedia import QWindowCapture
+
+
+class WindowListModel(QAbstractListModel):
+
+ def __init__(self, parent=None):
+ super().__init__(parent)
+ self._window_list = QWindowCapture.capturableWindows()
+
+ def rowCount(self, QModelIndex):
+ return len(self._window_list)
+
+ def data(self, index, role):
+ if role == Qt.DisplayRole:
+ window = self._window_list[index.row()]
+ return window.description()
+ return None
+
+ def window(self, index):
+ return self._window_list[index.row()]
+
+ @Slot()
+ def populate(self):
+ self.beginResetModel()
+ self._window_list = QWindowCapture.capturableWindows()
+ self.endResetModel()