Nested Containers and The Event Chain

When I create compound components, how is event handling affected and how can the constituent components communicate with components in the applet or other containers? Consider using the KeyPad to flip through a set of "slides." The main applet will have a KeyPad and a SlideViewer that are laid out next to each other with the default FlowLayout. The SlideViewer will be a compound Component containing a series of slides laid out using CardLayout. Here is the running SlideShow applet:



How can you get the key pad to flip through the slides in the CardLayout? Define an interface called KeyPadObserver that allows an object to be notified when a key has been pressed:

interface KeyPadObserver {
    public void pressed(String key);
}

The interface allows the key pad to be more general. An arbitrary object that implements this interface can then be attached to a new version of the KeyPad called KeyPadWithObserver:

class KeyPadWithObserver extends Panel {
    String[] keys = { "1","2","3",
                      "4","5","6",
                      "7","8","9",
                      "*","0","#" };
    Button[] b = new Button[keys.length];
    KeyPadObserver observer;
    public KeyPadWithObserver(KeyPadObserver o) {
        observer = o;
        setLayout(new GridLayout(4,3));
        for (int i=0; i<keys.length; i++) {
            b[i] = new Button(String.valueOf(keys[i]));
            add(b[i]);
        }
    }
    public boolean action(Event e, Object arg) {
        observer.pressed((String)arg);
        return true;
    }
}

A KeyPadObserver is passed to KeyPadWithObserver during construction. Then, upon key press (the action method is called), a KeyPadWithObserver can notify the observer. Events generated by a key are handled in KeyPadWithObserver rather than handling them in the SlideShow applet. The following containment hierarchy demonstrates the event chain when the "2" Button on the KeyPadWithObserver is pushed:

The SlideViewer is nothing but a Panel managed by CardLayout that implements the KeyPadObserver interface. The SlideViewer is designed so that the slides can be specified as an array of arbitrary Component objects:

class SlideViewer extends Panel implements KeyPadObserver {
    CardLayout layout;
    public SlideViewer(Component[] comps) {
        layout = new CardLayout();
        setLayout(layout);
        for (int i=0; i<comps.length; i++) {
            // set the key of component to the index
            add(String.valueOf(i+1), comps[i]);
        }
    }
    public void pressed(String key) {
        layout.show(this, key);
    }
}

The pressed method is called by the KeyPadWithObserver object when a key is pressed via:

observer.pressed((String)arg);

When the KeyPadWithOberserver object is created by the SlideShow applet, the SlideViewer is passed as the KeyPadObserver. SlideShow does nothing but create a set of slides, a SlideViewer, and a KeyPadWithObserver that is attached to the SlideViewer.

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

public class SlideShow extends Applet {
    Component[] slides = {    new Label("Slide 1"),
                              new Button("Slide 2"),
                              new TextField("Slide 3"),
                              new TextField("Slide 4"),
                              new Label("Slide 5"),
                              new Label("Slide 6"),
                              new Label("Slide 7"),
                              new Label("Slide 8"),
                              new Label("Slide 9") };
    public void init() {
        SlideViewer sv = new SlideViewer(slides);
        KeyPadWithObserver keypad = new KeyPadWithObserver(sv);
        add(keypad);
        add(sv);
    }
}

Note that there only 9 slides. Buttons "*", "0", and "#" will not affect the SlideViewer.

Related Magercise(s):