屏幕截图示例#

屏幕截图展示了如何使用QScreenCaptureQWindowCapture来捕获屏幕或窗口。该示例显示了一个屏幕和窗口列表,并使用一个QMediaCaptureSession和一个QVideoWidget显示所选项目的实时预览。可以通过一个QPushButton来启动或停止捕获。

应用程序结构#

该示例由三个自定义类组成。UI 组件和所有屏幕捕获功能都由类 ScreenCapturePreview 实现。类 ScreenListModelWindowListModel 仅作为两个 QListView 小部件的模型存在。主函数创建一个 ScreenCapturePreview 对象,该对象随后创建 QScreenCaptureQWindowCapture 的实例,以及一个 QMediaCaptureSessionQVideoWidget,此外还有所有 UI 小部件。

屏幕和窗口模型分别用 QGuiApplication.screens()QWindowCapture.capturableWindows() 的返回值填充。

当选择列表项时,使用 QScreenCapture.setScreen() 将其连接到 QScreenCapture 对象,或者使用 QWindowCapture.setWindow(). 将其连接到 QWindowCapture 对象。捕获对象分别使用 QMediaCaptureSession.setScreenCapture()QMediaCaptureSession.setWindowCapture() 连接到 QMediaCaptureSession 对象。捕获会话随后通过 QMediaCaptureSession.setVideoOutput() 连接到 QVideoWidget 对象。因此,捕获输出在 UI 右侧的视频小部件中预览。

开始/停止按钮调用 QScreenCapture.start()QScreenCapture.stop(),或 QWindowCapture.start()QWindowCapture.stop()

如果发出 errorOccurred 信号,将弹出一个 QMessageBox。

下载 此示例

# Copyright (C) 2023 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

"""PySide6 port of the QtMultiMedia Screen Capture Example from Qt v6.x"""

import sys

from PySide6.QtCore import QCoreApplication
from PySide6.QtWidgets import QApplication

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())
# 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 (QCapturableWindow, QMediaCaptureSession,
                                  QScreenCapture, QWindowCapture)
from PySide6.QtWidgets import (QGridLayout, QLabel, QListView,
                               QMessageBox, QPushButton, QWidget)
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):

    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("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.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, 4, 0)
        grid_layout.addWidget(self._video_widget_label, 0, 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)

        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)

        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(QWindowCapture.Error, str)
    def on_window_capture_error_occured(self, error, error_string):
        QMessageBox.warning(self, "QWindowCapture: Error occurred",
                            error_string)

    @Slot(QScreenCapture.Error, str)
    def on_screen_capture_error_occured(self, error, error_string):
        QMessageBox.warning(self, "QScreenCapture: Error occurred",
                            error_string)

    @Slot()
    def on_start_stop_button_clicked(self):
        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
# Copyright (C) 2023 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

from PySide6.QtGui import QGuiApplication
from PySide6.QtCore import QAbstractListModel, Qt, Slot


class ScreenListModel(QAbstractListModel):

    def __init__(self, parent=None):
        super().__init__(parent)
        app = qApp  # noqa: F821
        app.screenAdded.connect(self.screens_changed)
        app.screenRemoved.connect(self.screens_changed)
        app.primaryScreenChanged.connect(self.screens_changed)

    def rowCount(self, index):
        return len(QGuiApplication.screens())

    def data(self, index, role):
        screen_list = QGuiApplication.screens()

        if role == Qt.DisplayRole:
            screen = screen_list[index.row()]
            w = screen.size().width()
            h = screen.size().height()
            dpi = screen.logicalDotsPerInch()
            return f'"{screen.name()}" {w}x{h}, {dpi}DPI'

        return None

    def screen(self, index):
        return QGuiApplication.screens()[index.row()]

    @Slot()
    def screens_changed(self):
        self.beginResetModel()
        self.endResetModel()
# 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()