簡體   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