Wouldn't you like to be able to do all those things in Java? By using Swing with threads, you can!
Here is a first swing (no pun intended) at a class for a splash screen created for use in an application:
class SplashWindow1 extends JWindow
{
public SplashWindow1(String filename, Frame f)
{
super(f);
JLabel l = new JLabel(new ImageIcon(filename));
getContentPane().add(l, BorderLayout.CENTER);
pack();
Dimension screenSize =
Toolkit.getDefaultToolkit().getScreenSize();
Dimension labelSize = l.getPreferredSize();
setLocation(screenSize.width/2 - (labelSize.width/2),
screenSize.height/2 - (labelSize.height/2));
setVisible(true);
screenSize = null;
labelSize = null;
}
}
The SplashWindow1 class extends Swing's JWindow. JWindow is a heavyweight container. It also has none of the normal items that appear in other windows, such as a title bar, window
management buttons, or even a visible frame edge. Therefore, JWindow is perfect for a splash screen. The code above assumes an image file is located in the current directory. Once the image
is loaded by way of the ImageIcon, the image is placed in the center of the JWindow. The JWindow is packed to let Swing resize the window correctly, and then it is moved to the center of the screen and set visible. You
can find a similar version of that code in the reference material in Resources.
If you were to actually run the above code, you would unfortunately have a nicely centered splash screen that will not close! To make it close, you must add code:
class SplashWindow2 extends JWindow
{
public SplashWindow2(String filename, Frame f)
{
super(f);
JLabel l = new JLabel(new ImageIcon(filename));
getContentPane().add(l, BorderLayout.CENTER);
pack();
Dimension screenSize =
Toolkit.getDefaultToolkit().getScreenSize();
Dimension labelSize = l.getPreferredSize();
setLocation(screenSize.width/2 - (labelSize.width/2),
screenSize.height/2 - (labelSize.height/2));
addMouseListener(new MouseAdapter()
{
public void mousePressed(MouseEvent e)
{
setVisible(false);
dispose();
}
});
setVisible(true);
}
}
The only difference in that version of the SplashWindow class is that there is now an anonymous MouseListener installed on the JWindow. That will allow the user to click on the splash screen to make it disappear.
At that point, you will have a nice splash screen that can be removed but will not disappear on its own. You will then have to add code to remove the splash screen after a certain amount of time. Then you should be thinking threads. And if you've worked with Swing at all, you know that making threaded calls can be tricky at best. For reasons why and a more in-depth explanation of threads and Swing, see Resources.
class SplashWindow3 extends JWindow
{
public SplashWindow3(String filename, Frame f, int waitTime)
{
super(f);
JLabel l = new JLabel(new ImageIcon(filename));
getContentPane().add(l, BorderLayout.CENTER);
pack();
Dimension screenSize =
Toolkit.getDefaultToolkit().getScreenSize();
Dimension labelSize = l.getPreferredSize();
setLocation(screenSize.width/2 - (labelSize.width/2),
screenSize.height/2 - (labelSize.height/2));
addMouseListener(new MouseAdapter()
{
public void mousePressed(MouseEvent e)
{
setVisible(false);
dispose();
}
});
final int pause = waitTime;
final Runnable closerRunner = new Runnable()
{
public void run()
{
setVisible(false);
dispose();
}
};
Runnable waitRunner = new Runnable()
{
public void run()
{
try
{
Thread.sleep(pause);
SwingUtilities.invokeAndWait(closerRunner);
}
catch(Exception e)
{
e.printStackTrace();
// can catch InvocationTargetException
// can catch InterruptedException
}
}
};
setVisible(true);
Thread splashThread = new Thread(waitRunner, "SplashThread");
splashThread.start();
}
}
The general idea here is to first create a Thread object that will pause for a specific amount of time. In the above code, the thread will pause for four seconds. When that
thread wakes up, it will close the splash screen. Since Swing is not thread-safe, you should not affect the state of any UI
component unless the code is being executed on the event-dispatching thread. The event-dispatching thread is the thread that
handles drawing and event handling in Swing.
To get around that limitation, Swing designers gave the programmer the ability to add runnable objects to the UI event queue
in a safe manner. In this case, you are going to use the runnable object's closeRunner to do the dirty work. You pass the runnable object to the static method SwingUtilities.invokeAndWait(). Then SwingUtilities.invokeAndWait() will execute all pending UI activity and execute the run method on the runnable object closeRunner, which is passed to the method. By using a separate thread to handle the splash screen's closing, the application that is
displayed behind the splash screen is visible and responsive during the entire operation.
If you want a splash screen that is always visible and that the user cannot remove, you must remove the code that hides the
splash screen. If you want a splash screen that the user must close manually, you can call the setVisible(false) and dispose() methods on the SplashWindow3 object just like any other JWindow.
By using the SwingUtilities.invokeAndWait() method, you can safely create a multithreaded Swing splash screen. A user can click on the splash screen to remove it, or
the splash screen will disappear on its own after a set amount of time. The threading model that Swing supports will allow
the application to remain responsive and usable behind the splash screen.
Whirling splash screen?By Anonymous on October 31, 2008, 7:22 pmNice article thank you! I was wondering if we could create "whirling" splash screens like the one Google Picasa shows when it is started?
Reply | Read entire comment
View all comments