Using QGraphicsDropShadowEffect with multiple widgets

6.7k views Asked by At

I want to set a shadow on several widgets using QGraphicsDropShadowEffect and I am wondering if there is a better way to do so without having to write the same code over and over again for every instance where I want to use it like in my example below. Is it possible to create a class or something to call so that I just have to set setGraphicsEffect() on the widgets? I have tried to create a few classes for it but I was still only able to get them to create one shadow.

import sys
from PyQt5.QtWidgets import QWidget, QHBoxLayout, \
    QGraphicsDropShadowEffect, QPushButton, QApplication, QComboBox


class MainWindow(QWidget):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        layout = QHBoxLayout()

        self.shadow = QGraphicsDropShadowEffect()
        self.shadow.setBlurRadius(5)
        self.shadow.setXOffset(3)
        self.shadow.setYOffset(3)

        self.shadow2 = QGraphicsDropShadowEffect()
        self.shadow2.setBlurRadius(5)
        self.shadow2.setXOffset(3)
        self.shadow2.setYOffset(3)

        self.btn = QPushButton("Button")
        self.btn.setGraphicsEffect(self.shadow)
        self.combo = QComboBox()
        self.combo.setGraphicsEffect(self.shadow2)

        layout.addWidget(self.btn)
        layout.addWidget(self.combo)
        self.setLayout(layout)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = MainWindow()
    w.show()
    app.exec_()
3

There are 3 answers

1
eyllanesc On BEST ANSWER

The docs states that the same QGraphicsEffect can not be shared by other widgets:

If effect is the installed effect on a different widget, setGraphicsEffect() will remove the effect from the widget and install it on this widget.

So you will have to create a QGraphicsEffect for each widget, but if you do not want to write a lot of code and want to apply effects with similar characteristics you could iterate through the widgets and for that you can use findChildren(...).

import sys
from PyQt5.QtWidgets import QWidget, QHBoxLayout, \
    QGraphicsDropShadowEffect, QPushButton, QApplication, QComboBox


class MainWindow(QWidget):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        layout = QHBoxLayout(self)

        self.btn = QPushButton("Button")
        self.combo = QComboBox()

        layout.addWidget(self.btn)
        layout.addWidget(self.combo)

        for child in self.findChildren(QWidget):
            shadow = QGraphicsDropShadowEffect(blurRadius=5, xOffset=3, yOffset=3)
            child.setGraphicsEffect(shadow)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())
0
luceric On

Children inherit the effect, so all you needed to do is set it on the parent

import sys
from PySide2.QtWidgets import QWidget, QHBoxLayout, \
    QGraphicsDropShadowEffect, QPushButton, QApplication, QComboBox


class MainWindow(QWidget):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        layout = QHBoxLayout()

        self.shadow = QGraphicsDropShadowEffect(self)
        self.shadow.setBlurRadius(16)
        self.shadow.setXOffset(8)
        self.shadow.setYOffset(8)

        self.btn = QPushButton("Button")
        self.combo = QComboBox()

        layout.addWidget(self.btn)
        layout.addWidget(self.combo)
        self.setLayout(layout)
        self.setGraphicsEffect(self.shadow)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = MainWindow()
    w.show()
    app.exec_()
0
Karastoyanov On

If someone else is facing the same issue, I have found a working solution(at least working). It's not the best solution in my opinion, but it's a simple approach and gives the desired behavior. You just should add every QLabel in a list and run for loop through the list and apply the shadow effect on every iteration.

# Import PyQt5 Engine 
from PyQt5.QtWidgets import (QApplication, 
                             QWidget, 
                             QPushButton, 
                             QLabel, 
                             QLineEdit, 
                             QMessageBox, 
                             QPlainTextEdit, 
                             QHBoxLayout, 
                             QVBoxLayout,
                             QGraphicsDropShadowEffect) 
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys

class Main(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Main")
        self.setGeometry(650, 300, 100, 50)
        self.setMaximumWidth(400)
        self.setMaximumHeight(300)
        
        qlabels = []
        
        self.main_layout = QVBoxLayout()
        self.main_layout.addSpacing(2)
        
        self.line_one = QLabel()
        self.line_one.setText("Line One")
        self.line_one.setFont(QFont('Arial', 12))
        qlabels.append(self.line_one)
        
        self.line_two = QLabel()
        self.line_two.setText("Line Two")
        self.line_two.setFont(QFont('Arial', 12))
        qlabels.append(self.line_two)
        
        for i in range(len(qlabels)):
            shadow = QGraphicsDropShadowEffect()
            shadow.setOffset(2, 1)
            qlabels[i].setGraphicsEffect(shadow)
        
        
        self.main_layout.addWidget(self.line_one)
        self.main_layout.addWidget(self.line_two)
        
        self.setLayout(self.main_layout)
        self.show()


        

app = QApplication(sys.argv)
window = Main()
window.show()
app.exec()