List boxes

Bruce Eckel’s Thinking in Java Contents | Prev | Next

A
problem with a
List
is that the default action is double clicking, not single clicking. A single
click adds or removes elements from the selected group and a double click calls
action( ).
One way around this is to re-educate your user, which is the assumption made in
the following program:

//: List1.java
// Using lists with action()
import java.awt.*;
import java.applet.*;
 
public class List1 extends Applet {
  String[] flavors = { "Chocolate", "Strawberry",
    "Vanilla Fudge Swirl", "Mint Chip",
    "Mocha Almond Fudge", "Rum Raisin",
    "Praline Cream", "Mud Pie" };
  // Show 6 items, allow multiple selection:
  List lst = new List(6, true);
  TextArea t = new TextArea(flavors.length, 30);
  Button b = new Button("test");
  int count = 0;
  public void init() {
    t.setEditable(false);
    for(int i = 0; i < 4; i++)
      lst.addItem(flavors[count++]);
    add(t);
    add(lst);
    add(b);
  }
  public boolean action (Event evt, Object arg) {
    if(evt.target.equals(lst)) {
      t.setText("");
      String[] items = lst.getSelectedItems();
      for(int i = 0; i < items.length; i++)
        t.appendText(items[i] + "n");
    }
    else if(evt.target.equals(b)) {
      if(count < flavors.length)
        lst.addItem(flavors[count++], 0);
    }
    else
      return super.action(evt, arg);
    return true;
  }
} ///:~ 

When
you press the button it adds items to the
top
of the list (because of the second argument 0 to
addItem( )).
Adding elements to a
List
is
more reasonable than the
Choice
box because users expect to scroll a list box (for one thing, it has a built-in
scroll bar) but they don’t expect to have to figure out how to get a
drop-down list to scroll, as in the previous example.

However,
the only way for
action( )
to be called is through a double-click. If you need to monitor other activities
that the user is doing on your
List
(in particular, single clicks) you must take an alternative approach.

handleEvent( )

What
if these other methods –
action( )
in particular – don’t satisfy your needs? In the case of
List,
for example, what if you want to catch single mouse clicks but
action( )
responds to only double clicks? The solution is to override
handleEvent( )
for your applet, which after all is derived from
Applet
and can therefore override any non-
final
methods. When you override
handleEvent( )
for the applet you’re getting all the applet events before they are
routed, so you cannot just assume “This has to do with my button so I can
assume it’s been pressed,” since that’s true only for
action( ).
Inside
handleEvent( )
it’s possible that the button has the focus and someone is typing to it.
Whether it makes sense or not, those are events that you can detect and act
upon in
handleEvent( ).

To
modify the
List
example so that it will react to single mouse clicks, the button detection will
be left in
action( )
but the code to handle the
List
will be moved into
handleEvent( )
as follows:

//: List2.java
// Using lists with handleEvent()
import java.awt.*;
import java.applet.*;
 
public class List2 extends Applet {
  String[] flavors = { "Chocolate", "Strawberry",
    "Vanilla Fudge Swirl", "Mint Chip",
    "Mocha Almond Fudge", "Rum Raisin",
    "Praline Cream", "Mud Pie" };
  // Show 6 items, allow multiple selection:
  List lst = new List(6, true);
  TextArea t = new TextArea(flavors.length, 30);
  Button b = new Button("test");
  int count = 0;
  public void init() {
    t.setEditable(false);
    for(int i = 0; i < 4; i++)
      lst.addItem(flavors[count++]);
    add(t);
    add(lst);
    add(b);
  }
  public boolean handleEvent(Event evt) {
    if(evt.id == Event.LIST_SELECT ||
       evt.id == Event.LIST_DESELECT) {
      if(evt.target.equals(lst)) {
        t.setText("");
        String[] items = lst.getSelectedItems();
        for(int i = 0; i < items.length; i++)
          t.appendText(items[i] + "n");
      }
      else
        return super.handleEvent(evt);
    }
    else
      return super.handleEvent(evt);
    return true;
  }
  public boolean action(Event evt, Object arg) {
    if(evt.target.equals(b)) {
      if(count < flavors.length)
        lst.addItem(flavors[count++], 0);
    }
    else
      return super.action(evt, arg);
    return true;
  }
} ///:~ 

The
example is the same as before except for the addition of
handleEvent( ).
Inside, a check is made to see whether a list selection or deselection has
occurred. Now remember,
handleEvent( )
is
being overridden for the applet, so this occurrence could be anywhere on the
form and it could be happening to another list. Thus, you must also check to
see what the target is. (Although in this case there’s only one list on
the applet so we could have made the assumption that all list events must be
about that list. This is bad practice since it’s going to be a problem as
soon as another list is added.) If the list matches the one we’re
interested in, the same code as before will do the trick.

Note
that the form for
handleEvent( )
is
similar to
action( ):
if
you deal with a particular event you
return
true,
but if you’re not interested in any of the other events via
handleEvent( )
you must
return
super.handleEvent(evt)
.
This is vital because if you don’t do this, none of the other
event-handling code will get called. For example, try commenting out the
return
super.handleEvent(evt)

in the code above. You’ll discover that
action( )
never gets called, certainly not what you want. For both
action( )
and
handleEvent( )
it’s important to follow the format above and always return the
base-class version of the method when you do not handle the event yourself (in
which case you should return
true).
(Fortunately, these kinds of bug-prone details are relegated to Java 1.0
.
The new design in Java 1.1

that you will see later in the chapter eliminates these kinds of issues.)

More by Author

Must Read