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. 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'sbenefit 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 andadd()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 theaction(Event,Object)method used for handling user input--or, to cloak it in jargon we've used in the past,actionis 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
actionmethod 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. Ouractionhas twoifstatements--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.targetis our Next button (bnext). TheEventobject (e) that's passed toactionis an object containing a description of a single event.e.targetis 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 theCardLayoutto 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
CardLayoutobject and assigned it as a parameter to asetLayoutfunction. 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 tosetLayout(). But we had to take an extra step before we could use what the method returned. We had to enclose thep1.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 aLayoutManagerobject, and nothing more--andCardLayoutis a specific kind ofLayoutManager. We need to explicitly tell Java that we're getting a CardLayout system back before we can use thenext()method on it.next()is specific toCardLayout.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 theCardLayout. This panel is then added to the main interface. Theaction()method ties the next and previous buttons to thenext()andprevious()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.