by Trenton Schulz
Most large applications use splash screens to provide feedback to the user, and as advertising space. Despite appearing to be a simple graphical hack, there are some issues to consider when adding a splash screen so that you don't put people off using your program.
Update: Qt now has a QSplashScreen class built-in.
Swim Gear |
Most splash screens consist of a graphic that is shown for a few moments before the main window makes its appearance. Here's the header for an example splash screen class:
#ifndef SPLASHSCREEN_H #define SPLASHSCREEN_H #include <qpixmap.h> #include <qwidget.h> class SplashScreen : public QWidget { public: SplashScreen( const QPixmap &pixmap ); void setStatus( const QString &message, int alignment = AlignLeft, const QColor &color = black ); void finish( QWidget *mainWin ); void repaint(); protected: void mousePressEvent( QMouseEvent * ); private: QPixmap pix; }; #endif
Testing the Water |
The SplashScreen class makes it easy to create a simple splash screen that shows itself after creation and closes itself just before the main window appears. For example:
int main( int argc, char **argv ) { QApplication app( argc, argv ); QPixmap pixmap( "splash.png" ); SplashScreen *splash = new SplashScreen( pixmap ); QMainWindow *mainWin = new QMainWindow; ... app.setMainWidget( mainWin ); mainWin->show(); splash->finish( mainWin ); delete splash; return app.exec(); }
Snorkeling |
Now that we have seen how to use the SplashScreen class, let's look under the hood to see how it works. A splash screen differs from an ordinary widget in many respects.
#include <qapplication.h> #include <qpainter.h> #include <qpixmap.h> #include "splashscreen.h" SplashScreen::SplashScreen( const QPixmap &pixmap ) : QWidget( 0, 0, WStyle_Customize | WStyle_Splash ), pix( pixmap ) { setErasePixmap( pix ); resize( pix.size() ); QRect scr = QApplication::desktop()->screenGeometry(); move( scr.center() - rect().center() ); show(); repaint(); }
In the body of the constructor, we set the widget's "erase pixmap." The erase pixmap is used to clear the widget before it is (potentially) painted on. Although the widget is constructed with WStyle_StaysOnTop, it's still possible to put another window on top of it (for example, by pressing Alt+Tab), and when that window goes away, the widget needs to repaint itself. The remainder of the constructor code adjusts the size of the widget, centers it on the screen, calls show(), and then calls repaint().
void SplashScreen::repaint() { QWidget::repaint(); QApplication::flush(); }
In our example main(), there was also a call to the SplashScreen::finish() function. This function is not very pretty and reveals some of the issues that library writers face when implementing a multiplatform toolkit:
#if defined(Q_WS_X11) void qt_wait_for_window_manager( QWidget *widget ); #endif void SplashScreen::finish( QWidget *mainWin ) { #if defined(Q_WS_X11) qt_wait_for_window_manager( mainWin ); #endif close(); }
Taking the Plunge |
Now, with the addition of some artwork, we are able to present simple splash screens to our users. But we can go further than this, and create splash screens that are both more informative and more responsive to the user. Browsing through the demo example's main() function in main.cpp, you will find this comment:
// How about a splash screen?
So, let's add one. But instead of just displaying a simple splash screen, let's try to inform our users about what is happening during the initialization process. Also, if the process takes too long (e.g. on slow machines) it would be nice to get rid of the splash screen before the application has been loaded. We'll look at how to do both these things.
First we will look at the setStatus() method that we put in the splash screen class. This function paints text onto the image using the message, alignment, and color that are passed in to it.
void SplashScreen::setStatus( const QString &message, int alignment, const QColor &color ) { QPixmap textPix = pix; QPainter painter( &textPix, this ); painter.setPen( color ); QRect r = rect(); r.setRect( r.x() + 10, r.y() + 10, r.width() - 20, r.height() - 20 ); painter.drawText( r, alignment, message ); setErasePixmap( textPix ); repaint(); }
Some users don't like splash screens, and for them we could easily implement a -nosplash command-line option. Alternatively, we can make the splash screen disappear when the user clicks it. Achieving this appears to be straightforward:
void SplashScreen::mousePressEvent( QMouseEvent * ) { hide(); }
Here's a snippet based on the demo example's main() function, with the irrelevant parts removed:
int main( int argc, char **argv ) { QApplication app( argc, argv ); ... /* + */ QPixmap pixmap( "splash.png" ); /* + */ SplashScreen *splash = new SplashScreen( pixmap ); /* + */ splash->setFont( QFont("Times", 10, QFont::Bold) ); /* + */ splash->setStatus( "Initializing..." ); /* + */ app.processEvents(); Frame frame; /* + */ splash->setStatus( "Creating Widgets Page..." ); ... /* + */ app.processEvents(); /* + */ splash->setStatus( "Creating Database Page..." ); ... /* + */ app.processEvents(); ... // etc. ... /* + */ splash->setStatus( "Creating Games Page..." ); ... /* + */ app.processEvents(); if ( !category.isEmpty() ) frame.setCurrentCategory( category ); app.setMainWidget( &frame ); frame.show(); /* + */ splash->finish( &frame ); /* + */ delete splash; return app.exec(); }
With these changes (indicated by +), the user gets feedback about what is going on while the demo is loading, and they can also hide the splash screen, if they want.
Developers looking for a splash screen solution are encouraged to try the class described here. Your feedback is especially welcome since we hope to add a splash screen class with similar functionality to Qt 3.2.
Copyright © 2002 Trolltech. | Trademarks |