As mentioned before, most full-screen applications usually function better
if they are at the helm during drawing. In traditional windowed GUI
applications, the question of when to paint is usually handled by the operating
system. When operating in a windowed environment, this makes perfect
sense. A windowed application does not know when the user is going
to move, resize, expose, or cover an application by another window until
it actually happens. In a Java GUI application, the operating system
delivers a
paint event to the AWT, which figures out what needs
to be painted, creates a
java.awt.Graphics object with the
appropriate clipping region, then calls the
paint method with
that
Graphics object:
// Traditional GUI Application paint method:
// This can be called at any time, usually from the event dispatch thread
public void paint(Graphics g) {
// Use g to draw my Component
}
This is sometimes referred to as
passive rendering. As you
can imagine, such a system incurs a lot of overhead, much to the annoyance
of many performance-sensitive AWT and Swing programmers.
When in full-screen exclusive mode, you don't have to worry anymore
about the window being resized, moved, exposed, or occluded (unless you've
ignored my suggestion to turn off resizing). Instead, the application
window is drawn directly to the screen (active rendering).
This simplifies painting quite a bit, since you don't ever need to worry
about paint events. In fact, paint events delivered by the operating
system may even be delivered at inappropriate or unpredictable times when
in full-screen exclusive mode.
Instead of relying on the paint method in full-screen exclusive
mode, drawing code is usually more appropriately done in a rendering
loop:
public void myRenderingLoop() {
while (!done) {
Graphics myGraphics = getPaintGraphics();
// Draw as appropriate using myGraphics
myGraphics.dispose();
}
}
Such a rendering loop can done from any thread, either its own helper thread
or as part of the main application thread.
Programming Tips
Some tips about using active rendering:
-
Don't put drawing code in the paint routine. You may never
know when that routine may get called! Instead, use another method
name, such as render(Graphics g), which can be called from the
paint
method when operating in windowed mode, or alternately called with its
own graphics from the rendering loop.
-
Use the setIgnoreRepaint method on your application window and
components to turn off all paint events dispatched from the operating system
completely, since these may be called during inappropriate times, or worse,
end up calling paint, which can lead to race conditions between
the AWT event thread and your rendering loop.
-
Separate your drawing code from your rendering loop, so that you can operate
fully under both full-screen exclusive and windowed modes.
-
Optimize your rendering so that you aren't drawing everything on the screen
at all times (unless you are using page-flipping or double-buffering, both
discussed below).
-
Do not rely on the update or repaint methods for
delivering paint events.
-
Do not use heavyweight components, since these will still incur the overhead
of involving the AWT and the platform's windowing system.
-
If you use lightweight components, such as Swing components, you may have
to fiddle with them a bit so that they draw using your Graphics,
and not directly as a result of calling the paint method.
Feel free to call Swing methods such as paintComponents, paintComponent,
paintBorder,
and paintChildren directly from your rendering loop.
-
Feel free to use passive rendering if you just want a simple full-screen
Swing or AWT application, but remember that paint events may be somewhat
unreliable or unnecessary while in full-screen exclusive mode. Additionally,
if you use passive rendering, you will not be able to use more advanced
techniques such as page-flipping. Finally, be very careful to avoid
deadlocks if you decide to use both active and passive rendering simultaneously--this
approach is not recommended.