You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyQt5实现控件与窗口自定义阴影的qt_blurImage接口调用方案咨询

PyQt5 自定义控件/窗口阴影效果实现方案

开发过程中需要为PyQt5的控件或窗口添加自定义阴影效果时,原生PyQt5未暴露qt_blurImage接口,无法直接复用原C版本的Qt阴影实现逻辑,对应的C接口定义如下:

QT_BEGIN_NAMESPACE
extern Q_WIDGETS_EXPORT void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius, bool quality, bool alphaOnly, int transposed = 0 );
QT_END_NAMESPACE

C++实现中的调用语句为:

qt_blurImage(&blurPainter, tmp, blurRadius(), false, true);

可行实现方案

可通过ctypes调用Qt5Widgets.dll中对应的隐藏接口实现需求,完整代码如下:

from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5 import sip
import ctypes
# 该接口未在PyQt中暴露,可通过ctypes调用
_qt_blurImage  = getattr(ctypes.CDLL(r"E:\Python\Lib\site-packages\PyQt5\Qt5\bin\Qt5Widgets.dll"), 
        '?qt_blurImage@@YAXPAVQPainter@@AAVQImage@@N_N2H@Z')
class CustomShadowEffect(QGraphicsEffect):
    def __init__(self,parent):
        super().__init__(parent)
        self._distance=4.0
        self._blurRadius=10.0
        self._color=QColor (0, 0, 0, 80)
    def setBlurRadius(self, blurRadius) :
        self._blurRadius = blurRadius
        self.updateBoundingRect()  
    def blurRadius(self) :
        return self._blurRadius  
    def setColor(self, color):
         self._color = color
    def color(self) :
         return self._color
    def setDistance(self,distance) :
        self._distance = distance
        self. updateBoundingRect()
    def distance(self) :
         return self._distance
    def boundingRectFor( self,rect) :
        delta = self.blurRadius() + self.distance()
        return rect.united(rect.adjusted(-delta, -delta, delta, delta))
       
    def draw(self, painter):
        # 若不需要向外扩展阴影,直接绘制原控件
        if ((self.blurRadius() + self.distance()) <= 0) :
            self.drawSource(painter)
            return
        
        mode = QGraphicsEffect.PadToEffectiveBoundingRect
        px,offset = self.sourcePixmap(Qt.DeviceCoordinates, mode)

        # 无原控件内容直接返回
        if (px.isNull()):
            return
        
        # 保存世界变换
        restoreTransform = painter.worldTransform()
        painter.setWorldTransform(QTransform())

        # 计算背景图尺寸
        szi=QSize (int(px.size().width() + 2 * self.distance()), int(px.size().height() + 2 * self.distance()))

        tmp=QImage(szi, QImage.Format_ARGB32_Premultiplied)
        scaled = px.scaled(szi)
        tmp.fill(0)
        tmpPainter=QPainter(tmp)
        tmpPainter.setCompositionMode(QPainter.CompositionMode_Source)
        tmpPainter.drawPixmap(QPointF(-self.distance(), -self.distance()), scaled)
        tmpPainter.end()

        # 模糊alpha通道
        blurred=QImage(tmp.size(), QImage.Format_ARGB32_Premultiplied)
        blurred.fill(0)
        blurPainter=QPainter(blurred)
        self.applyBlurEffect(blurPainter, tmp, self.blurRadius(), False, True)
        blurPainter.end()

        tmp = blurred

        # 为阴影填充指定颜色
        tmpPainter.begin(tmp)
        tmpPainter.setCompositionMode(QPainter.CompositionMode_SourceIn)
        tmpPainter.fillRect(tmp.rect(), self.color())
        tmpPainter.end()

        # 绘制模糊阴影
        painter.drawImage(offset, tmp)

        # 绘制原控件内容
        painter.drawPixmap(offset, px, QRectF())

        # 恢复世界变换
        painter.setWorldTransform(restoreTransform)
    def applyBlurEffect(self, painter,blurImage, radius, quality, alphaOnly, transposed=0 ):
        blurImage = ctypes.c_void_p(sip.unwrapinstance(blurImage))
        radius = ctypes.c_double(radius)
        quality = ctypes.c_bool(quality)
        alphaOnly = ctypes.c_bool(alphaOnly)
        transposed = ctypes.c_int(transposed)
        if painter:
            painter = ctypes.c_void_p(sip.unwrapinstance(painter))
        _qt_blurImage(painter, blurImage, radius, quality, alphaOnly, transposed)
           

if __name__=="__main__": 
    app=QApplication([])
    win=QWidget()
    win.resize(400,400)
    l=QLabel(win)
    l.setGeometry(100,100,200,200)
    l.setStyleSheet("background:green;border-radius:15px;color:white;font: 18pt Calibri;")
    l.setAlignment(Qt.AlignCenter)
    bodyShadow = CustomShadowEffect(l)
    bodyShadow.setBlurRadius(20.0)
    bodyShadow.setDistance(10.0)
    bodyShadow.setColor(QColor(0, 0, 0, 200))
    l.setAutoFillBackground(True)
    l.setGraphicsEffect(bodyShadow)
    l.setText("hello")
    win.show()
    app.exec_()

窗口阴影使用示例

注意:如果需要为整个窗口添加阴影,可使用如下示例代码:

if __name__=="__main__": 
    app=QApplication([])
    win=QMainWindow()
    win.resize(400,400)
    l=QWidget(win)
    l.setGeometry(10,10,380,380)
    win.setAttribute(Qt.WA_TranslucentBackground)
    win.setWindowFlag(Qt.FramelessWindowHint)
    l.setStyleSheet("background:green;border-radius:15px;")
    bodyShadow = CustomShadowEffect(l)
    bodyShadow.setBlurRadius(5.0)
    bodyShadow.setDistance(5.0)
    bodyShadow.setColor(QColor(23, 144, 255, 255))
    l.setGraphicsEffect(bodyShadow)
    win.show()
    app.exec_()

实现效果

效果图1
效果图2


内容的提问来源于stack exchange,提问作者Raj1234

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 22:24:06