|
|
Listing 5.3 The ChaserLightsBorder Class
package com.foley.borders;
import java.awt.Insets;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Color;
import javax.swing.JComponent;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
/**
* ChaserLightsBorder is a concrete AnimatedBorder. It
* paints the border as a chase light.
*
* @see AnimatedBorder
* @see Border
* @author Mike Foley
**/
public class ChaserLightsBorder extends AnimatedBorder {
/**
* The index of the next light to be out
* when drawing the border.
**/
private int currentLightIndex = 0;
/**
* The number of lights to be on in a row
**/
private int onLightCount = 5;
/**
* The first off light index for this cycle.
**/
private int firstOffLightIndex = 0;
/**
* The color to draw on lights
**/
private Color onLightColor = Color.yellow;
/**
* The color to draw off lights
**/
private Color offLightColor = Color.white;
/**
* The direction of light travel. True = forward.
**/
private boolean direction = true;
/**
* Bound property names.
**/
public static final String DIRECTION_PROPERTY = DirectionProperty;
public static final String ONLIGHTCOLOR_PROPERTY =
OnLightColorProperty;
public static final String OFFLIGHTCOLOR_PROPERTY =
OffLightColorProperty;
/**
* Constructor.
* Create insets from the raw parameter and call our
* constructor taking Insets to do the work.
*
* @param c The component we border.
* @param top The top border width.
* @param left The left border width.
* @param bottom The bottom border width.
* @param right The right border width.
**/
public ChaserLightsBorder( JComponent c, int top, int left,
int bottom, int right ) {
this( c, new Insets( top, left, bottom, right ) );
}
/**
* Constructor.
* Call our super. We dont do any additional processing.
*
* @param c The component we border.
* @param insets The border size.
**/
public ChaserLightsBorder( JComponent c, Insets insets ) {
super( c, insets );
}
/**
* Set the on light count of the chaser lights.
* This value is one greater than the number of lights
* on before the off light. A value of two will give
* every other light being off. A value of one will give
* all lights on, not very good.
*
* This is a bound property.
*
* @param onLightCount The new on light count.
**/
public void setOnLightCount( int onLightCount ) {
if( onLightCount < 1 )
throw new IllegalArgumentException(
Negative or zero onLightCount given );
Integer old = new Integer( this.onLightCount );
this.onLightCount = onLightCount;
changes.firePropertyChange( ONLIGHTCOUNT_PROPERTY,
old, new Integer( this.onLightCount ) );
} // setOnLightCount
/**
* @return The number of lights - 1 in a row between the off light.
**/
public int getOnLightCount() {
return( this.onLightCount );
}
/**
* Set the direction of the chaser lights. True means
* forward.
* This is a bound property.
*
* @param direction The new direction of the chaser lights.
**/
public void setDirection( boolean direction ) {
Boolean old = new Boolean( this.direction );
this.direction = direction;
changes.firePropertyChange( DIRECTION_PROPERTY,
old, new Boolean( this.direction ) );
} // setDirection
/**
* @return The direction the chaser lights are going.
**/
public boolean getDirection() {
return( this.direction );
}
/**
* Set the color for on lights.
* This is a bound property.
*
* @param onLightColor The new color for on lights.
**/
public void setOnLightColor( Color onLightColor ) {
Color old = this.onLightColor;
this.onLightColor = onLightColor;
changes.firePropertyChange( ONLIGHTCOLOR_PROPERTY,
old, this.onLightColor );
} // setOnLightColor
/**
* @return The color for on lights.
**/
public Color getOnLightColor() {
return( this.onLightColor );
}
/**
* Set the color for off lights.
* This is a bound property.
*
* @param offLightColor The new color for off lights.
**/
public void setOffLightColor( Color offLightColor ) {
Color old = this.offLightColor;
this.offLightColor = offLightColor;
changes.firePropertyChange( OFFLIGHTCOLOR_PROPERTY,
old, this.offLightColor );
} // setOffLightColor
/**
* @return The color for off lights.
**/
public Color getOffLightColor() {
return( this.offLightColor );
}
/**
* Paint the border.
* Get the color at the current color index. Then update the index.
* The index is wrapped, so that the array of colors repeat every
* length of the array.
*
* @param c The bordered component.
* @param g The graphics to paint with.
* @param x The X location of the bordered component.
* @param y The Y location of the bordered component.
* @param width The width of the bordered component.
* @param height The height of the bordered component.
**/
public void paintBorder( Component c, Graphics g, int x,
int y, int width, int height ) {
//
// Save the current color so we can restore at end of method.
//
Color oldColor = g.getColor();
g.translate( x, y );
//
// Get our size.
//
Insets insets = getBorderInsets( c );
//
// Paint the border.
// Set the current light index. Start at 0.
//
currentLightIndex = 0;
//
// Top
int xpos = 0;
int ypos = 0;
if( 0 < insets.top ) {
do {
setGraphicsColor( g );
g.fillOval( xpos, ypos, insets.top, insets.top );
xpos += insets.top + 1;
} while( xpos < width );
}
//
// Right
xpos = width - insets.right;
ypos = insets.top;
if( 0 < insets.right ) {
do {
setGraphicsColor( g );
g.fillOval( xpos, ypos, insets.right, insets.right );
ypos += insets.right + 1;
} while( ypos < height - 2 * insets.bottom );
}
//
// Bottom
xpos = width - insets.right;
ypos = height - insets.bottom;
if( 0 < insets.bottom ) {
do {
setGraphicsColor( g );
g.fillOval( xpos, ypos, insets.bottom, insets.bottom );
xpos -= insets.bottom + 1;
} while( 0 < xpos );
}
//
// Left
xpos = 0;
ypos = height - 2 * insets.bottom;
if( 0 < insets.left ) {
do {
setGraphicsColor( g );
g.fillOval( xpos, ypos, insets.left, insets.left );
ypos -= insets.left + 1;
} while( 0 < ypos - insets.top );
}
//
// Update the light off index. If going forward, increment
// else decrement. Wrap the index as required.
//
if( direction ) {
firstOffLightIndex += 1;
firstOffLightIndex %= onLightCount;
} else {
firstOffLightIndex -= 1;
if( firstOffLightIndex < 0 )
firstOffLightIndex = onLightCount - 1;
}
//
// Restore the Graphics objects state.
//
g.translate( -x, -y );
g.setColor( oldColor );
} // paintBorder
/**
* Set the color to draw the next light with.
* We update the currentLight Index. This index
* must be reset each cycle.
*
* @param g The graphics used to paint.
**/
private void setGraphicsColor( Graphics g ) {
if( currentLightIndex % onLightCount == firstOffLightIndex ) {
g.setColor( offLightColor );
} else {
g.setColor( onLightColor );
}
//
// Update the currentLightIndex, wrap if required
//
currentLightIndex += 1;
}
} // ChaserLightsBorder
Very interesting visual effects can be created by using animated borders. However, creating a thread for each border makes the cost of these borders rather high. If multiple animated borders are to be used in an application or applet, a single thread should be used to control the animation in all of the animated borders.
|