Animating QWidget opacity property(fade in ,fade out effect)



  • hello, lost about 2 hours trying to animate QWidget. The animation consists of these parts:

    1. change opacity from 0 to 1.
      2.1 secong holding opacity with 1 value
      3.change opacity from 1 to 0.

    i've tried this code:

        int duration_ms=500;
        QWidget *wdgt = new QWidget();
        wdgt->setStyleSheet("background-color:#F0F8FF");
        wdgt->resize(QSize(200,100));
    
        wdgt->setWindowFlags(Qt::Tool |
                             Qt::FramelessWindowHint |
                             Qt::WindowSystemMenuHint |
                             Qt::WindowStaysOnTopHint);
    
        //opacity from 0 to 1
        QGraphicsOpacityEffect * show_effect = new QGraphicsOpacityEffect(wdgt);
        QPropertyAnimation* animation = new QPropertyAnimation(show_effect, "opacity");
        wdgt->setGraphicsEffect(show_effect);
        animation->setStartValue(0);
        animation->setEndValue(1);
        animation->setDuration(duration_ms);
    
        //do nothing for 1 sec
        QGraphicsOpacityEffect * no_effect = new QGraphicsOpacityEffect(wdgt);
        QPropertyAnimation* animation2 = new QPropertyAnimation(no_effect, "opacity");
        wdgt->setGraphicsEffect(show_effect);
        animation2->setStartValue(0);
        animation2->setEndValue(1);
        animation2->setDuration(duration_ms);
    
        //opacity from 1 to 0
        QGraphicsOpacityEffect * hiding_effect = new QGraphicsOpacityEffect(wdgt);
        QPropertyAnimation* animation3 = new QPropertyAnimation(hiding_effect, "opacity");
        wdgt->setGraphicsEffect(show_effect);
        animation3->setStartValue(1);
        animation3->setEndValue(0);
        animation3->setDuration(duration_ms);
    
        QSequentialAnimationGroup *group=new QSequentialAnimationGroup();
        group->addAnimation(animation);
        group->addAnimation(animation2);
        group->addAnimation(animation3);
    
        group->start();
        wdgt->show();
    

    First appears black rectangle then the widget changes it's background color according to the background i set in stylesheet. After that nothing happens. Could you please advise another possible approach or am i missing something? Glad to hear any advice, thanks in advance!



  • you set wdgt->setGraphicsEffect(show_effect); no other will apply to the widget

    do not use QSequentialAnimationGroup, remove the //do nothing for 1 sec block. start the first one on finished() signal for the first start a timer for the "do nothing" period, when the timer times out call wdgt->setGraphicsEffect(hiding_effect); and start animation3

    you might also want to set the animation easing curve to linear



  • i got your point, thanks for the detailed answer. The problem is that how the animation looks: first appears black rectangle, than it becomes blue(as i set in stylesheet), and then the opacity starts to grow. Why the black rectangle appears? Is there maybe another approach? for example, invoking qml from qt widget? Thanks in advance.



  • there is QQuickWidget for this purpose. However it seems the class working only with qt quick 2.0.



  • Hi.

    You don't need QGraphicsOpacityEffect. You just need a only one QPropertyAnimation in your case.

    You should do something like this:

    QPropertyAnimation* animation = new QPropertyAnimation(wdgt, "windowOpacity");
    animation->setStartValue(0);
    animation->setEndValue(1);
    animation->setDuration(duration_ms);
    
    connect(animation, &QPropertyAnimation::finished, [animation](){
        if (animation->direction() == QAbstractAnimation::Forward) {
            animation->setDirection(QAbstractAnimation::Backward);
            QTimer::singleShot(1000, [animation]{ animation->start(); });
        }
    });
    
    wdgt->show();
    animation->start();
    


  • okay the solution is to animate qml and display in a QDeclarativeView
    (if you are on qt quick 1.1).
    like this:
    QDeclarativeView *view = new QDeclarativeView;
    view->setSource(QUrl::fromLocalFile);//your path here
    view->show();



  • here is the complete example :

    c++ code

       QDeclarativeView *view = new QDeclarativeView;
        view->setSource((QUrl("qrc:/qml/content/Message.qml")));
        view->setWindowFlags(Qt::FramelessWindowHint
                            |Qt::WindowSystemMenuHint);
        view->setAttribute(Qt::WA_TranslucentBackground);
        view->show();
        QGraphicsObject *obj = view->rootObject();
        QObject::connect(this, SIGNAL(message(QVariant, QVariant)),
                         obj, SLOT(showMessage(QVariant, QVariant)));
        emit message(QString("Success!"), "qrc:/icons/yeeh.png");
    

    Message.qml

    import QtQuick 1.1
    Rectangle {
    
        function showMessage(msg, img) {
            messageTimer.interval = 3000
            dataText.text = msg;
            msg_img.source = img;
            anim_open.start();
            messageTimer.start();
        }
    
        id: message
        width: 200
        height: 30
        color: "lightgrey"
        opacity: 0
        radius: 5
        smooth: true
        Image {
            id: msg_img
            x: 5; y: 5
            width: 40; height: 40
        }
    
        Text {
            id: dataText
            anchors.fill: parent
            font.pointSize: 10
            wrapMode: Text.WordWrap
            clip: true
            horizontalAlignment: Text.AlignHCenter
            verticalAlignment: Text.AlignVCenter
        }
    
        ParallelAnimation {
            id: anim_open
            NumberAnimation { target: message; property: "height";  to: 50;  duration: 300 }
            NumberAnimation { target: message; property: "opacity"; to: 0.8; duration: 200 }
        }
    
        ParallelAnimation {
            id: anim_close
            NumberAnimation { target: message; property: "height";  to: 30; duration: 300 }
            NumberAnimation { target: message; property: "opacity"; to: 0;  duration: 200 }
            onCompleted: {dataText.text = ""}
        }
    
        MouseArea {
            anchors.fill: parent
            onClicked: anim_close.start()
        }
    
        Timer {
            id: messageTimer
            interval: 3000;
            repeat: false
            onTriggered: { anim_close.start() }
        }
    }
    


  • I would not introduce a Qt Quick dependency just for something this trivial...



  • maybe you right, but i failed to animate the QWidget properly, it appears first black on screen and then turns the color i set via stylesheet, which is pretty ugly.



  • @Devopia53 you method is perfect, thank you!


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.