Shadow effect does not work in QMainWindow

Question:

I have the following code in which I try to show a shadow effect behind the QMainWindow, for which I use QGraphicsDropShadowEffect
to be able to get the shadow.

But when running the code does not suspend anything.

I already tried modifying the color and the offset but it did not work either

enter image description here

Code. Py

from PyQt5.QtWidgets import QMainWindow,QApplication,QGraphicsDropShadowEffect
from PyQt5 import QtCore,QtGui
from PyQt5 import uic


class CInicial(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        uic.loadUi("ConfiguracionInicial.ui",self)

        self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
        self.setAttribute(QtCore.Qt.WA_TranslucentBackground)

        self.shadow = QGraphicsDropShadowEffect(self)
        self.shadow.setBlurRadius(99)
        self.shadow.setColor(QtGui.QColor(99,255,255))
        self.shadow.setOffset(4)
        self.setGraphicsEffect(self.shadow)



app = QApplication([])
ci = CInicial()
ci.show()
app.exec_()

. Ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>683</width>
    <height>482</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <property name="styleSheet">
   <string notr="true">background-color:#5E5858;</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <widget class="QFrame" name="fContenedor1">
    <property name="geometry">
     <rect>
      <x>0</x>
      <y>0</y>
      <width>691</width>
      <height>41</height>
     </rect>
    </property>
    <property name="styleSheet">
     <string notr="true">background:qlineargradient(spread:pad, x1:0.498, y1:1, x2:0.472, y2:0, stop:0 rgba(46, 46, 48, 255), stop:1 rgba(137, 137, 137, 255));</string>
    </property>
    <property name="frameShape">
     <enum>QFrame::StyledPanel</enum>
    </property>
    <property name="frameShadow">
     <enum>QFrame::Raised</enum>
    </property>
    <widget class="QLabel" name="label">
     <property name="geometry">
      <rect>
       <x>5</x>
       <y>9</y>
       <width>151</width>
       <height>21</height>
      </rect>
     </property>
     <property name="font">
      <font>
       <pointsize>10</pointsize>
       <weight>75</weight>
       <bold>true</bold>
      </font>
     </property>
     <property name="styleSheet">
      <string notr="true">color:white;
background:none;</string>
     </property>
     <property name="text">
      <string>ConfiguraciĆ³n Inicial</string>
     </property>
    </widget>
   </widget>
  </widget>
 </widget>
 <resources/>
 <connections/>
</ui>

Answers:

When the shadow effect is applied it is painted in the parent widget, so in the case of your CInicial it will have no effect. One solution is to create a parent widget and set the Initialize through a layout:

from PyQt5 import QtCore, QtGui, QtWidgets, uic

class Container(QtWidgets.QWidget):
    def __init__(self, window, parent=None):
        super(Container, self).__init__(parent)
        self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
        self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
        lay = QtWidgets.QVBoxLayout(self)
        lay.addWidget(window)
        lay.setContentsMargins(10, 10, 10, 10)
        shadow = QtWidgets.QGraphicsDropShadowEffect(self,
            blurRadius=9.0,
            color=QtGui.QColor(99, 255, 255),
            offset=QtCore.QPointF(8.0, 8.0)
        )
        window.setGraphicsEffect(shadow)

class CInicial(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(CInicial, self).__init__(parent)
        uic.loadUi("ConfiguracionInicial.ui",self)

if __name__ == '__main__':
    import sys 
    app = QtWidgets.QApplication(sys.argv)
    w = CInicial()
    container = Container(w)
    container.resize(640, 480)
    container.show()
    sys.exit(app.exec_())

enter image description here

Answered By: eyllanesc

If you want to not only drop the shadow but also make the corner rounded, here is the solution.

from PyQt5.QtCore import Qt, QRectF, QMargins
from PyQt5.QtGui import QColor, QPainter, QPainterPath, QBrush, QPen, QRegion, QPalette
from PyQt5.QtWidgets import QWidget, QMainWindow, QApplication, QGraphicsDropShadowEffect, QGridLayout, QLabel, 
    QTextEdit, QVBoxLayout


# shadow + rounded frame
class ShadowFrame(QWidget):
    def __init__(self, main_window):
        super().__init__()
        # main_window is main widget to show
        self.__main_window = main_window
        self.__initUi()

    def __initUi(self):
        # for frameless window/prevent occurrence of minor bugs
        self.setWindowFlags(Qt.Window | Qt.FramelessWindowHint | Qt.WindowMinMaxButtonsHint)
        # make basic background(which is dark) invisible to show shadow
        self.setAttribute(Qt.WA_TranslucentBackground)

        # set the shadow
        self.__effect = QGraphicsDropShadowEffect()
        self.__effect.setBlurRadius(12.0)
        self.__effect.setColor(QColor(0, 0, 0, 127))
        self.__effect.setOffset(0.0)
        self.setGraphicsEffect(self.__effect)

        lay = QGridLayout()
        lay.addWidget(self.__main_window)
        self.setLayout(lay)

    def paintEvent(self, e):
        painter = QPainter(self)
        # set the background and pen (looks like Windows 11 default window)
        pen = QPen(QColor(Qt.gray), 1)
        brush = QBrush(QColor(241, 241, 241, 255))
        painter.setPen(pen)
        painter.setBrush(brush)

        # set rounded window
        path = QPainterPath()
        rect = self.rect()
        # set margin to each direction for giving the space to show shadow
        rect = rect.marginsRemoved(QMargins(5, 5, 5, 5))
        # rounded corner's radius
        radius = 12.0
        path.addRoundedRect(QRectF(rect), radius, radius)
        # set antialiasing to enhance quality of window
        painter.setRenderHints(QPainter.Antialiasing)
        painter.drawPath(path)

        return super().paintEvent(e)


# sample widget to put inside the shadow(+rounded) frame
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.__initUi()

    def __initUi(self):
        lbl = QLabel()
        lbl.setText('Shadow window example')
        textEdit = QTextEdit()

        lay = QVBoxLayout()
        lay.addWidget(lbl)
        lay.addWidget(textEdit)

        mainWidget = QWidget()
        mainWidget.setLayout(lay)
        self.setCentralWidget(mainWidget)


if __name__ == "__main__":
    import sys

    app = QApplication(sys.argv)
    widget = MainWindow()
    # put inside the shadow(+rounded) frame
    window = ShadowFrame(widget)
    window.show()
    app.exec_()

Check my repo if you want to see the detail of it: https://github.com/yjg30737/pyqt-shadow-frame-window-example

Answered By: yjg30737
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.