by David Wood

Pour On The Java.  Hold The Programming.  Click Here.  Jamba.

The CardLayout

In case you haven't been following along, we've been spending time talking about how to create a good layout for your user interface. We've talked about the use of several of Java's basic "Layout Manager" classes. As promised, this week we're going to deliver the bigger, better layout--the CardLayout.

In point of fact, the CardLayout isn't actually a layout at all, in the sense that we've been describing. Unlike any of the other Layout Manager classes, this one does not contribute much of anything to arranging the position of your user interface objects on the screen.

Instead, CardLayout's benefit lies in the use of a technique we discussed last week: embedding panels within other panels. CardLayouts are used to keep track of a number of interface panels (defined and add()ed by you) and allow your application to easily flip between them--thus, the metaphor of flipping between various cards.

With the above applet, we've created two cards in our CardLayout. The Next and Prev buttons flip between them. In this case, the only things we added to either of the two panels were buttons, with each Panel having a separate layout.

CardLayout is a shortcut system. It allows you to create and arrange interfaces in several Containers, switching back and forth between them easily. Where before we discussed placing other Panels within your panel as an option, it is what's usually expected when using this layout system.

Now let's look at how we did it.


import java.awt.*;
import java.applet.Applet;

public class card extends Applet
{
  Panel p1,p2,p3;
  Button bnext,bprev;
  
  public void init()
  {
     bnext = new Button("Next");
     bprev = new Button("Prev");
     add(bnext);
     add(bprev);

     p3 = new Panel();
     p3.setLayout(new GridLayout(2,2));
     p3.add(new Button("Button 1"));
     p3.add(new Button("Button 2"));
     p3.add(new Button("Button 3"));
     p3.add(new Button("Button 4"));

     p2 = new Panel();
     p2.setLayout(new BorderLayout());
     p2.add("North",new Button("North"));
     p2.add("South",new Button("South"));
     p2.add("East",new Button("East"));
     p2.add("West",new Button("West"));

     p1 = new Panel();
     p1.setLayout(new CardLayout());
     p1.add("Grid",p3);
     p1.add("Border",p2);

     add(p1);
  }

  public boolean action (Event e, Object arg)
  {
    if (e.target == bnext)
      ((CardLayout)p1.getLayout()).next(p1);
    if (e.target == bprev)
      ((CardLayout)p1.getLayout()).previous(p1);

    return(false);
  }
}

This example incorporates a number of features we've been discussing over the weeks in Java Jolt. Most basically, it's an applet that redefines two methods. First, there is the init() method, which is used for setting up its interface and is only run once at startup. Second, there is the action(Event,Object) method used for handling user input--or, to cloak it in jargon we've used in the past, action is our event handler.

The interface objects that we lay out as we start the applet automatically shape the information flow that Java maintains for applet events. When a button is created, all the routines that communicate whether it's being pressed, for instance, are put into place as well.

As we discussed in a previous column that focused on event handling, the action method is called an applet when any number of different kinds of events occur. By defining a version of it ourselves, we can create our own behaviors when events happen. Our action has two if statements--each one ready to trigger the appropriate routine if an event occurs on one of our buttons.

    if (e.target == bnext)
      ((CardLayout)p1.getLayout()).next(p1);

We check to see if e.target is our Next button (bnext). The Event object (e) that's passed to action is an object containing a description of a single event. e.target is a reference to the target of the event--the object the event was related to. If that's the Next button, then we execute the proper code; in this case, we tell the CardLayout to show the "next" card in its repertoire.

The way we do this looks complicated, but we did this on purpose, just as the authors of the Sun CardLayout tutorial did. Look back at the line where we instantiated the CardLayout in the first place:

     p1.setLayout(new CardLayout());

We simply created a new CardLayout object and assigned it as a parameter to a setLayout function. We didn't assign it to a variable like we did our three panels of our two control buttons. We've lost "direct" contact with the object.

However, to control our CardLayout, we need to call methods on the CardLayout object we're using. Fortunately, we can get it back by calling the convenient getLayout() method of our panel--the companion method to setLayout(). But we had to take an extra step before we could use what the method returned. We had to enclose the p1.getLayout() call in parenthesis and do something commonly known as casting. Basically, we had to specify precisely what type of object we're dealing with. That's the "(CardLayout)" part of the line.

We do that because getLayout() is designed to return a LayoutManager object, and nothing more--and CardLayout is a specific kind of LayoutManager. We need to explicitly tell Java that we're getting a CardLayout system back before we can use the next() method on it. next() is specific to CardLayout.

Still with us? To sum up, the init() method creates the Next and Previous buttons, and then three panels. Two of which are the cards that you have been flipping back and forth between. They are attached to the third, which is the one that implements the CardLayout. This panel is then added to the main interface. The action() method ties the next and previous buttons to the next() and previous() routines of the card layout. Presto.

And if you thought this was complicated, wait until we start talking about the last, most infamous, GridBagLayout. Coming next week.

Past installments of Java Jolt

http://www.internet.com/