HomeDigital EditionSys-Con RadioSearch Java Cd
Advanced Java AWT Book Reviews/Excerpts Client Server Corba Editorials Embedded Java Enterprise Java IDE's Industry Watch Integration Interviews Java Applet Java & Databases Java & Web Services Java Fundamentals Java Native Interface Java Servlets Java Beans J2ME Libraries .NET Object Orientation Observations/IMHO Product Reviews Scalability & Performance Security Server Side Source Code Straight Talking Swing Threads Using Java with others Wireless XML
 

When designing a Java applet or application, you often may wish to place a similar set of components in several different places. Perhaps you would like to have a labeled text entry field, or a more complicated structure like a list of IP addresses and subnet masks, with entry fields for each. You could do these by creating a Panel, placing them there, having a method in your class to create this, and returning the Panel. There is an easier way.

A 'macro' component [treating multiple components as a single object] is a simple step between writing a custom component which handles all the events and drawing its needs, and just creating a new panel in your existing class. From an object-oriented standpoint, it is a cleaner, simpler way to write code. From a Java Abstract Window Toolkit (AWT) standpoint, it is simpler than trying to deal with all the Events and data within a single class.

As an example, consider a labeled choice. The AWT does not contain this construct, but it's likely something you use a lot in your applets. Perhaps you have created a method 'createLabelledChoiceComponent', and it returns a panel which you add to yourself. You could just as easily create a 'labelledChoice' class. For this trivial example, you would need to provide a constructor, taking the label string as a parameter. Additionally, you could provide methods to get at the Choice component methods: addItem(), getItem(), etc. Another way you could do this would be to provide a getChoice() method, simply returning the Choice to the caller.

You may be wondering why this example extends Panel, instead of Choice. If it extended Choice, you would automatically have access to all the Choice methods. The problem is, I need this to be a layout manager in order to hold the two components, the Label and the Choice.

  • In the example above, there is no benefit to having placed this code in a separate class. It would have been just as simple to create a Panel and parent the Label and the Choice directly on it. The benefit becomes clear, however, when there is a need to do event handling.
Say you wished to create a list of IP addresses. You would like to prevent the user from entering something that wasn't an IP address in it. Additionally, you would like to group this list, somehow, so that it stood out as a unit.

In the next example, I have created a new class which presents the user with a labeled box for entering IP addresses. Drawing a box around it was easy since it is a component of its own and has bounds(). In addition, I don't allow any keys other than editing keys and '0-9' plus '.' in the IP address field. The event handler discards any other key. The outcome of this is shown in Figure 1.

Figure 1
Figure 1

If you examine the source code in Listing 2, you will see how easy it was to accomplish this entire component. The border around it was obtained by overriding the paint function to always draw a box of our bounding size. The key-filtering in the IP field was accomplished by passing only those keys which we wanted. Recall that if an event handler returns 'true', then it has handled the event, and the next event handler won't see it. Thus, I return 'true' if it is a key I don't want.

The benefits of making this list into a component are much clearer than the first example:

  • It was trivial to draw a border around it.
  • Event handling was simple -- It didn't conflict with the rest of the applet.
  • We can now create and add multiple lists of this type trivially.
  • There is a single piece of code to change if we want additional functionality.
  • There is a possibility we can share this component with other applets.
This simple (and obvious) technique can make your coding simpler, provide you with a library of reusable components for your other applets, and make documentation simpler.

About the Author
Don Bowman is a software designer with Hewlett-Packard. He is the co-webmaster for his division. Don has worked with Java on HP-UX and Windows 95 environments.

	

Listing 1: Labeled choice method

import java.awt.*;
public class
labelledChoice extends Panel
{
    Label label;
    Choice choice;
    public
    labelledChoice(String l)
    {
	label = new Label(l);
	choice = new Choice();
	add(label);
	add(choice);
    }
    public Choice
    getChoice()
    {
	return choice;
    }
}

Listing 2: IPList method

import java.awt.*;
class IPList extends Panel
{
  List        addressList;
  TextField   ipTextField;
  Button      addButton;
  Button      removeButton;
  Label       listLabel;

  public
  IPList(String label)
  {
    setLayout(new GridBagLayout());
    listLabel = new Label(label);
    constrain(  listLabel,
		0, 0, 1, 1,
		GridBagConstraints.NONE,
		GridBagConstraints.NORTHWEST,
		0.0, 0.0,
		1, 1, 1, 1);

    Panel ipPanel = new Panel();
    ipPanel.setLayout(new GridLayout(1,2));
    Label ipLabel = new Label("IP");
    ipPanel.add("West",ipLabel);
    ipTextField = new TextField(15);
    ipPanel.add("East",ipTextField);
    constrain(  ipPanel,
		0, 1, 1, 1,
		GridBagConstraints.NONE,
		GridBagConstraints.NORTHWEST,
		0.0, 0.0,
		1, 1, 1, 10);

    addButton = new Button("Add");
    constrain(  addButton,
		1, 1, 1, 1,
		GridBagConstraints.NONE,
		GridBagConstraints.NORTHWEST,
		0.0, 0.0,
		1, 1, 1, 5);

    addressList = new List();
    addressList.setMultipleSelections(true);
    constrain(  addressList,
		0, 2, 1, 5,
		GridBagConstraints.BOTH,
		GridBagConstraints.NORTHWEST,
		1.0, 1.0,
		1, 10, 10, 10);

    removeButton = new Button("Remove");
    constrain(  removeButton,
		1, 2, 1, 1,
		GridBagConstraints.NONE,
		GridBagConstraints.NORTHWEST,
		0.0, 0.0,
		1, 1, 1, 5);
  }
  private void 
  constrain(  Component component, 
	      int grid_x,      int grid_y, 
	      int grid_width,  int grid_height,
	      int fill, 
	      int anchor, 
	      double weight_x, double weight_y,
	      int top,         int left, 
	      int bottom,      int right)
  {
    GridBagConstraints cst = new GridBagConstraints();
    cst.gridx = grid_x; 
    cst.gridy = grid_y;
    cst.gridwidth = grid_width; 
    cst.gridheight = grid_height;
    cst.fill = fill; 
    cst.anchor = anchor;
    cst.weightx = weight_x; 
    cst.weighty = weight_y;
    cst.insets = new Insets(top, left, bottom, right);
    ((GridBagLayout)getLayout()).setConstraints(component, cst);
    add(component);
  }

  public List
  getList()
  {
    return addressList;
  }
  private void
  doRemoveIP()
  {
    int sel[] = addressList.getSelectedIndexes();
    for (int i = 0; i < sel.length; i++)
    {
      addressList.delItem(sel[i]);
    }
    ipTextField.setText("");
  }
  private void
  doAddIP()
  {
    String ip = ipTextField.getText();
    ipTextField.setText("");
    addressList.addItem(ip);
  }
  private void
  doIPShow()
  {
    String ip = addressList.getSelectedItem();
    ipTextField.setText(ip);
  }
  private void
  handleActionEvents(Event event)
  {
    if (event.target == addButton)
    {
      doAddIP();
    }
    else if (event.target == removeButton)
    {
      doRemoveIP();
    }
  }
  private boolean
  handleKeyEvents(Event event)
  {
    if (event.target == ipTextField)
    {
      switch (event.key)
      {
	case Event.LEFT:
	case Event.RIGHT:
	case '\b':
	case '.':
	case '0': case '1': case '2':
	case '3': case '4': case '5':
	case '6': case '7': case '8':
	case '9':
	  break;
	default:
	  return true;
      }
    }
    return false;
  }
  public boolean
  handleEvent(Event event)
  {
    switch (event.id)
    {
      case Event.ACTION_EVENT:
	handleActionEvents(event);
	break;
      case Event.LIST_SELECT:
	doIPShow();
	break;
      case Event.KEY_PRESS:
	return handleKeyEvents(event);
    }
    return super.handleEvent(event);
  }
  public void
  paint(Graphics g)
  {
    Rectangle r = bounds();
    g.drawRect(0, 0, r.width-1, r.height-1);
  }
}

 

All Rights Reserved
Copyright ©  2004 SYS-CON Media, Inc.
  E-mail: [email protected]

Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.