NetBeans 6 delivers great updates to the Matisse GUI builder. Spend a few minutes with Roman Strobl and get an expert briefing on what's new and what has changed. (sponsored)
In this, the third and final installation of Andres' Introduction to Groovy series, you learn about how Groovy handles variable numbers of arguments, named parameters, currying, and more about Groovy operators. Including, some new operators.
Swing Fuse (actually just Fuse), is a framework designed to make it easier to create your own custom desktop components. In this article, Daniel Spiewak shows you how to get started and provides sample source code you can download.
Willam Louth shows how he uses JXInsight Probes to investigate probable performance issues with code bases that he is not familiar with. He also highlights possible pitfalls in creating a benchmark, as well as in the analysis of results.
There are many articles about doing Splash Screens in Java. Not
all of them take performance seriously. This one does.
A splash screen is an image being shown on screen while an
application is starting up. This article discusses how to create a splash screen
that is shown
very
early in the process of starting a Java application.
To achieve this we minimize the number of API classes needed to display the
splash screen and we carefully avoid resource contention by the threads running
in the JVM.
1. The Problem
Java applications often have very long initialization
times. I am assuming, that we have already tried our best to reduce the start
up latency of our application. But sometimes we reach a hard limit that we
cannot undercut. It takes a while until our application is ready, and there
is nothing we can do about it.
A splash screen is a means to provide feedback to the
user, telling that our application is starting up, and it also is a way to
advertise our product.
At first glance, implementing a splash screen seems
to be straightforward. The Swing API provides a rich set of classes to do this.
Simply create a JWindow, put a JLabel with an ImageIcon on it, put the current
Thread to sleep for 3 seconds and then continue loading the application...
Unfortunately with such
a naïve approach we not
only end up increasing the start up latency of our application by the 3 seconds
sleep time, we also happen to 'achieve' that our splash screen shows up late
in the initialization process of our application. And if the splash screen
shows up late, it does not fulfil its job.
When we design a splash screen we have to take account
of the following:
Class resolution.
Before the Java
Virtual Machine (JVM) can use a class, it has to load and initialize all
other classes that are referenced by this class. Without special measures
taken, this may delay the splash screen a considerable amount
of time.
Size of API's.
Displaying "Hello
World" using Swing involves the loading of roughly 800 API classes into
the JVM. Doing the same using AWT only takes about 600 API classes. The less
API classes we use for our splash screen, the shorter will be its start up
latency.
Limited Resources.
Displaying a
splash screen is a CPU intensive task. We do not want the application initialization
code to contend with the splash screen code over CPU resources.
Clean design.
We want to keep the
splash screen code separate from the initialisation code of our application.
This enables us to test it separately, and to add or remove it to our liking
without having to do much code changing.
2. Design Proposal
The proposed design consists of three classes: MyApplication,
Splasher and SplashWindow. The diagram below outlines the classes and their
collaboration.
MyApplication is our application class. SplashWindow contains all code required
to do the fast splash screen. Class Splasher is the new entry point for MyApplication.
The numbers show the sequence of the method invocations.
3. Class MyApplication
MyApplication is our application class. It contains
the long running initialisation code. To achieve a clear design, we keep this
class free from our splash screen code. The only concession that we require
is, that its main method must return once the application is up and running.
Here is an outline of the code of MyApplication.java.
public class MyApplication {
public static void main(String[]
args) {
/* Start the
application and return when it is ready to use. */
//...program code creating a
JFrame with a ‘Hello World’
//
message omitted...
}
}
Please note that we can launch the application
without
a splash screen
by directly invoking the main method of this class. This is useful for testing
and debugging.
Now let's see how to add a splash screen to this class.
4. Class Splasher
Splasher is our bootstrap class. Its purpose is to separate
the splash screen code from the application class code, and to keep class SplashWindow
maintenance free. Class Splasher consists of a main method only, which does
three things:
Open the splash window
Invoke the main method of class MyApplication
Close the splash window when the main method of MyApplication returns
Please note that we want to keep this class as small
as possible. The size of this class and of the of classes referenced by this
class directly influence the startup latency of our splash screen.
public class Splasher {
public static void main(String[]
args) {
SplashWindow.splash(Splasher.class.getResource("splash.gif" ));
SplashWindow.invokeMain("MyApplication",
args);
SplashWindow.disposeSplash();
}
}
As you can see, this class consists only of code that
delegates tasks to the SplashWindow class.
In fact, we could have moved all the code of this class
into class SplashWindow. Why haven't I done so? Class Splasher contains all
the code that needs to be changed per application. That is, for each application
we will be using another splash image, and the class name of the application
will also be different. This keeps class SplashWindow free from application
specific changes. It can be reused over and over again, without ever having
to touch its code.
Also note, that we could have put all three method calls
into a single call. But keeping each step of the initialization procedure separate,
makes the procedure easier to understand.
5. Class SplashWindow
Now lets take a look at class SplashWindow. This class
and its interaction with the other two classes are the meat of this article.
I will show only the essential portions of this class,
the full listing is available in the attachment.
5.1 Method invokeMain()
First lets take a look at method invokeMain(). Here
we invoke the main() method of our application using, er, clumsy Reflection
code.
public static void invokeMain(String className, String[]
args) {
try {
Class.forName(className)
.getMethod("main",
new Class[]
{String[].class})
.invoke(null,
new Object[]
{args});
} catch (Exception e) {
InternalError error =
new
InternalError("Failed
to invoke main method" );
error.initCause(e);
throw error;
}
}
Today, most Java VM's lazily resolve and verify classes.
At one time, on Mac OS X 10.1, we had the case of an eagerly resolving Java
VM. Without using Reflection, the main method of class Splasher was only executed,
after the Java VM had resolved all dependencies between the Splasher class,
the rest of the application and of all API classes used by the application.
Reflection is a means to dynamically write code at
runtime. Therefore, the dependency between our splash screen code and the application
code will only be revealed to the Java VM, when the Class.forName() method
is executed. Since class Splasher invokes method invokeMain() after it has
invoked method splash(), the splash screen will be shown to the user, before
such a resolution process can take place.
Reflection does not prevent though, that the Java VM
loads all files of a JAR file and of dependent JAR files into memory before
executing our code. If JAR file loading is a restricting performance factor
(e.g. because we load them over a slow network connection), we may want to
put the Splasher class and the SplashWindow together with the splash image
into a separate JAR file. In the manifest of the JAR file, we do not specify
a dependency to the application JAR files. Instead, we change the invokeMain()
method, to have it use an URLClassLoader to load the JAR files containing the
application.
5.2 Method splash()
Now, lets tackle method splash().
public static void splash(URL imageURL) {
if (imageURL != null)
{
splash(Toolkit.getDefaultToolkit().createImage(imageURL));
}
}
private static SplashWindow instance;
public static void splash(Image image) {
if (instance == null && image
!= null) {
Frame f = new Frame();
instance = new SplashWindow(f,
image);
instance.show();
if (! EventQueue.isDispatchThread()
&& Runtime.getRuntime().availableProcessors()
== 1) {
synchronized
(instance) {
while
(! instance.paintCalled) {
try
{
instance.wait();
}
catch (InterruptedException
e) {}
}
}
}
}
}
You may have noticed, that there are two splash methods:
one that creates the image from the URL, and one that works with the SplashWindow
instance. This is just because I like to keep methods short and simple.
In the first splash() method
we use the AWT Toolkit class to create the image. We use this method instead
of the new Image IO API, because it does not immediately load the image using
the current thread. We will initiate image loading in the AWT Event Dispatcher
thread later. I will come back to this topic further
below
in
this article.
In the
second splash() method, you see that an instance of the SplashWindow is created
(class SplashWindow is a subclass of java.awt.Window). Then, the instance is
shown. And then, we wait in a synchronized block until the paint method of
the instance has been called.
The last two steps are worth to be looked at closely.
Showing the SplashWindow, starts the AWT Event Dispatcher thread, which is
going to call the paint method of the SplashWindow. We wait in the synchronized
block until the painting has happened.
Why is there an if-statement which guards the synchronized
block?
We must not wait, if method splash() is called from
the AWT Event Dispatcher thread. This would cause a live lock, which would
hang our application. This check appears to be overkill, because we are calling
this method from the Main thread anyway. I have added it, because I sometimes
use the SplashWindow to display the about box of my application, and then I
don't want to care on which thread I am calling this method.
The check for the number of available processors is
more interesting.
On a single processor machine,
if we wouldn't wait here, and instead proceed with our start up process,
we would compete for the CPU
with the AWT Event Dispatcher thread. Since the AWT Event Dispatcher thread
has not yet started, we are likely to win the competition, or – in this
case – actually hog the CPU, and therefore significantly delay the splash
screen. In the worst case, the splash screen would not be shown at all.
On a multiple processor machine, we have a chance, that
both threads will get a CPU of their own. In this case, we have an opportunity
to maximize resource usage. Of course, it all depends on how independent the
two threads are with respect to other resources they are using. Thus, on a
multiprocessor machine, we take a small risk of delaying the splash screen
by a little bit. In return for the risk, we get better overall performance.
5.3 The constructor
The constructor of class SplashWindow makes the object
ready for later usage.
public class SplashWindow extends Window
{
private SplashWindow(Frame
parent, Image image) {
super(parent);
this.image
= image;
In the
first
of the two splash()
methods, we used Toolkit.getDefault().createImage() to create the splash image.
This did not actually load the image data into memory. We load it now synchronously
using a MediaTracker.
Depending on the number of available processors, this
is not the only thing that is going on. This is because, the Main thread may
(or may not be) waiting in the synchronized block in the
second
of
the two splash() methods.
If we are running on a single CPU machine, the processing
of the image is the only task that we want to work on now. If the image is
contained in the same JAR file as the other splash screen classes, the Java
VM has loaded it into memory already. All we have to do, is to decode the image.
The time for this task is entirely CPU bound. Any attempt to work on more than
one task now, would needlessly delay the splash screen.
On a machine with more processors, the loading will
happen asynchronously to the Main thread, which we have sent off to launch
the application. If all files are contained in the same JAR file, we are using
one CPU entirely for loading the image and leaving other resources free for
the application initialization procedure.
5.4 The painting methods
And finally, lets take a look at the methods which are
responsible for painting the splash image.
private boolean paintCalled = false;
public void update(Graphics g) {
paint(g);
}
public void paint(Graphics g) {
g.drawImage(image, 0, 0, this);
The original implementation of method update() in class Window fills its display
area with a background color before calling the paint() method. Since we
are drawing an image that completely covers this area, we directly call paint().
This is done to avoid undesired flickering of the splash image.
In method paint(), we draw the image, and after this
has happened the first time, we notify the Main thread of our application.
As I have described further
above
, on a single
CPU machine, the Main thread is patiently awaiting this notification in method
splash(). This strategy ensures that, on a single CPU machine, the user is
granted to see the splash window.
Conclusion
Doing a fast splash screen, requires that we carefully
manage resources, so that tasks needed for displaying the splash screen are
execuded prior to other tasks.
This article has shown, how to use Reflection to shift
the class resolution task behind the splash screen task, and how to keep the
CPU resource(s) focused on the splash screen task, until we have painted our
splash image on screen.
In side tracks of this article, we have covered additional
issues, such as avoiding flickering, and how to take advantage of multiprocessor
machines.
Possible enhancements
The splash screen described in this article is pretty
much bare bone. If you like, you can extend it to display information about
start up steps to the user.
To do this, remember that we have designed class SplashWindow
using the Singleton design pattern. Thus you can add more static methods to
class SplashWindow, which act on the Singleton instance. These static methods
can be accessed from the main method of the MyApplication class (and of any
other methods involved in the start up procedure of our application).
This will have no negative impact on the class resolution
and class loading issue, because the dependency is directed from the application
code to the splash screen code, and not the other way round.
Credits
I would like to thank Roy Ratcliffe, Harry Mantheakis
and the Apple Java-Dev community for their valuable critique and input on the
various versions of the code and the article.
OK, so it's Windows-only and $69 for a nag-free version (licensed per developer, generated launcher is free to distribute/bundle), but you'll get the fastest splash screen there is. Not to forget JVM search, environment variables, NT service support etc.
Re: General: How to do a fast Splash Screen in Java
I just implemented some splash screen code with similar concerns (avoiding excessive classloading, splash screen code in a separate "bootstrap" jar that loads other code with its own classloader and ((Runnable)Class.forName("realMainClass")).run(). It doesn't load in an image, it uses Java2D to create it, with TextLayout to draw feedback. The complicated background (with gradients and the like) is drawn on a buffered image which is then copied onto an AWT Frame using a 2-screen buffer strategy (to avoid redraw flicker).
It does NOT load in any AWT components and uses a null layout manager. repaint() just calls paint(). The splash screen runs in an asynchronous daemon thread, and on each run of the main loop (every 40s), only repaints if one of its public-API properties has changed. repaint() is also called to force a repaint if the O/S requires it.
With Java 5, you also have the "alwaysOnTop" property for windows.
Re: General: How to do a fast Splash Screen in Java
I've been using http://launch4j.sourceforge.net/ to display a splash screen while the JVM loads, then showing my own splash screen while the app loads. But this wasn't quite good enough; after launch4j's splash screen disappeared, there was a little bit too much dead-screen time before the app's splash screen showed up. Applying this tip solved that problem. I even use a Swing-based splash screen (JLabel + JProgressBar in a JWindow) instead of AWT as the author does, and it loads plenty fast enough.
General: How to do a fast Splash Screen in Java
At 10:53 AM on Apr 3, 2005, Werner Randelshofer wrote:
Fresh Jobs for Developers Post a job opportunity
How to do a fast Splash Screen in Java
There are many articles about doing Splash Screens in Java. Not all of them take performance seriously. This one does.
A splash screen is an image being shown on screen while an application is starting up. This article discusses how to create a splash screen that is shown very early in the process of starting a Java application. To achieve this we minimize the number of API classes needed to display the splash screen and we carefully avoid resource contention by the threads running in the JVM.
1. The Problem
Java applications often have very long initialization times. I am assuming, that we have already tried our best to reduce the start up latency of our application. But sometimes we reach a hard limit that we cannot undercut. It takes a while until our application is ready, and there is nothing we can do about it.
A splash screen is a means to provide feedback to the user, telling that our application is starting up, and it also is a way to advertise our product.
At first glance, implementing a splash screen seems to be straightforward. The Swing API provides a rich set of classes to do this. Simply create a JWindow, put a JLabel with an ImageIcon on it, put the current Thread to sleep for 3 seconds and then continue loading the application...
Unfortunately with such a naïve approach we not only end up increasing the start up latency of our application by the 3 seconds sleep time, we also happen to 'achieve' that our splash screen shows up late in the initialization process of our application. And if the splash screen shows up late, it does not fulfil its job.
When we design a splash screen we have to take account of the following:
2. Design Proposal
The proposed design consists of three classes: MyApplication, Splasher and SplashWindow. The diagram below outlines the classes and their collaboration.
MyApplication is our application class. SplashWindow contains all code required to do the fast splash screen. Class Splasher is the new entry point for MyApplication. The numbers show the sequence of the method invocations.
3. Class MyApplication
MyApplication is our application class. It contains the long running initialisation code. To achieve a clear design, we keep this class free from our splash screen code. The only concession that we require is, that its main method must return once the application is up and running.
Here is an outline of the code of MyApplication.java.
public class MyApplication {public static void main(String[] args) {
/* Start the application and return when it is ready to use. */
//...program code creating a JFrame with a ‘Hello World’
//
message omitted...}
}
Please note that we can launch the application without a splash screen by directly invoking the main method of this class. This is useful for testing and debugging.
Now let's see how to add a splash screen to this class.
4. Class Splasher
Splasher is our bootstrap class. Its purpose is to separate the splash screen code from the application class code, and to keep class SplashWindow maintenance free. Class Splasher consists of a main method only, which does three things:
Please note that we want to keep this class as small as possible. The size of this class and of the of classes referenced by this class directly influence the startup latency of our splash screen.
public class Splasher {public static void main(String[] args) {
SplashWindow.splash(Splasher.class.getResource("splash.gif" ));
SplashWindow.invokeMain("MyApplication", args);
SplashWindow.disposeSplash();
}
}
As you can see, this class consists only of code that delegates tasks to the SplashWindow class.
In fact, we could have moved all the code of this class into class SplashWindow. Why haven't I done so? Class Splasher contains all the code that needs to be changed per application. That is, for each application we will be using another splash image, and the class name of the application will also be different. This keeps class SplashWindow free from application specific changes. It can be reused over and over again, without ever having to touch its code.
Also note, that we could have put all three method calls into a single call. But keeping each step of the initialization procedure separate, makes the procedure easier to understand.
5. Class SplashWindow
Now lets take a look at class SplashWindow. This class and its interaction with the other two classes are the meat of this article.
I will show only the essential portions of this class, the full listing is available in the attachment.
5.1 Method invokeMain()
First lets take a look at method invokeMain(). Here we invoke the main() method of our application using, er, clumsy Reflection code.
public static void invokeMain(String className, String[] args) {
try {
Class.forName(className)
.getMethod("main", new Class[] {String[].class})
.invoke(null, new Object[] {args});
} catch (Exception e) {
InternalError error =
new InternalError("Failed to invoke main method" );error.initCause(e);
throw error;
}
}
Today, most Java VM's lazily resolve and verify classes. At one time, on Mac OS X 10.1, we had the case of an eagerly resolving Java VM. Without using Reflection, the main method of class Splasher was only executed, after the Java VM had resolved all dependencies between the Splasher class, the rest of the application and of all API classes used by the application.
Reflection is a means to dynamically write code at runtime. Therefore, the dependency between our splash screen code and the application code will only be revealed to the Java VM, when the Class.forName() method is executed. Since class Splasher invokes method invokeMain() after it has invoked method splash(), the splash screen will be shown to the user, before such a resolution process can take place.
Reflection does not prevent though, that the Java VM loads all files of a JAR file and of dependent JAR files into memory before executing our code. If JAR file loading is a restricting performance factor (e.g. because we load them over a slow network connection), we may want to put the Splasher class and the SplashWindow together with the splash image into a separate JAR file. In the manifest of the JAR file, we do not specify a dependency to the application JAR files. Instead, we change the invokeMain() method, to have it use an URLClassLoader to load the JAR files containing the application.
5.2 Method splash()
Now, lets tackle method splash().
public static void splash(URL imageURL) {if (imageURL != null) {
splash(Toolkit.getDefaultToolkit().createImage(imageURL));
}
}
private static SplashWindow instance;
public static void splash(Image image) {
if (instance == null && image != null) {
Frame f = new Frame();
instance = new SplashWindow(f, image);
instance.show();
if (! EventQueue.isDispatchThread()&& Runtime.getRuntime().availableProcessors() == 1) {
synchronized (instance) {while (! instance.paintCalled) {
try {
instance.wait();} catch (InterruptedException e) {}}
}
}
}
}
You may have noticed, that there are two splash methods: one that creates the image from the URL, and one that works with the SplashWindow instance. This is just because I like to keep methods short and simple.
In the first splash() method we use the AWT Toolkit class to create the image. We use this method instead of the new Image IO API, because it does not immediately load the image using the current thread. We will initiate image loading in the AWT Event Dispatcher thread later. I will come back to this topic further below in this article.
In the second splash() method, you see that an instance of the SplashWindow is created (class SplashWindow is a subclass of java.awt.Window). Then, the instance is shown. And then, we wait in a synchronized block until the paint method of the instance has been called.
The last two steps are worth to be looked at closely. Showing the SplashWindow, starts the AWT Event Dispatcher thread, which is going to call the paint method of the SplashWindow. We wait in the synchronized block until the painting has happened.
Why is there an if-statement which guards the synchronized block?
We must not wait, if method splash() is called from the AWT Event Dispatcher thread. This would cause a live lock, which would hang our application. This check appears to be overkill, because we are calling this method from the Main thread anyway. I have added it, because I sometimes use the SplashWindow to display the about box of my application, and then I don't want to care on which thread I am calling this method.
The check for the number of available processors is more interesting.
On a single processor machine, if we wouldn't wait here, and instead proceed with our start up process, we would compete for the CPU with the AWT Event Dispatcher thread. Since the AWT Event Dispatcher thread has not yet started, we are likely to win the competition, or – in this case – actually hog the CPU, and therefore significantly delay the splash screen. In the worst case, the splash screen would not be shown at all.
On a multiple processor machine, we have a chance, that both threads will get a CPU of their own. In this case, we have an opportunity to maximize resource usage. Of course, it all depends on how independent the two threads are with respect to other resources they are using. Thus, on a multiprocessor machine, we take a small risk of delaying the splash screen by a little bit. In return for the risk, we get better overall performance.
5.3 The constructor
The constructor of class SplashWindow makes the object ready for later usage.
public class SplashWindow extends Window {
private SplashWindow(Frame parent, Image image) {
super(parent);
this.image = image;
MediaTracker mt = new MediaTracker(this);
mt.addImage(image,0);
try {
mt.waitForID(0);
} catch(InterruptedException ie){}
//...boilerplate code omitted...
}
// ...}In the first of the two splash() methods, we used Toolkit.getDefault().createImage() to create the splash image. This did not actually load the image data into memory. We load it now synchronously using a MediaTracker.
Depending on the number of available processors, this is not the only thing that is going on. This is because, the Main thread may (or may not be) waiting in the synchronized block in the second of the two splash() methods.
If we are running on a single CPU machine, the processing of the image is the only task that we want to work on now. If the image is contained in the same JAR file as the other splash screen classes, the Java VM has loaded it into memory already. All we have to do, is to decode the image. The time for this task is entirely CPU bound. Any attempt to work on more than one task now, would needlessly delay the splash screen.
On a machine with more processors, the loading will happen asynchronously to the Main thread, which we have sent off to launch the application. If all files are contained in the same JAR file, we are using one CPU entirely for loading the image and leaving other resources free for the application initialization procedure.
5.4 The painting methods
And finally, lets take a look at the methods which are responsible for painting the splash image.
private boolean paintCalled = false;public void update(Graphics g) {
paint(g);
}
public void paint(Graphics g) {
g.drawImage(image, 0, 0, this);
if (! paintCalled) {
paintCalled = true;
synchronized (this) { notifyAll(); }
}
}
The original implementation of method update() in class Window fills its display area with a background color before calling the paint() method. Since we are drawing an image that completely covers this area, we directly call paint(). This is done to avoid undesired flickering of the splash image.
In method paint(), we draw the image, and after this has happened the first time, we notify the Main thread of our application. As I have described further above , on a single CPU machine, the Main thread is patiently awaiting this notification in method splash(). This strategy ensures that, on a single CPU machine, the user is granted to see the splash window.
Conclusion
Doing a fast splash screen, requires that we carefully manage resources, so that tasks needed for displaying the splash screen are execuded prior to other tasks.
This article has shown, how to use Reflection to shift the class resolution task behind the splash screen task, and how to keep the CPU resource(s) focused on the splash screen task, until we have painted our splash image on screen.
In side tracks of this article, we have covered additional issues, such as avoiding flickering, and how to take advantage of multiprocessor machines.
Possible enhancements
The splash screen described in this article is pretty much bare bone. If you like, you can extend it to display information about start up steps to the user.
To do this, remember that we have designed class SplashWindow using the Singleton design pattern. Thus you can add more static methods to class SplashWindow, which act on the Singleton instance. These static methods can be accessed from the main method of the MyApplication class (and of any other methods involved in the start up procedure of our application).
This will have no negative impact on the class resolution and class loading issue, because the dependency is directed from the application code to the splash screen code, and not the other way round.
Credits
I would like to thank Roy Ratcliffe, Harry Mantheakis and the Apple Java-Dev community for their valuable critique and input on the various versions of the code and the article.
4 replies so far (
Post your own)
Re: General: How to do a fast Splash Screen in Java
http://www.exe4j.comOK, so it's Windows-only and $69 for a nag-free version (licensed per developer, generated launcher is free to distribute/bundle), but you'll get the fastest splash screen there is. Not to forget JVM search, environment variables, NT service support etc.
Re: General: How to do a fast Splash Screen in Java
Or you could just use the class from the free and open source package UIc.http://uic.sourceforge.net/api/20/uic/widgets/Splash.html
Or this one if you run JVM 1.4+
http://uic.sourceforge.net/api/20/uic/widgets/SplashScreen.html
Re: General: How to do a fast Splash Screen in Java
I just implemented some splash screen code with similar concerns (avoiding excessive classloading, splash screen code in a separate "bootstrap" jar that loads other code with its own classloader and ((Runnable)Class.forName("realMainClass")).run(). It doesn't load in an image, it uses Java2D to create it, with TextLayout to draw feedback. The complicated background (with gradients and the like) is drawn on a buffered image which is then copied onto an AWT Frame using a 2-screen buffer strategy (to avoid redraw flicker).It does NOT load in any AWT components and uses a null layout manager. repaint() just calls paint(). The splash screen runs in an asynchronous daemon thread, and on each run of the main loop (every 40s), only repaints if one of its public-API properties has changed. repaint() is also called to force a repaint if the O/S requires it.
With Java 5, you also have the "alwaysOnTop" property for windows.
- Chris
Re: General: How to do a fast Splash Screen in Java
I've been using http://launch4j.sourceforge.net/ to display a splash screen while the JVM loads, then showing my own splash screen while the app loads. But this wasn't quite good enough; after launch4j's splash screen disappeared, there was a little bit too much dead-screen time before the app's splash screen showed up. Applying this tip solved that problem. I even use a Swing-based splash screen (JLabel + JProgressBar in a JWindow) instead of AWT as the author does, and it loads plenty fast enough.