Search code examples
pythonpython-3.xpyside2qpropertyanimation

QPropertyAnimation not working with Window Opacity


I'm setting up a new desktop widget to make my life easier at work and using QPropertyAnimation to make it pretty. Fading the app in and out doesn't seem to want to work and in typical coder fashion, it's brought my progress to a standstill.

I'm implementing QPropertyAnimation in a personalised class to make my life easier, but since it's not intially worked I've taken it back to the class code and it's still being pretty stubborn. So far I've tried.

class widget(QWidget):

def init(self):
   self.setSize(QSize(300, 300))
   self.setWindowOpacity(1)
   self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
   self.setAttribute(Qt.WA_TranslucentBackground)

def paintEvent(self, event):
   s = self.size()
   qp = QPainter()
   qp.begin(self)
   qp.setRenderHint(QPainter.Antialiasing, True)
   qp.setBrush(QColor().fromRgb(2,106,194))
   qp.setPen(QColor().fromRgb(2,106,194))
   qp.drawRoundRect(QRect(0,0, 300, 300), 16, 8)
   qp.end()

def show(self):
   self.superShow()
   a = QPropertyAnimation(self, "windowOpacity")
   a.setDuration(500)
   a.setStartValue(1)
   a.setEndValue(0)
   a.start()

def hide(self):
   a = QPropertyAnimation(self, "windowOpacity")
   a.setDuration(500)
   a.setStartValue(0)
   a.setEndValue(1)
   a.finished.connect(self.superHide)
   a.start()

def superShow(self):
   super(widget, self).show()

def superHide(self):
   super(widget, self).hide()

No error messages at all it just hides and shows after the animation duration is over. No idea where to look or what to do to get it working. I've only been coding for like 3 months or so.


Solution

  • Your code has many errors, for example:

    • I don't see where you call init().
    • Animations are local variables that will be removed when the show and hide methods are finished, which is almost instantaneous.
    • etc.

    Instead of changing the opacity directly I will use QGraphicsOpacityEffect, instead of using the show and close method, I will use the showEvent, hideEvent and closeEvent methods.

    import sys
    from PySide2.QtCore import QEasingCurve, QEventLoop, QPropertyAnimation, QRect, QSize, Qt
    from PySide2.QtGui import QColor, QPainter
    from PySide2.QtWidgets import QAction, QApplication, QGraphicsOpacityEffect, QWidget
    
    
    class Widget(QWidget):
        def __init__(self, parent=None):
            super().__init__(parent)
            self.resize(QSize(300, 300))
            # self.setWindowOpacity(1)
            self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
            self.setAttribute(Qt.WA_TranslucentBackground)
            self.setContextMenuPolicy(Qt.ActionsContextMenu)
    
            quit_action = QAction(self.tr("E&xit"), self)
            quit_action.setShortcut(self.tr("Ctrl+Q"))
            quit_action.triggered.connect(self.close)
            self.addAction(quit_action)
    
            effect = QGraphicsOpacityEffect(self, opacity=1.0)
            self.setGraphicsEffect(effect)
            self._animation = QPropertyAnimation(
                self,
                propertyName=b"opacity",
                targetObject=effect,
                duration=500,
                startValue=0.0,
                endValue=1.0,
            )
    
        def paintEvent(self, event):
            qp = QPainter(self)
            qp.setRenderHint(QPainter.Antialiasing, True)
            qp.setBrush(QColor().fromRgb(2, 106, 194))
            qp.setPen(QColor().fromRgb(2, 106, 194))
            qp.drawRoundedRect(QRect(0, 0, 300, 300), 16, 8)
    
        def fade_in(self):
            self._animation.setDirection(QPropertyAnimation.Forward)
            self._animation.start()
    
        def fade_out(self):
            loop = QEventLoop()
            self._animation.finished.connect(loop.quit)
            self._animation.setDirection(QPropertyAnimation.Backward)
            self._animation.start()
            loop.exec_()
    
        def showEvent(self, event):
            super().showEvent(event)
            self.fade_in()
    
        def closeEvent(self, event):
            # fade out
            self.fade_out()
            super().closeEvent(event)
    
        def hideEvent(self, event):
            # fade out
            self.fade_out()
            super().hideEvent(event)
    
    
    if __name__ == "__main__":
        import sys
    
        app = QApplication(sys.argv)
        w = Widget()
        w.show()
        sys.exit(app.exec_())