Something for the weekend
Java Carousel Part 2: Creating a Carousel Component
We can now layout and animate our components using a layout manager, but we need something that can cause the animations to occur, and perhaps looks a little better. Queue our Gradient Panel and introducing JCarosel.

We want our component to be derived from a JPanel (it contains all of the container functionality we need, no pun intended), but we also know we want it to look pretty. So the first thing I'm going to do use a GrandientPanel class I've written for this purpose several times, here it is for completeness.

public class GradientPanel extends JPanel{
protected Color start;
protected Color end;


public void setBackground(Color color){
this.start = color;
this.end = color;
super.setBackground(color);
}

public void setBackground(Color start, Color end){
this.start = start;
this.end = end;
}

public void paint(Graphics graphics) {
if (start == end){
super.paint(graphics);
return;
}

Graphics2D g = (Graphics2D) graphics;

Rectangle2D.Double rectangle = new Rectangle2D.Double();
rectangle.setRect(0, 0, getWidth(), getHeight());
GradientPaint gradient = new GradientPaint((float)(getWidth()/2), (float) getY(), start, (float) (getWidth()/2), (float) getHeight(), end, false);

g.setPaint(gradient);
g.fill(rectangle);
super.paintChildren(graphics);
}

}


It's not very complicated, just using a custom paint method to draw a gradient instead of a single color background. But it's already starting to look a little better!

Picture 5

So our carosel component will extend this gradient panel class, let's take a look at it in full...

public class JCarosel extends GradientPanel implements MouseListener{
public static final String FRONT_COMPONENT_CHANGE = "frontComponentChanged";
protected CaroselLayout layout;

/**
* Creates a new instance of JCarosel
*/
public JCarosel() {
layout = new CaroselLayout(this);
this.setLayout(layout);
}

public Component add(Component component){
add("",component);
bringToFront(getComponent(0));
validate();
return component;
}

public void remove(Component component) {
super.remove(component);
if (getComponentCount()>0){
bringToFront(getComponent(0));
}
invalidate();
validate();
}

public Component add(ImageIcon icon, int width, int height){
ReflectedImageLabel component = new ReflectedImageLabel(icon,width,height);
component.addMouseListener(this);
return add(component);
}

public Component add(ImageIcon icon, String text, int width, int height){
ReflectedImageLabel component = new ReflectedImageLabel(icon,text,width,height);
component.addMouseListener(this);
return add(component);
}

public void bringToFront(Component component){
firePropertyChange(FRONT_COMPONENT_CHANGE,getComponent(0),component);
layout.setFrontMostComponent(component);
}

/**
* Which component is at the front
*/
public Component getFrontmost(){
return getComponent(0);
}

/**
* Bring the "clicked" component to the front
*/
public void mouseClicked(MouseEvent mouseEvent) {
if (mouseEvent.getClickCount()==1){
bringToFront((Component) mouseEvent.getSource());
}
}

/**
* Moves everything to their final positions
*
*/
public void finalizeLayoutImmediately(){
layout.layoutContainer(this);
layout.finalizeLayoutImmediately();
repaint();
}

/** Not interested */
public void mousePressed(MouseEvent mouseEvent) {}
/** Not interested */
public void mouseReleased(MouseEvent mouseEvent) {}
/** Not interested */
public void mouseEntered(MouseEvent mouseEvent) {}
/** Not interested */
public void mouseExited(MouseEvent mouseEvent){}
}


Not too much to try to understand is it? Well, hopefully not. Once again, let's break it down. As already discussed it extends GradientPanel, but also implements MouseLIstener. Why? Well what we want to make our carosel spin when the user clicks on an component on the carosel to bring that component to the front (remember setFrontmostComponent?) and we'll use a mouse listener to do that. First things first, let's look at the constructor...

/**
* Creates a new instance of JCarosel
*/
public JCarosel() {
layout = new CaroselLayout(this);
this.setLayout(layout);
}


Simple really, we construct and use a CaroselLayout object. We need to keep a reference to the layout manager so we can call that setFrontmostComponent method later.

public Component add(Component component){
component.addMouseListener(this);
add("",component);
bringToFront(getComponent(0));
validate();
return component;
}

public void remove(Component component) {
super.remove(component);
component.removeMouseListener(this);
if (getComponentCount()>0){
bringToFront(getComponent(0));
}
invalidate();
validate();
}


I also override the add and remove methods inherited from Container. We want to animate if that happens, bringing the newly added component to the front.

The next two methods we'll look at in more detail in the next installment, but for now you just need to know that we are going to have some methods for easily adding nice image buttons to look similar to the FrontRow buttons without a lot of over-head.

public Component add(ImageIcon icon, int width, int height){
ReflectedImageLabel component = new ReflectedImageLabel(icon,width,height);
component.addMouseListener(this);
return add(component);
}

public Component add(ImageIcon icon, String text, int width, int height){
ReflectedImageLabel component = new ReflectedImageLabel(icon,text,width,height);
component.addMouseListener(this);
return add(component);
}


So finally, and oh-so-Java wonderfully simply... the code to spin around our carosel when they click on a component...

/**
* Bring the "clicked" component to the front
*/
public void mouseClicked(MouseEvent mouseEvent) {
if (mouseEvent.getClickCount()==1){
bringToFront((Component) mouseEvent.getSource());
}
}

That's it. In the final installment I'll introduce the ReflectedImage component (and you'll know why give the citation to Romain Guy too!) and make the jar and source code available.

Pasted Graphic 3

Note: The iTunes CD Images used in this example are reproduced here by kind permission of Brian Zeitler from PixelNet Design and please note that all copyright remains with Brian and PixelNet Design.
|