O'Reilly logo

Swing Hacks by Chris Adamson, Joshua Marinacci

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Animating a Sheet Dialog #45
Chapter 6, Transparent and Animated Windows
|
237
HACK
startAnimation( ) begins by refreshing the glass pane with a repaint( ). It
then informs the
AnimatingSheet of its new source (i.e., the sheet) and adds
the
AnimatingSheet
to the layout. It then sets up a
javax.swing.Timer
to get
callbacks to an
actionPerformed( )
method that performs each step of the
animation. The
ANIMATION_SLEEP
parameter affects how smooth the anima-
tion will look—shorter sleeps will result in a higher frame rate, but higher
CPU use.
I’ve set this value as low as 2 ms and haven’t had a problem,
but I’m on a pretty fast box (a dual 1.8 GHz G5 Power Mac).
You might want to play with this value to get an ideal
performance-to-smoothness ratio.
stopAnimation( ) just stops the Timer, as you might expect.
The
actionPerformed( ) method is used by the Timer callbacks. It has two
tasks: calculating the height of the sheet to show, and wrapping up the ani-
mation if it has run its course. Notice that the progress calculation doesn’t
assume that it has been called back in accordance with the
ANIMATION_SLEEP.
It calculates the current time offset from when the animation began, and cal-
culates a progress from that, which in turn allows it to figure out how much
of the sheet to show. This is a really good practice because if your computer
can’t keep up with your desired rate, the
Timer will combine multiple call-
backs into one. By just using the current time (instead of a possibly incor-
rect assumption about frame rate), you’ll keep up with the specified rate and
duration. On screen, combined callbacks will look like dropped frames, but
a choppier animation is preferable to one that takes longer than it should.
If
actionPerformed( ) decides that the animation has finished, it calls
stopAnimation( ) and then cleans up the glass pane by either removing its
contents (if the direction is
OUTGOING) or by calling finishShowingSheet( ) (if
direction is
INCOMING). The finishShowingSheet( ) method clears the glass
pane and puts the real sheet in place, just like
showJDialogAsSheet( ) did in
the last lab.
Self-Painting
So, the frame is responsible for adding, removing, and animating the
AnimatedSheet, and for adding the real sheet when the incoming animation
completes. What that leaves for the
AnimatedSheet is the ability to paint itself
(from a region of the original dialog) and report an accurate size for the ben-
efit of the glass pane’s
LayoutManager.
238
|
Chapter 6, Transparent and Animated Windows
#45 Animating a Sheet Dialog
HACK
Example 6-10 shows the code for the AnimatingSheet inner class.
Example 6-10. Inner class to paint sheet during animation
class AnimatingSheet extends JPanel {
Dimension animatingSize = new Dimension (0, 1);
JComponent source;
BufferedImage offscreenImage;
public AnimatingSheet ( ) {
super( );
setOpaque(true);
}
public void setSource (JComponent source) {
this.source = source;
animatingSize.width = source.getWidth( );
makeOffscreenImage(source);
}
public void setAnimatingHeight (int height) {
animatingSize.height = height;
setSize (animatingSize);
}
private void makeOffscreenImage(JComponent source) {
GraphicsConfiguration gfxConfig =
GraphicsEnvironment.getLocalGraphicsEnvironment( )
.getDefaultScreenDevice( )
.getDefaultConfiguration( );
offscreenImage =
gfxConfig.createCompatibleImage(source.getWidth( ),
source.getHeight( ));
Graphics2D offscreenGraphics =
(Graphics2D) offscreenImage.getGraphics( );
source.paint (offscreenGraphics);
}
public Dimension getPreferredSize( ) { return animatingSize; }
public Dimension getMinimumSize( ) { return animatingSize; }
public Dimension getMaximumSize( ) { return animatingSize; }
public void paint (Graphics g) {
// get the bottom-most n pixels of source and
// paint them into g, where n is height
BufferedImage fragment =
offscreenImage.getSubimage (0,
offscreenImage.getHeight( ) -
animatingSize.height,
source.getWidth( ),
animatingSize.height);
// g.drawImage (fragment, 0, 0, this);
g.drawImage (fragment, 0, 0, this);
}
}

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required