屏幕截图示例#
屏幕截图展示了如何使用QScreenCapture
和QWindowCapture
来捕获屏幕或窗口。该示例显示了一个屏幕和窗口列表,并使用一个QMediaCaptureSession
和一个QVideoWidget
显示所选项目的实时预览。可以通过一个QPushButton
来启动或停止捕获。
应用程序结构#
该示例由三个自定义类组成。UI 组件和所有屏幕捕获功能都由类 ScreenCapturePreview
实现。类 ScreenListModel
和 WindowListModel
仅作为两个 QListView
小部件的模型存在。主函数创建一个 ScreenCapturePreview
对象,该对象随后创建 QScreenCapture
和 QWindowCapture
的实例,以及一个 QMediaCaptureSession
和 QVideoWidget
,此外还有所有 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()