使用PyQt5,如何在布局的矩形区域上添加阴影效果

2024-06-11 21:25:20 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试实现一个网格的图像标题下,与悬停阴影。到目前为止,我所做的是在两个小部件(带有图像的标签和带有标题的标签)上添加阴影,但我希望在包含它们的矩形区域上添加阴影。它试图将它们放在另一个小部件上,并在这个小部件上应用效果,但它仍然适用于两个标签。代码如下

import sys, os
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *



class App(QMainWindow):
    def __init__(self):
        super().__init__()
        self.title = 'PyQt5 layout - pythonspot.com'
        self.left = 100
        self.top = 100
        self.width = 800
        self.height = 600
        
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        content_widget = QWidget()
        self.setCentralWidget(content_widget)
        self._lay = QGridLayout(content_widget)

        self.shadow = QGraphicsDropShadowEffect(self)
        self.shadow.setBlurRadius(5)
        
        nb = 6
        i = 0
        for i in range(0, 12):
            panel=QWidget()
            vbox = QVBoxLayout()
            pixmap = QPixmap(str(i+1)+"jpg")
            pixmap = pixmap.scaled(100, 150, transformMode=Qt.SmoothTransformation)
            img_label = QLabel(pixmap=pixmap)
            vbox.addWidget(img_label)
            
            txt_label = QLabel(str(i+1))
            vbox.addWidget(txt_label)
            vbox.addStretch(1)
            panel.setLayout(vbox)
            self._lay.addWidget(panel , int(i/nb), i%nb)
            panel.installEventFilter(self)
            i = i+1
            
        self.show()
        
    def eventFilter(self, object, event):
        if event.type() == QEvent.Enter:
            object.setGraphicsEffect(self.shadow)
            self.shadow.setEnabled(True)
        elif event.type() == QEvent.Leave:
            print("Mouse is not over the label")
            self.shadow.setEnabled(False)
        return False

if __name__ == '__main__':

    app = QApplication(sys.argv)
    ex = App()
    sys.exit(app.exec_())


Tags: fromimportself部件sys标签contentwidget
1条回答
网友
1楼 · 发布于 2024-06-11 21:25:20

问题来自于一个普通的QWidget通常不会自己绘制任何东西:它只是一个透明的widget。如果应用图形效果,它将是该小部件内部的结果

解决方案是通过调用^{},确保小部件是不透明的

不幸的是,特别是在您的情况下,结果不会很好,因为您有很多其他小部件,它们之间有一定的间距。你最终会在一切的后面有阴影

shadow behind everything

解决方案是在设置图形效果时调用^{},以确保小部件实际上比任何其他东西都高(显然是在其父级的兄弟姐妹和子级之间)。
不幸的是——同样——这有一个小但重要的问题,与您的实现有关:第一次从一个小部件上删除效果时,因为它设置在另一个小部件上,周围的小部件无法正确更新

artifacts

这主要是由于绘画引擎的优化和图形效果的实现

为避免此问题,有两种可能性:

  1. 为每个小部件设置唯一的图形效果,在创建时禁用,然后仅在enterEvent上启用它:
class App(QMainWindow):
    def __init__(self):
        # ...
        for i in range(0, 12):
            panel = QWidget()
            effect = QGraphicsDropShadowEffect(panel, enabled=False, blurRadius=5)
            panel.setGraphicsEffect(panel)
            # ...

    def eventFilter(self, obj, event):
        if event.type() == QEvent.Enter and obj.graphicsEffect():
            obj.graphicsEffect().setEnabled(True)
        elif event.type() == QEvent.Leave and obj.graphicsEffect():
            obj.graphicsEffect().setEnabled(False)
        return super().eventFilter(obj, event)
  1. 或者,获取图形效果的边界矩形,将其转换为小部件的坐标,检查是否有任何其他“同级”几何体与边界矩形相交,并最终调用这些小部件上的update()
class App(QMainWindow):
    def __init__(self):
        # ...
        self.panels = []
        for i in range(0, 12):
            panel = QWidget()
            self.panels.append(panel)
            # ...

    def eventFilter(self, obj, event):
        if event.type() == QEvent.Enter:
            obj.setGraphicsEffect(self.shadow)
            self.shadow.setEnabled(True)
            obj.raise_()
        elif event.type() == QEvent.Leave:
            obj.graphicsEffect().setEnabled(False)
            rect = self.shadow.boundingRect().toRect()
            rect.translate(obj.geometry().topLeft())
            for other in self.panels:
                if other != obj and other.geometry().intersects(rect):
                    other.update()
        return super().eventFilter(obj, event)

PS:object是Python的内置类型,不应将其用作变量

相关问题 更多 >