FastBlur能否模糊后方所有内容?含PyQt5/PySide2组件的实现咨询
实现跨QML与Qt Widget的背景模糊效果
能否用FastBlur实现?
可以,但需要调整你的架构——当前QML组件被包裹在QWidget.createWindowContainer中,和原生Qt Widget处于不同渲染层级:Qt Quick使用独立的场景图渲染,而原生Widget属于平台窗口系统层级,默认情况下ShaderEffectSource只能捕获QML场景内部内容,无法获取容器外的Qt Widget。调整后就能实现你要的全局模糊效果。
解决方案1:全QML化界面(推荐,效果最佳)
如果可以将所有UI元素迁移到QML中,所有内容将处于同一个Qt Quick场景图内,ShaderEffectSource能直接捕获父窗口的全部内容,FastBlur就能完美实现背景模糊。
修改后的QML代码
import QtQuick 2.12 import QtQuick.Window 2.12 import QtQuick.Controls 2.12 import QtGraphicalEffects 1.0 ApplicationWindow { id: applicationWindow visible: true width: 600 height: 600 title: "GUI_MainWindow" // 背景图片 Image { id: image_bug anchors.fill: parent source: "im.png" } // 模糊层:捕获整个窗口所有内容 ShaderEffectSource { id: effectSource sourceItem: applicationWindow.contentItem anchors.fill: parent captureDepth: 10 // 确保捕获顶层所有UI元素 } FastBlur { id: blur anchors.fill: effectSource source: effectSource radius: 100 } // 替换原Qt Widget的Hello World为QML组件 Rectangle { width: 151 height: 181 x: 180 y: 40 color: "transparent" Text { text: "<h1>Hello World !</h1>" anchors.centerIn: parent font.pointSize: 24 font.bold: true } } // 可交互绿色条 Rectangle { width: 100; height: 600 color: "green" Text { id: helloText text: "Hello world!" anchors.verticalCenter: parent.verticalCenter anchors.horizontalCenter: parent.horizontalCenter font.pointSize: 10; font.bold: true } MouseArea { anchors.fill: parent onClicked: { effectSource.width = 1200; effectSource.height = 1200; } } } }
修改后的PyQt代码(简化版)
import sys import os from PyQt5.QtCore import QUrl from PyQt5.QtWidgets import QApplication from PyQt5.QtQml import QQmlApplicationEngine DIR_PATH = os.path.dirname(os.path.realpath(__file__)) if __name__ == "__main__": myApp = QApplication(sys.argv) file = os.path.join(DIR_PATH, "qml_window.qml") url = QUrl.fromLocalFile(file) engine = QQmlApplicationEngine() engine.load(url) if not engine.rootObjects(): sys.exit(-1) sys.exit(myApp.exec_())
解决方案2:混合架构下的屏幕抓取方案(保留Qt Widget)
如果必须保留原生Qt Widget,可通过实时抓取窗口内容的方式,将整个窗口(含Widget和QML)的像素传递给QML,再用FastBlur处理。需要监听窗口大小、Widget位置变化,实时更新抓取内容。
修改后的PyQt代码
import sys import os from PyQt5.QtCore import Qt, QUrl, QTimer from PyQt5.QtWidgets import QApplication, QWidget, QMainWindow, QVBoxLayout, QLabel from PyQt5.QtQml import QQmlApplicationEngine from PyQt5.QtGui import QPixmap DIR_PATH = os.path.dirname(os.path.realpath(__file__)) class GUI_MainWindow(QMainWindow): def __init__(self, qml_widget, parent=None): QMainWindow.__init__(self, parent) self.setWindowTitle('GUI_MainWindow') self.resize(600, 600) self.qml_widget = qml_widget centralWidget = QWidget() self.setCentralWidget(centralWidget) self.widget_test_2 = QLabel("<h1>Hello World !</h1>", alignment=Qt.AlignCenter) self.widget_test_2.setObjectName(u"widget_test_2") self.widget_test_2.setGeometry(180, 40, 151, 181) layout = QVBoxLayout(centralWidget) layout.addWidget(self.widget_test_2) layout.addWidget(self.qml_widget, stretch=1) # 定时抓取窗口内容,传递给QML(约60fps) self.grab_timer = QTimer(self) self.grab_timer.setInterval(16) self.grab_timer.timeout.connect(self.update_window_grab) self.grab_timer.start() # 获取QML根对象,用于传递抓取的图像 self.root_object = self.qml_widget.windowHandle().contentItem() def update_window_grab(self): # 抓取整个窗口的像素内容 pixmap = QApplication.primaryScreen().grabWindow(self.winId()) # 将Pixmap传递给QML的imageSource属性 self.root_object.setProperty("imageSource", pixmap) if __name__ == "__main__": myApp = QApplication(sys.argv) file = os.path.join(DIR_PATH, "qml_window.qml") url = QUrl.fromLocalFile(file) engine = QQmlApplicationEngine() engine.load(url) if not engine.rootObjects(): sys.exit(-1) qml_widget = QWidget.createWindowContainer(engine.rootObjects()[0]) window = GUI_MainWindow(qml_widget) window.show() sys.exit(myApp.exec_())
修改后的QML代码
import QtQuick 2.12 import QtQuick.Window 2.12 import QtQuick.Controls 2.12 import QtGraphicalEffects 1.0 ApplicationWindow { id: applicationWindow visible: true width: 600 height:600 property var imageSource: null // 隐藏的抓取内容,作为模糊源 Image { id: grabbedContent anchors.fill: parent source: imageSource visible: false } ShaderEffectSource { id: effectSource sourceItem: grabbedContent anchors.fill: parent } FastBlur{ id: blur anchors.fill: effectSource source: effectSource radius: 100 } // 原绿色交互条 Rectangle { width: 100; height: 600 color: "green" Text { id: helloText text: "Hello world!" anchors.verticalCenter: parent.verticalCenter anchors.horizontalCenter: parent.horizontalCenter font.pointSize: 10; font.bold: true } MouseArea { anchors.fill: parent onClicked: { effectSource.width = 1200; effectSource.height = 1200; } } } }
为什么QGraphicsBlurEffect无法满足需求?
QGraphicsBlurEffect仅能对单个QWidget或QGraphicsItem及其子元素应用模糊,属于Qt Widgets渲染体系,无法跨层级模糊Qt Quick场景图内容,也无法同时模糊自身后方的混合内容(Widget+QML),这就是它达不到预期效果的核心原因。
内容的提问来源于stack exchange,提问作者askqest




