Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QGraphicsOpacityEffect on a QLabel
Forum Updated to NodeBB v4.3 + New Features

QGraphicsOpacityEffect on a QLabel

Scheduled Pinned Locked Moved General and Desktop
22 Posts 3 Posters 9.4k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • Chris KawaC Offline
    Chris KawaC Offline
    Chris Kawa
    Lifetime Qt Champion
    wrote on last edited by
    #2

    What if you need to fade something else? You're gonna copy/paste all of that? You should check out the "DRY rule":http://en.wikipedia.org/wiki/Don't_repeat_yourself

    Here's a potential implementation of this:
    EDIT: formatted to fit better
    @
    class Delay: public QObject {
    public:
    Delay(int duration) {
    QTimer::singleShot(duration, this, SLOT(deleteLater()));
    }
    };

    class Fader : public QObject {
    public:
    Fader(QWidget* target, double start, double end, int fade) {
    auto effect = new QGraphicsOpacityEffect(this);
    target->setGraphicsEffect(effect);

    auto anim = new QPropertyAnimation(effect, "opacity", this);
    connect(anim, &QPropertyAnimation::finished, this, &Fader::deleteLater);
    anim->setDuration(fade);
    anim->setStartValue(start);
    anim->setEndValue(end);
    anim->setEasingCurve(QEasingCurve::OutQuad);
    anim->start();
    

    }

    static void fadeInOut(QWidget* target, int fade, int pause) {
    connect(new Fader(target, 0.0, 1.0, fade), &Fader::destroyed, ={
    connect(new Delay(pause), &Delay::destroyed, ={
    connect(new Fader(target, 1.0, 0.0, fade), &Fader::destroyed, ={
    target->setVisible(false);
    });
    });
    });
    }
    };
    @
    You can of course extend that to have fadeIn, fadeOut and whatever else animation you might need.

    Now whenever you need to fade something you just do this:
    @
    Fader::fadeInOut(someWidget, 2000, 1000);
    @

    1 Reply Last reply
    0
    • M Offline
      M Offline
      maximus
      wrote on last edited by
      #3

      Wow this is exactly what I needed! your C++ skills are way better than mine. Never used the "auto keyword":http://en.cppreference.com/w/cpp/language/auto, will have to learn how to use it, better than a raw pointer right? Really clever use of signal and slot for auto memory management, thanks so much!

      @//----------------------------------------------------------------------------
      Fader::Fader(QWidget* target, double start, double end, int fadeTime) {

      auto effect = new QGraphicsOpacityEffect(this);
      target->setGraphicsEffect(effect);
      
      auto anim = new QPropertyAnimation(effect, "opacity", this);
      connect(anim, &QPropertyAnimation::finished, this, &Fader::deleteLater);
      anim->setDuration(fadeTime);
      anim->setStartValue(start);
      anim->setEndValue(end);
      anim->setEasingCurve(QEasingCurve::OutQuad);
      anim->start();
      

      }

      //----------------------------------------------------------------------------
      void Fader::fadeInOut(QWidget* target, int fadeInTime, int fadeOutTime, int pause) {

      connect(new Fader(target, 0.0, 1.0, fadeInTime), &Fader::destroyed, [=](){
          target->setVisible(true);
          connect(new Delay(pause), &Delay::destroyed, [=](){
              connect(new Fader(target, 1.0, 0.0, fadeOutTime), &Fader::destroyed, [=](){
                  target->setVisible(false);
              });
          });
      });
      

      }
      @


      Free Indoor Cycling Software - https://maximumtrainer.com

      1 Reply Last reply
      0
      • Chris KawaC Offline
        Chris KawaC Offline
        Chris Kawa
        Lifetime Qt Champion
        wrote on last edited by
        #4

        It's still a raw pointer. It just fits into a line on this forum :P

        auto is not a type or a smart pointer or anything like that. It's just a way to tell the compiler to figure out the type of expression. It's very useful for things like this:
        @std::vector<std::pair<std::vector<int>, std::vector<int>>>::const_iterator it1 = ...

        auto it2 = ...
        @
        it2 is still the same ugly long type. You just don't have to type it ;)

        1 Reply Last reply
        0
        • M Offline
          M Offline
          maximus
          wrote on last edited by
          #5

          Oh I get it,

          I think there is a small problem with a part of the code, if the *target pointer is deleted (user closed QDialog before animation was over) I will get a crash, still trying to figure a good solution to check if the pointer is still good or not,
          thanks

          @//----------------------------------------------------------------------------
          void Fader::fadeInAndOut(QWidget* target, int fadeInTime, int fadeOutTime, int pause) {

          qDebug() << "fadeInAndOut";
          target->setVisible(true);
          connect(new Fader(target, 0.0, 1.0, fadeInTime), &Fader::destroyed, [=](){
              connect(new Delay(pause), &Delay::destroyed, [=](){
                  connect(new Fader(target, 1.0, 0.0, fadeOutTime), &Fader::destroyed, [=](){
                      qDebug() << "fadeInAndOut2";
                      if( target != NULL){
                         target->setVisible(false);
                      }
                  });
              });
          });
          

          }@

          Edit: Problem is with the Fader constructor, it doesnt' check if *target is still valid before creating.. still investigating


          Free Indoor Cycling Software - https://maximumtrainer.com

          1 Reply Last reply
          0
          • Chris KawaC Offline
            Chris KawaC Offline
            Chris Kawa
            Lifetime Qt Champion
            wrote on last edited by
            #6

            If you need to keep an eye on the lifetime of a QObject use "QPointer":http://qt-project.org/doc/qt-5/qpointer.html. It automatically becomes null when the object is destroyed and you can check with isNull() before using it.

            1 Reply Last reply
            0
            • SGaistS Offline
              SGaistS Offline
              SGaist
              Lifetime Qt Champion
              wrote on last edited by
              #7

              Hi,

              Are you thinking about something like QPointer ?

              [edit: looks like I have some lag around here…]

              Interested in AI ? www.idiap.ch
              Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

              1 Reply Last reply
              0
              • M Offline
                M Offline
                maximus
                wrote on last edited by
                #8

                Thanks for the tip guys.

                I will check to use QPointer, first time using it so hopefully I get it right.

                For example, I could use a QPointer in the constructor instead of a QWidget*? Then check in the constructor if the QPointer is null before creating the animation.
                Will try and post if it's working good!

                @Fader::Fader(QPointer ptrWidget, double start, double end, int fadeTime)@


                Free Indoor Cycling Software - https://maximumtrainer.com

                1 Reply Last reply
                0
                • M Offline
                  M Offline
                  maximus
                  wrote on last edited by
                  #9

                  edited


                  Free Indoor Cycling Software - https://maximumtrainer.com

                  1 Reply Last reply
                  0
                  • SGaistS Offline
                    SGaistS Offline
                    SGaist
                    Lifetime Qt Champion
                    wrote on last edited by
                    #10

                    Rather than calling setVisible, why not connect the animation e.g. finished signal to the show/hide slot of your widget ?

                    Interested in AI ? www.idiap.ch
                    Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                    1 Reply Last reply
                    0
                    • M Offline
                      M Offline
                      maximus
                      wrote on last edited by
                      #11

                      [quote author="SGaist" date="1416875137"]Rather than calling setVisible, why not connect the animation e.g. finished signal to the show/hide slot of your widget ?[/quote]

                      I could do that, but the same problem can happen--, the slot Show() or Hide() from the QWidget could crash the program if the QWidget is no longer existing.
                      I find it hard to do a elegant solution, my original solution was okay and not crash prone even though it had a lot of copy and pasted code...

                      @class FadeObj: public QObject {
                      public:
                      FadeObj(QPointer<QWidget> target, double start, double end, int fadeTime) {

                          qDebug() << "NEW FADER!";
                          if (!target.isNull()) {
                              qDebug() << "widget still exist";
                          }
                          else {
                              qDebug() << "widget is now null! dont do it!";
                          }
                      
                          qDebug() << "BUG HERE";
                          auto effect = new QGraphicsOpacityEffect(target.data());
                          target.data()->setGraphicsEffect(effect);
                      
                      
                          auto anim = new QPropertyAnimation(effect, "opacity", this);
                          connect(anim, SIGNAL(finished()), target.data(), SLOT(show()));
                      

                      /// Could crash the program..
                      connect(anim, &QPropertyAnimation::finished, this, &FadeObj::deleteLater);
                      anim->setDuration(fadeTime);
                      anim->setStartValue(start);
                      anim->setEndValue(end);
                      anim->setEasingCurve(QEasingCurve::OutQuad);
                      anim->start();
                      }
                      };
                      @


                      Free Indoor Cycling Software - https://maximumtrainer.com

                      1 Reply Last reply
                      0
                      • M Offline
                        M Offline
                        maximus
                        wrote on last edited by
                        #12

                        edited


                        Free Indoor Cycling Software - https://maximumtrainer.com

                        1 Reply Last reply
                        0
                        • M Offline
                          M Offline
                          maximus
                          wrote on last edited by
                          #13

                          edited


                          Free Indoor Cycling Software - https://maximumtrainer.com

                          1 Reply Last reply
                          0
                          • M Offline
                            M Offline
                            maximus
                            wrote on last edited by
                            #14

                            I think I forgot about QObject parent property, since Fader is a subclass of QObject, I will pass a reference to the parent and the pointer should be taken care when the parentWidget is destroyed? will try.

                            @Fader::Fader(QWidget* parentAndTarget) : QObject( parentAndTarget ) {

                             //give target and parent to have auto memory management
                            this->widgetPtr = parentAndTarget;
                            

                            }@


                            Free Indoor Cycling Software - https://maximumtrainer.com

                            1 Reply Last reply
                            0
                            • M Offline
                              M Offline
                              maximus
                              wrote on last edited by
                              #15

                              Okay Version 3 is better:

                              Fader.h
                              @class Fader : public QObject
                              {
                              Q_OBJECT
                              public:
                              Fader(QWidget* parentTarget);
                              ~Fader();

                              void fadeIn(int fadeInTime);
                              void fadeOut(int fadeInTime);
                              
                              void fadeOutAfter(int fadeOutTime, int fadeAfter);
                              void fadeInAndOut(int fadeInTime, int fadeOutTime, int pause);
                              

                              private slots:
                              void animateFadeIn();
                              void animateFadeOut();

                              private :
                              QWidget *widget;

                              QTimer *timerSetVisible;
                              QTimer *timerFadeOut;
                              
                              int fadeOutTime;
                              int fadeInTime;
                              

                              };@

                              Fader.cpp
                              @Fader::Fader(QWidget* parentAndTarget) : QObject( parentAndTarget ) {

                              widget = parentAndTarget;
                              widget->setVisible(true);
                              

                              }

                              ///////////////////////////////////////////////////////////////////////////////
                              void Fader::fadeIn(int fadeInTime) {
                              this->fadeInTime = fadeInTime;
                              animateFadeIn();
                              }
                              void Fader::fadeOut(int fadeOutTime) {
                              this->fadeOutTime = fadeOutTime;
                              animateFadeOut();
                              }

                              //----------------------------------------------------------------------------
                              void Fader::fadeOutAfter(int fadeOutTime, int fadeAfter) {

                              timerFadeOut = new QTimer(this);
                              timerSetVisible = new QTimer(this);
                              timerFadeOut->setSingleShot(true);
                              timerSetVisible->setSingleShot(true);
                              
                              this->fadeOutTime = fadeOutTime;
                              
                              connect(timerFadeOut, SIGNAL(timeout()), this, SLOT(animateFadeOut()) );
                              connect(timerSetVisible, SIGNAL(timeout()), widget, SLOT(hide()) );
                              
                              timerFadeOut->start(fadeAfter);
                              timerSetVisible->start(fadeAfter + fadeOutTime);
                              

                              }

                              //----------------------------------------------------------------------------
                              void Fader::fadeInAndOut(int fadeInTime, int fadeOutTime, int pause) {

                              this->fadeInTime = fadeInTime;
                              animateFadeIn();
                              
                              timerFadeOut = new QTimer(this);
                              timerSetVisible = new QTimer(this);
                              timerFadeOut->setSingleShot(true);
                              timerSetVisible->setSingleShot(true);
                              
                              this->fadeOutTime = fadeOutTime;
                              
                              connect(timerFadeOut, SIGNAL(timeout()), this, SLOT(animateFadeOut()) );
                              connect(timerSetVisible, SIGNAL(timeout()), widget, SLOT(hide()) );
                              
                              timerFadeOut->start(fadeInTime + pause);
                              timerSetVisible->start(fadeInTime + fadeOutTime + pause);
                              

                              }

                              //---------------------------------------------------------------------------------
                              void Fader::animateFadeIn() {

                              qDebug() << "animateFadeIn";
                              
                              
                              QGraphicsOpacityEffect *effect = new QGraphicsOpacityEffect(widget);
                              QPropertyAnimation *anim = new QPropertyAnimation(widget);
                              widget->setGraphicsEffect(effect);
                              
                              anim->setPropertyName("opacity");
                              anim->setTargetObject(effect);
                              anim->setDuration(fadeInTime);
                              anim->setStartValue(0.0);
                              anim->setEndValue(1.0);
                              anim->setEasingCurve(QEasingCurve::OutQuad);
                              anim->start(QAbstractAnimation::DeleteWhenStopped);
                              

                              }
                              //---------------------------------------------------------------------------------
                              void Fader::animateFadeOut() {

                              qDebug() << "animateFadeOut";
                              
                              
                              QGraphicsOpacityEffect *effect = new QGraphicsOpacityEffect(widget);
                              QPropertyAnimation *anim = new QPropertyAnimation(widget);
                              widget->setGraphicsEffect(effect);
                              
                              anim->setPropertyName("opacity");
                              anim->setTargetObject(effect);
                              anim->setDuration(fadeOutTime);
                              anim->setStartValue(1.0);
                              anim->setEndValue(0.0);
                              anim->setEasingCurve(QEasingCurve::OutQuad);
                              anim->start(QAbstractAnimation::DeleteWhenStopped);
                              

                              }@


                              Free Indoor Cycling Software - https://maximumtrainer.com

                              1 Reply Last reply
                              0
                              • M Offline
                                M Offline
                                maximus
                                wrote on last edited by
                                #16

                                Just want to close the thread with what I chose.

                                After a lot of testing using the Fader class, it was working but not 100% like I wanted. I will go back to the old approach with many slots and QTimer inside the QDialog

                                Pro to old method:

                                • I can see if the widget is already being animated before setting a new animation on it (The Fader just blindly set a new animation, if there is still an active animation on the Widget it can cause weird animations and bad timing)
                                • Easier memory management

                                Cons:

                                • Lot of copied code, will try to put the common animation in a function to reuse code.

                                Thanks for your help


                                Free Indoor Cycling Software - https://maximumtrainer.com

                                1 Reply Last reply
                                0
                                • M Offline
                                  M Offline
                                  maximus
                                  wrote on last edited by
                                  #17

                                  Solution found inside FancyTab! (credit to QtCreator source code)

                                  Keep a reference to QPropertyAnimation, stop the current animation every time a new one is received before activating new one, brillant!

                                  @#ifndef FANCYTAB_H
                                  #define FANCYTAB_H

                                  #include <QIcon>
                                  #include <QWidget>

                                  #include <QPropertyAnimation>

                                  class FancyTab : public QObject
                                  {
                                  Q_OBJECT

                                  Q_PROPERTY(float fader READ fader WRITE setFader)
                                  

                                  public:
                                  FancyTab(QWidget *tabbar) : enabled(false), mTabBar(tabbar), mFader(0)
                                  {
                                  mAnimator.setPropertyName("fader");
                                  mAnimator.setTargetObject(this);
                                  }

                                  float fader() { return mFader; }
                                  void setFader(float value);
                                  
                                  void fadeIn();
                                  void fadeOut();
                                  
                                  QIcon icon;
                                  QString text;
                                  QString toolTip;
                                  bool enabled;
                                  

                                  private:
                                  QPropertyAnimation mAnimator;
                                  QWidget *mTabBar;
                                  float mFader;
                                  };

                                  #endif // FANCYTAB_H@


                                  Free Indoor Cycling Software - https://maximumtrainer.com

                                  1 Reply Last reply
                                  0
                                  • M Offline
                                    M Offline
                                    maximus
                                    wrote on last edited by
                                    #18

                                    Okay here is a complete working solution (add it to Qt? :P)
                                    Only wish I subclassed QWidget instead of QLabel, as I need this for other QWidget also

                                    FaderLabel
                                    @#include <QLabel>
                                    #include <QTimer>
                                    #include <QPropertyAnimation>
                                    #include <QGraphicsOpacityEffect>

                                    class FaderLabel : public QLabel
                                    {
                                    Q_OBJECT

                                    public:
                                    explicit FaderLabel(QWidget *parent = 0);

                                    void fadeIn(int durationMs);
                                    void fadeOut(int durationMs);
                                    
                                    void fadeOutAfterPause(int fadeDuration, int pause);
                                    void fadeInAndFadeOutAfterPause(int fadeInDuration, int fadeOutDuration, int pause);
                                    

                                    private slots: //Used to connect with timer

                                    void fadeInAfterTimer();
                                    void fadeOutAfterTimer();
                                    

                                    private :
                                    QTimer *timerAnimatorFadeOut;
                                    QTimer *timerAnimatorFadeIn;

                                    QGraphicsOpacityEffect *effect;
                                    QPropertyAnimation *anim;
                                    
                                    int tmpDurationFadeOut;
                                    int tmpDurationFadeIn;
                                    

                                    };

                                    #endif // FADERLABEL_H@

                                    FaderLabel.cpp
                                    @#include "faderlabel.h"

                                    #include <QDebug>

                                    FaderLabel::FaderLabel(QWidget *parent) :
                                    QLabel(parent)
                                    {

                                    timerAnimatorFadeOut = new QTimer(this);
                                    timerAnimatorFadeOut->setSingleShot(true);
                                    timerAnimatorFadeIn = new QTimer(this);
                                    timerAnimatorFadeIn->setSingleShot(true);
                                    
                                    connect(timerAnimatorFadeOut, SIGNAL(timeout()), this, SLOT(fadeOutAfterTimer()) );
                                    connect(timerAnimatorFadeIn, SIGNAL(timeout()), this, SLOT(fadeInAfterTimer()) );
                                    
                                    
                                    effect = new QGraphicsOpacityEffect(this);
                                    this->setGraphicsEffect(effect);
                                    anim = new QPropertyAnimation(effect, "opacity", this);
                                    
                                    
                                    tmpDurationFadeOut = 0;
                                    tmpDurationFadeIn = 0;
                                    

                                    }

                                    //---------------------------------------------------
                                    void FaderLabel::fadeInAfterTimer() {

                                    fadeIn(this->tmpDurationFadeIn);
                                    

                                    }
                                    void FaderLabel::fadeOutAfterTimer() {

                                    fadeOut(this->tmpDurationFadeOut);
                                    

                                    }

                                    //---------------------------------------------------------------------------------
                                    void FaderLabel::fadeIn(int durationMs) {

                                    qDebug() << "animateFadeIn FaderLabel" << durationMs;
                                    anim->stop();
                                    anim->setDuration(durationMs);
                                    anim->setStartValue(0);
                                    anim->setEndValue(1);
                                    anim->setEasingCurve(QEasingCurve::OutQuad);
                                    anim->start();
                                    

                                    }

                                    //---------------------------------------------------------------------------------
                                    void FaderLabel::fadeOut(int durationMs) {

                                    qDebug() << "animateFadeout FaderLabel" << durationMs;
                                    anim->stop();
                                    anim->setDuration(durationMs);
                                    anim->setStartValue(1);
                                    anim->setEndValue(0);
                                    anim->setEasingCurve(QEasingCurve::OutQuad);
                                    anim->start();
                                    

                                    }

                                    //--------------------------------------------------------------------------------
                                    void FaderLabel::fadeOutAfterPause(int fadeDuration, int pause) {

                                    this->tmpDurationFadeOut = fadeDuration;
                                    timerAnimatorFadeOut->start(pause);
                                    

                                    }

                                    //-------------------------------------------------------------------------------------------------
                                    void FaderLabel::fadeInAndFadeOutAfterPause(int fadeInDuration, int fadeOutDuration, int pause) {

                                    fadeIn(fadeInDuration);
                                    
                                    this->tmpDurationFadeOut = fadeOutDuration;
                                    timerAnimatorFadeOut->start(pause);
                                    

                                    }
                                    @


                                    Free Indoor Cycling Software - https://maximumtrainer.com

                                    1 Reply Last reply
                                    0
                                    • M Offline
                                      M Offline
                                      maximus
                                      wrote on last edited by
                                      #19

                                      I ended up creating a "FaderWidget", "FaderFrame" and "FaderLabel"

                                      since QFrame and QLabel are childrens of QWidet, would it be possible to just code "FaderWidget" and make them inherit "FaderWidget"? Or do I have to edit Qt code?

                                      Thanks!


                                      Free Indoor Cycling Software - https://maximumtrainer.com

                                      1 Reply Last reply
                                      0
                                      • Chris KawaC Offline
                                        Chris KawaC Offline
                                        Chris Kawa
                                        Lifetime Qt Champion
                                        wrote on last edited by
                                        #20

                                        For whatever reason i stopped receiving notifications for this thread... :/

                                        I think creating this sort of class for each possible widget is cumbersome and it's back to copy/pasting which is no good. You want something that just takes (any) widget and animates it without intruding into that class code. And you want to write it only once.

                                        A little tweak to my original proposal using QPointer to take care of that releasing problem:
                                        @
                                        class Delay: public QObject {
                                        public:
                                        Delay(int duration) {
                                        QTimer::singleShot(duration, this, SLOT(deleteLater()));
                                        }
                                        };

                                        class Fader : public QObject {
                                        public:
                                        Fader(QWidget* target, double start, double end, int fade) {
                                        auto effect = new QGraphicsOpacityEffect(this);
                                        target->setGraphicsEffect(effect);

                                        auto anim = new QPropertyAnimation(effect, "opacity", this);
                                        connect(anim, &QPropertyAnimation::finished, this, &Fader::deleteLater);
                                        anim->setDuration(fade);
                                        anim->setStartValue(start);
                                        anim->setEndValue(end);
                                        anim->setEasingCurve(QEasingCurve::OutQuad);
                                        anim->start();
                                        

                                        }

                                        static void fadeInOut(QWidget* target, int fade, int pause) {
                                        QPointer<QWidget> p(target);
                                        if(p)connect(new Fader(target, 0.0, 1.0, fade),&Fader::destroyed,={
                                        if(p)connect(new Delay(pause), &Delay::destroyed, ={
                                        if(p)connect(new Fader(target,1.0,0.0,fade),&Fader::destroyed,={
                                        if(p)target->setVisible(false);
                                        });
                                        });
                                        });
                                        }
                                        };
                                        @

                                        1 Reply Last reply
                                        0
                                        • M Offline
                                          M Offline
                                          maximus
                                          wrote on last edited by
                                          #21

                                          Hey Chris thanks for your message!

                                          I know the oriented style design is not the best in this case, but I need to have control over the fade effect (stop effect, resume,.. ) because it is tied with user interactions. Also with my lack of C++ programming experience, I'm no good to adapt your solution and it''s more "crash-prone" in my case..

                                          Thanks for your help!
                                          Max


                                          Free Indoor Cycling Software - https://maximumtrainer.com

                                          1 Reply Last reply
                                          0

                                          • Login

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • Users
                                          • Groups
                                          • Search
                                          • Get Qt Extensions
                                          • Unsolved