Solved Animating QWidget opacity property(fade in ,fade out effect)
-
hello, lost about 2 hours trying to animate QWidget. The animation consists of these parts:
- 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!
- change opacity from 0 to 1.
-
you set
wdgt->setGraphicsEffect(show_effect);
no other will apply to the widgetdo 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 animation3you 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!