定期截屏虽然完全可行,但由于会影响性能,因此不受欢迎。相反,您应该使用主窗口的onFrameSwapped() 信号,仅在生成新帧时抓取图像。
理想情况下,您会想要使用 Layer 或 ShaderEffectSource,正如 @dtech 所建议的那样,直接从 GPU 读取和重新渲染帧。不幸的是,由于 Qt Quick 的场景图的限制,不可能在不破坏源窗口的场景图的情况下跨单独的窗口完成此操作。
选项是通过 CPU 复制帧,或者在 C++ 中重新实现部分 QML 引擎以在生成新帧时提取图像。
有效的 QML 解决方案
最简单的方法是从 QML 中抓取帧,使用 Item 的 grabToImage() 函数。由于 Window 本身不是一个项目,因此您必须从其中一个元素中获取图像。在此示例中,每次在 mainWindow 上交换帧时,我使用 onFrameSwapped() 信号从名为 viewport 的项目中获取图像。然后将内存中该图像的路径设置为第二个窗口中图像的源,名为 projectionWindow。第二个窗口将在 screenID 变量设置的屏幕上打开;它也被设置为无框窗口,其可见性设置为最大化或全屏,因此它是在第二个屏幕上看到的唯一窗口。
import QtQuick 2.15
import QtQuick.Window 2.15
Window {
id: mainWindow
title: qsTr("Main Window")
visible: true
width: 400
height: 200
color: "#0F0"
Rectangle {
id: viewport
color: "#00F"
width: parent.width/2
height: parent.height/2
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
}
onFrameSwapped: {
viewport.grabToImage(function(result) {
projectionWindow.frame = String(result.url);
});
}
Window {
id: projectionWindow
property int screenID: 1
property alias frame: img.source
transientParent: mainWindow
visible: true
x: Qt.application.screens[screenID].virtualX
y: Qt.application.screens[screenID].virtualY
width: Qt.application.screens[screenID].desktopAvailableWidth
height: Qt.application.screens[screenID].desktopAvailableHeight
flags: Qt.FramelessWindowHint
color: "#000"
visibility: Window.Maximized
// visibility: Window.FullScreen
Image {
id: img
anchors.fill: parent
fillMode: Image.PreserveAspectFit
// Performance tweaks
asynchronous: true
cache: false
}
}
}
我实际上已经在我开发的一个项目中使用了这个解决方案。您可以在以下位置学习完整的实现:
替代 C++ 解决方案
第二种更有效但不完整的解决方案超出了我目前的经验水平。本质上,您将从 QQuickWindow 继承并将图像发送到QQuickWindow::afterRendering() 或QQuickWindow::frameSwapped() 信号上的第二个窗口。您将使用QQuickFramebufferObject 来渲染和抓取屏幕外的帧,这意味着使用 OpenGL 作为您的渲染器,这可能会限制 Qt 6 中的平台可移植性,或者至少会抵消使用本机渲染管道带来的所有性能优势。
https://doc.qt.io/qt-6/qtquick-visualcanvas-scenegraph.html
Giuseppe D'Angelo 的以下演讲展示了其中一些是如何设置的。它没有显示如何将内容复制到另一个窗口/屏幕,但它可以在这方面有所帮助。
https://www.youtube.com/watch?v=V_idc9BBRuI
https://www.youtube.com/watch?v=D-7fVGIBz6k