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_()
实现效果


内容的提问来源于stack exchange,提问作者Raj1234
相关产品推荐
相关产品推荐

