繁体   English   中英

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

[英]With PyQt5, how to add drop shadow effect on the rectangle area of a layout

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

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_())

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

解决方案是通过调用setAutoFillBackground(True)来确保小部件不透明

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

一切背后的阴影

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

人工制品

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

为了避免这个问题,有两种可能:

  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 的内置类型,不要把它当成变量。

self.shadow = QGraphicsDropShadowEffect(self)
self.shadow.setBlurRadius(15)
self.shadow.setXOffset(0)
self.shadow.setYOffset(0)
self.shadow.setColor(QColor(0, 0, 0, 150))
# add the shadow object to the frame
self.ui.topframe.raise_()
self.ui.topframe.setGraphicsEffect(self.shadow)

在此处输入图像描述

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM