Fade-Effects: a Blast from the Past

I must admit, I'm not the best blog writer out there. I always find it fun to read the new entries on than write a new one myself. I enjoy writing articles for Qt Quarterly more, then I have something that is crunchy and I can put it on a shelf and collect space. I suppose I could invest in a printer for the blog, but that seems like more work. Anyway, I found a topic here that follows up on a previous Qt Quarterly article of mine and updates it to more modern Qt technologies, all in a short enough space for a blog entry (I hope).

A couple years ago, I quickly wrote the article, Fading Effects with Qt 4.1. It outlined a fader widget which you could drop on top of another widget (like a QTabWidget or a QStackedWidget) and have a fade transition. It was a quick job that showed off the neat effects you can do when you have a backing store. Since I wrote that article, there were some things added to Qt 4.2 that make the thing even easier to use. So, I thought I would point them out in case you missed them. Download the source code from the original article and you can make changes at home.

Here's the header:
class FaderWidget : public QWidget
Q_PROPERTY(QBrush fadeBrush READ fadeBrush WRITE setFadeBrush)
Q_PROPERTY(int fadeDuration READ fadeDuration WRITE setFadeDuration)

FaderWidget(QWidget *parent);

QBrush fadeBrush() const { return startBrush; }
void setFadeBrush(const QBrush &newColor) { startBrush = newColor; }

int fadeDuration() const { return timeLine->duration(); }
void setFadeDuration(int milliseconds) { timeLine->setDuration(milliseconds); }

void start();

void paintEvent(QPaintEvent *event);

QTimeLine *timeLine;
QBrush startBrush;

You'll notice that we've eliminated some of the now needless variables and changed our QColor to a QBrush and our QTimer to a QTimeLine.

Now the changed parts of the source file, first the constructor:

FaderWidget::FaderWidget(QWidget *parent)
: QWidget(parent)
if (parent)
startBrush = parent->palette().window();
startBrush = Qt::white;

timeLine = new QTimeLine(333, this);
timeLine->setFrameRange(1000, 0);
connect(timeLine, SIGNAL(frameChanged(int)), this, SLOT(update()));


Here, we create our QTimeLine. QTimeLine is a class introduced in 4.2 that will take a time and a set number of frames and dish them out in regular intervals over that duration to make them appear animated. It helps keep animation constant, dropping frames if things end up getting behind and trying to ensure that an animation only lasts for the time alloted to it.
We set the time to be about a third of a second and give it a thousand frames to draw, starting at 1000 and ending at 0. Obviously, it won't be drawing all of them in this time frame. We tell the timeline's frameChanged() signal to trigger an update on the fader widget.

We also try to get the brush for the parent widget's window role. This is a change from before where we only got the color and not the brush, since we couldn't trivially alpha blend the an arbitrary pixmap in Qt 4.1.

void FaderWidget::start()

Start remains similar to before, except it only needs to start the timeline.

void FaderWidget::paintEvent(QPaintEvent * /* event */)
QPainter painter(this);
qreal frame = timeLine->currentFrame();
painter.setOpacity(frame / 1000.);
painter.fillRect(rect(), startBrush);

if (frame < = 0.)

Our paint event has probably changed the most (for the better). Instead of constantly calculating the new alpha color, we simply take the current frame of the timeline and divide it by our total frames, and use that as the opacity value for our QPainter. QPainter::setOpacity() was introduced in Qt 4.2 and sets the opacity for all drawing operations done with that painter. It's easier than ever to get alpha blending effects with QPainter::setOpacity(). Then we simply fill the entire widget with the brush we got at the beginning.

That's it! Feel free to make these changes to the code and see it in action. It will look much better than the previous version on platforms that have a pixmap for their window brush (like Mac OS X, XP, and Vista). I included a screen shot of a fade in action here below:

FaderWidget in action

Anyway, this is just an example with what you can do with Qt 4.2, not to mention 4.3. So, take a look at the classes like QTimeLine and new functions like QPainter::setOpacity(), see where you can use them in your existing apps to improve the user experience and make your maintenance easier.


Blog Topics: