d_stranz
28th October 2013, 22:30
Here's a summary of today's adventures in Qt5. Maybe this will be of some help to others.
I would like to implement a fade-in / fade-out feature for modal dialogs derived from QDialog. I did this for a QML-based modal Window and liked the effect, using a QML PropertyAnimation on the opacity property.
It should be possible to duplicate this behavior with QDialog using a QPropertyAnimation on the QWidget::windowOpacity property. I display the dialog using QDialog::exec().
I created two QPropertyAnimation instances, one for fade-in, one for fade-out as members of my dialog class.
I implemented the fade-in feature by overriding the showEvent() and starting the fade-in animation there. This works fine - the dialog slowly fades into view as expected.
I had trouble with the fade-out implementation. I tried overriding the hideEvent(), but this is too late. Qt has already hidden the window by the time this event occurs, so the fade out animation does nothing. I've also tried it in the closeEvent(), but this method is not called - hideEvent() is called instead. I assume that this is because my QDialog is not a top-level widget, but a child of the QMainWindow.
The hideEvent() also occurs before QDialog:exec() returns, so it can't be trapped there either without re-implementing that method.
So what I finally hit on was to override the QDialog::done() slot. I also added a new slot, onFadeOutFinished() and connected this to the QPropertyAnimation::finished() signal for the fade-out instance. In my done() slot, I start the fade-out animation, and in the finished() signal handler slot, I call the actual QDialog::done() slot.
The code looks like this:
FaderDialog::FaderDialog( QWidget * parent ) : QDialog( parent ), mResult( 0 )
{
// Create the fade-in / fade-out animators
mpFadeIn = new QPropertyAnimation( this, "windowOpacity" );
mpFadeIn->setDuration( 150 );
mpFadeIn->setStartValue( 0.0 );
mpFadeIn->setEndValue( 1.0 );
mpFadeOut = new QPropertyAnimation( this, "windowOpacity" );
mpFadeOut->setDuration( 500 );
mpFadeOut->setStartValue( 1.0 );
mpFadeOut->setEndValue( 0.0 );
connect( mpFadeOut, SIGNAL( finished() ), this, SLOT( onFadeOutFinished() ) );
}
void FaderDialog::showEvent( QShowEvent * )
{
mpFadeIn->start();
}
void FaderDialog::done( int result )
{
mResult = result; // remember the result in a member variable
mpFadeOut->start();
}
void FaderDialog::onFadeOutFinished()
{
QDialog::done( mResult ); // now call the real done() slot
}
There seems to be one glitch - the whole application "blinks" just as the fade-out animation starts. It seems that changing the opacity of the dialog causes a paint event in the parent. I will look into ways to counteract that. I think it is possible - if I do the same thing with a QML dialog, I don't think I see a blink.
I would like to implement a fade-in / fade-out feature for modal dialogs derived from QDialog. I did this for a QML-based modal Window and liked the effect, using a QML PropertyAnimation on the opacity property.
It should be possible to duplicate this behavior with QDialog using a QPropertyAnimation on the QWidget::windowOpacity property. I display the dialog using QDialog::exec().
I created two QPropertyAnimation instances, one for fade-in, one for fade-out as members of my dialog class.
I implemented the fade-in feature by overriding the showEvent() and starting the fade-in animation there. This works fine - the dialog slowly fades into view as expected.
I had trouble with the fade-out implementation. I tried overriding the hideEvent(), but this is too late. Qt has already hidden the window by the time this event occurs, so the fade out animation does nothing. I've also tried it in the closeEvent(), but this method is not called - hideEvent() is called instead. I assume that this is because my QDialog is not a top-level widget, but a child of the QMainWindow.
The hideEvent() also occurs before QDialog:exec() returns, so it can't be trapped there either without re-implementing that method.
So what I finally hit on was to override the QDialog::done() slot. I also added a new slot, onFadeOutFinished() and connected this to the QPropertyAnimation::finished() signal for the fade-out instance. In my done() slot, I start the fade-out animation, and in the finished() signal handler slot, I call the actual QDialog::done() slot.
The code looks like this:
FaderDialog::FaderDialog( QWidget * parent ) : QDialog( parent ), mResult( 0 )
{
// Create the fade-in / fade-out animators
mpFadeIn = new QPropertyAnimation( this, "windowOpacity" );
mpFadeIn->setDuration( 150 );
mpFadeIn->setStartValue( 0.0 );
mpFadeIn->setEndValue( 1.0 );
mpFadeOut = new QPropertyAnimation( this, "windowOpacity" );
mpFadeOut->setDuration( 500 );
mpFadeOut->setStartValue( 1.0 );
mpFadeOut->setEndValue( 0.0 );
connect( mpFadeOut, SIGNAL( finished() ), this, SLOT( onFadeOutFinished() ) );
}
void FaderDialog::showEvent( QShowEvent * )
{
mpFadeIn->start();
}
void FaderDialog::done( int result )
{
mResult = result; // remember the result in a member variable
mpFadeOut->start();
}
void FaderDialog::onFadeOutFinished()
{
QDialog::done( mResult ); // now call the real done() slot
}
There seems to be one glitch - the whole application "blinks" just as the fade-out animation starts. It seems that changing the opacity of the dialog causes a paint event in the parent. I will look into ways to counteract that. I think it is possible - if I do the same thing with a QML dialog, I don't think I see a blink.