Search code examples
pythonpyqtpyqt5qgraphicseffect

Using QGraphicsDropShadowEffect with multiple widgets


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

Solution

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