PDA

View Full Version : QGraphicsOpacityEffect and QLabel



hayzel
11th July 2014, 18:50
I want to animate error messages inside the status bar of my application.
I use a QLabel for the statusbar.

On status bar change i do the following:



void sectiona::statusBarChanged(const QString& text, bool message)
{
QLabel* b=m_gui->m_textOut;
QString newtext;
oldStatusBarText=b->text();
if(message==false)
{
b->setText(text);
return;
}else //animated message
{
newtext=text;
newtext=newtext.prepend("<font color=\"red\"><b>").append("</b></font>");
b->setText(newtext);
QGraphicsOpacityEffect* effect=new QGraphicsOpacityEffect(b);
b->setGraphicsEffect(effect);
QPropertyAnimation* animation=new QPropertyAnimation(effect,"opacity");
effect->setOpacity(0.0);
animation->setDuration(3000);
animation->setKeyValueAt(0.0,1.0);
animation->setKeyValueAt(0.9,1.0);
animation->setKeyValueAt(1.0,0.0);
animation->setEasingCurve(QEasingCurve::InOutCubic);
connect(animation,SIGNAL(finished()),this,SLOT(sta tusBarAnimationFinished()));
animation->start(QAbstractAnimation::DeleteWhenStopped);
};
}


if the new status bar is a temporary message I animate the fadeout for 3seconds and then on the finish of the animation I restore the permanent status bar text:



void sectiona::statusBarAnimationFinished()
{
QLabel* b=m_gui->m_textOut;
QGraphicsOpacityEffect* effect=new QGraphicsOpacityEffect(b);
effect->setOpacity(0.0);
qDebug()<<effect->opacity();
b->setText(oldStatusBarText);
qDebug()<<effect->opacity();
b->setGraphicsEffect(effect);
qDebug()<<effect->opacity();
b->setText(oldStatusBarText);
qDebug()<<effect->opacity();
effect->setOpacity(1.0);
qDebug()<<effect->opacity();
}


It works fine except a minor detail. The qDebug statements return:


0
0
0
0
1

, so the opacity changes only on the final statement, <b>BUT</b> the previous text blinks for a frame before setting the oldStatusBarText
I want to smoothly disappear the message, and the just update the QLabel with the previous text.
Any ideas?

d_stranz
11th July 2014, 19:32
Why do you think the opacity should change? You create a new effect in the statusBarAnimationFinished() slot, set the opacity to 0, then don't do anything with it except print its value until you finally set the value to 1 and print it again. The code is doing exactly what you've told it to do.

Are you confusing this effect instance with the effect instance that you create in the statusBarChanged() slot? The one you create in the statusBarAnimationFinished() slot is not the one you installed on the label in the statusBarChanged() slot, it's a new one. And in any case, by the time the statusBarAnimationFinished() slot is called, the original effect has an opacity of 1, because that's what you've told the animation to do and it doesn't emit its finished() signal until it's done doing it.

hayzel
11th July 2014, 20:00
It's difficult to explain the problem without seeing it.
Let me be more detailed:

1. statusBar text is "mode 1". in black
2. I emit an error message "Error 1" that is catched be statusBarChanged("Error 1", true)
3. I made a red bold message of "Error 1" and set it to statusBar.
4. Status bar is now "error 1" in red bold
5. I create a QGraphicsOpacityEffect with initial opacity 1.0 (setKeyValueAt(0.0,1.0)) and final opacity 0.0 (setKeyValueAt(1.0,0.0)).
6. I start the animation .
7. "error 1" in statusBar fades out to invisible (opacity 0.0 at 1.0time).
8. signal "finished()" is triggered and slot "statusBarAnimationFinished" is executed.
9. I change the text back to oldstatusBar "mode 1" checking all the time if opacity is still 0.0 invisible.
10. After settings the text back to "mode 1" I change the opacity back to 1.0 and check if the value has changed.

All the above logic and the opacity values I get are correct, but in the steps 8-10 I get the following behaviour:
"error 1" is invisible and is made visible again for one ugly frame, before "mode 1" is shown in statusBar. I want to know if there is a way to avoid this "opacity jump" in the logic of the above.

Is it more clear now ?

I think the problem is related to some standard effect animation inside QLabel setText change, and not in my code. But I cannot figure it out.

d_stranz
12th July 2014, 04:59
The instances of QGraphicsOpacityEffect in your two slots are unrelated, even though you are supplying the QLabel instance when you create them. In the statusBarAnimationFinished() slot, you never call b->setGraphicsEffect(effect); so the label is still using the old effect from the slot that starts the animation. This might account for the "ugly" behavior you are seeing. Changing the opacity of the new effect instance in the finished() slot does nothing because you haven't set it on the label instance. You're just changing the opacity of an effect that isn't hooked up to anything.

hayzel
12th July 2014, 10:19
Thanks for the correction. I added b->setGraphicsEffect(effect); on the slot you mentioned. But even If I set the oldtext on the status bar before it is shown, I see the "frame" with the "error 1" with full opacity before updating to oldtext. So I concluded that my kde, uses its own animations for changing text in qlabel and somehow it conflicts with my animation.
So I decided to drop the animation anyway, because it is to jumpy like that, and use a simple setText with a timer.