Introduction
Why, you may well ask yourself, does the world
need another splash screen control? I have to
agree with such sentiment. I myself have found
hundreds, if not thousands of examples on the web,
many on this site, in every language
imaginable.
I have found a running theme in all cases
however. While some offer transparency, fading in
and out, status update, separate thread execution,
even an excellent example using a custom
ApplicationContext class, all of these have one
thing in common. Most of these splash screens are
initiated in the main form load of the
application, then closed once the form has
finished loading. The rest initiate before the
main form, and are closed before the main form
execution begins. None of them (that I have found)
cover the scenario of initiating before the main
Application thread and being disposed after the
Main form has fully loaded.
Background
A project I worked on recently included my early
attempts at this, using a separate thread and so
forth, however, I had a problem. As soon as the
Splash Screen closed the main form of the
application would go to the back of the z-order
behind any other open applications. This was
particularly annoying when launching the
application from the IDE.
We had, as I often do, good reason to run in this
manner as a whole range of classes had to be
discovered and dynamically loaded before the Main
Application Window could be launched. As a more
common requirement we wanted to display the splash
screen while authenticating against a web service.
If the user could not be automatically
authenticated the splash screen would be closed
and user credentials requested, or possibly
rejected, therefore closing the application
without ever going near the main application
window.
Explanation of the code
In the source code I have included two projects.
One in C# and the other in VB.NET, both compiled
on the .NET Framework 2.0 . I tried back porting
this control to 1.1 or 1.0, but certain tricks
just aren't there in 1.n of the framework. Things
like the fade out are not possible without a
message loop, at least not in the same manner, so
I have left this as a 2.0 framework-only solution.
For the purposes of this article I shall present
the code examples from the C# source code. The
VB.NET code is very similar, and you can find it
in the source code solution.
The important part, of either project, is the
Splash class. I suggest that the best way to use
this is to copy the entire Splash.cs or Splash.vb
into your project and work with it there, making
the appropriate Namespace changes. This is also
recommended as the entire splash screen code and
resources will then be loaded as part of your main
executable and no external assemblies will be
required.
Now for a short list of the main features, and
how I implemented them. I found some neat tricks
on the way.
Splash Image Transparency
This feature has been done ad nauseam so I'll be
brief. You use the forms designer to set the
BackgroundImage property of the Splash screen
class to the image you wish to display. This
should have a transparency colour set; it does not
matter what it is. At runtime the Splash screen
resizes to fit around your image and sets it's
TransparencyKey to it's BackgroundColor, thereby
rendering the form transparent, as demonstrated in
the source code, and in the picture above.
Splash Fading In
Now the fun begins, as this is a little tricky
without a message pump. I have exposed the class
as a singleton instance so that you can only show
one splash at a time, then we get down to
business. But first, a short explanation of what
this 'without a message pump' is all about.
At some point in your application you will find
the code - Application.Run(new MainForm()),
although this is generally hidden from VB.NET
programmers as the framework generates this for
you at compile time when you set the Startup form
for the Application. However, you will find an
example of this in VB.NET in the source code. This
code not only displays the main form of your
application, it also starts a message loop so that
Windows can send the application messages to
process mouse clicks, keyboard key presses, paint
events and so forth. More importantly, it also
starts up a message pump to read those messages of
the loop. Without this pump the messages would sit
on the message loop forever, and your application
would be totally unresponsive.
As I mentioned in the introduction,
authentication should be occurring before the
message pump starts. These are non GUI actions
that do not require any direct user interaction.
You just want to display the splash screen so the
users know something is happening. Technically you
are using a message pump, but all interaction with
it is manual via the Application.DoEvents()
method.
So you call the Show method on the Splash Form,
making it visible but not capturing the execution
thread. If we had used ShowDialog then .NET would
have started a message pump for us. This, however,
just displays a black rectangle on the screen. To
process the initial paint event you must call
Application.DoEvents() as shown below.
Code:
// Hide initially so as to avoid a nasty pre
paint flicker
Instance.Opacity = 0;
Instance.Show();
// Process the initial paint events
Application.DoEvents();
|
Now we take whatever value has been specified for
the fade in time (for example, 500 milliseconds)
and generate the time per fade step. I am using a
twenty-step fade to keep it smooth up to about
four seconds, which should be long enough for
anyone. This value is then stored for use later on
for the fade out. Passing a value of zero for the
fade in time will result in the splash displaying
and closing without a fade. A simple loop is now
used to increment the Opacity of the Splash
screen, using Thread.Sleep, until it is 100%
visible. We could not use a timer here because
that requires a message pump. Using this method of
fade works equally well if called from within the
main form of the application should you wish to
display it in that manner.
Code:
// Perform the fade in
if (fadeinTime > 0) {
// Set the timer interval so that we fade
out at the same speed.
int fadeStep =
(int)System.Math.Round((double)fadeinTime/20);
Instance.fadeTimer.Interval = fadeStep;
for (int i = 0; i
The problem with the z-order was caused by
running two message loops within the same
AppDomain. As soon as the AppDomain receives the
message loop exited message it deactivates the
Application sending it to the back of the z-order.
This is not normally a problem as this exited
message would indicate the application is closing,
but not in this case. Fortunately, this
implementation of a splash screen avoids this
problem by never starting a message loop for the
splash screen, but rather pumping the messages
manually.
Using the code
Calling the Splash screen is quite simple, once
you have set the background image.
To Display the Splash Screen
[code]
Splash.ShowSplash();
|
To Display the Splash Screen with a fade
in/out
Code:
Splash.ShowSplash(500);
|
For this method you specify the number of
milliseconds the splash should take to fade in or
out.
To Hide the Splash Screen
Please feel free to use this code in your own
applications, adapting it as you see fit. I will
appreciate any suggestions for improvements.
at http://www.lujosoft.net/Forum/
Happy coding