Animate Transitions Between Tabs #8
Chapter 1, Basic JComponents
|
33
HACK
TransitionTabbedPane extends the standard JTabbedPane and also imple-
ments
ChangeListener and Runnable. ChangeListener allows you to learn
when the user has switched between tabs. Since the event is propagated
before the new tab is painted, inserting the animation is very easy.
Runnable
is used for the animation thread itself.
You could have split the thread into a separate class, but I
think that keeping all of the code together makes the system
more encapsulated and easier to maintain.
TransitionTabbedPane adds one new property, the animation length. This
defines the number of steps used for the transition, and it can be set by the
subclass or external code.
Scheduling the Animation
Since the pane was added as a ChangeListener to itself, the stateChanged( )
method will be called whenever the user switches tabs. This is the best place
to start the animation thread. Once started, the thread will capture the pre-
vious tab into a buffer, loop through the animation, and control the repaint
speed:
// threading code
public void stateChanged(ChangeEvent evt) {
new Thread(this).start( );
}
protected int step;
protected BufferedImage buf = null;
protected int previous_tab = -1;
public void run( ) {
step = 0;
public TransitionTabbedPane( ) {
super( );
this.addChangeListener(this);
}
public int getAnimationLength( ) {
return this.animation_length;
}
public void setAnimationLength(int length) {
this.animation_length = length;
}
Example 1-16. A skeleton for the transition manager (continued)
34
|
Chapter 1, Basic JComponents
#8 Animate Transitions Between Tabs
HACK
// save the previous tab
if(previous_tab != -1) {
Component comp = this.getComponentAt(previous_tab);
buf = new BufferedImage(comp.getWidth( ),
comp.getHeight( ),
BufferedImage.TYPE_4BYTE_ABGR);
comp.paint(buf.getGraphics( ));
}
Notice that the run( ) method grabs the previous tab component only when
the
previous_tab index isn’t -1. The component will always have a valid
value, except for the first time the pane is shown on screen, but that’s OK
because the user won’t have really switched from anything anyway. If there
is a previous tab, then the code grabs the component and paints it into a
buffer image.
It’s important to note that this is not thread-safe because the
code is being executed on a custom thread, not the Swing
thread. However, since the tab is about to be hidden
anyway—and, in fact, the next real
paint( ) call will only
draw the new tab—you shouldn’t have any problems. Any
changes introduced by this extra
paint( ) call won’t show up
on screen.
With the previous component safely saved away, you can now loop through
the animation:
for(int i=0; i<animation_length; i++) {
step = i;
repaint( );
try {
Thread.currentThread( ).sleep(100);
} catch (Exception ex) {
p("ex: " + ex);
}
}
step = -1;
previous_tab = this.getSelectedIndex( );
repaint( );
This code shows a basic animation loop from 1 to N, with a 100-millisecond
duration for each frame.
A more sophisticated version of the code could have
dynamic frame rates to adjust for system speed.

Get Swing Hacks now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.