You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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

火山引擎 最新活动