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
 
A PopupButton Component, by Pat Paternostro

Popup menus, the extremely functional components available to the Java developer, allow developers to provide menu capability without the inclusion of a full-blown menu system (i.e., MenuBar, Menus). From a user interface perspective, however, they're not intuitively accessible. The popup menu is usually triggered by pressing the right mouse button, but users may not be aware of its availability.

This article details a PopupButton component that ties the popup menu to a button component and allows users to display the menu via a click of the PopupButton.

Class Design
The PopupButton component is made up of one abstract class, PopupButton, located in PopupButton.java (see Listing 1). This class extends the java.awt.Button class and implements the java.awt.event.ActionListener event listener interface. Since the class is abstract, the java.awt.event.ActionListener interface method, actionPerformed(), doesn't need to be implemented; however, any nonabstract (concrete) direct descendant class is required to implement the method (more on this later).

Two overloaded constructors are provided for class construction, each taking a different number of arguments. The two-argument constructor simply calls the three-argument constructor via the this() method, which provides a convenient mechanism for one constructor to call another constructor, allowing you to localize construction code inside a single constructor.

The three-argument constructor requires three parameters:

  • A java.lang.String reference that represents the button's label
  • A java.lang.String array reference that represents the popup menu item labels
  • A java.awt.Container reference that represents the popup menu's container

The constructor first calls a superclass constructor, passing in the button's label concatenated with the "" character (Alt-0164 on your keyboard). This arbitrarily chosen character (you can choose any nonalphanumeric character you like) acts as a visual clue to the user that the button will display a popup menu when pressed. (I decided to use a character versus a "down arrow" image file [JPEG or GIF] for the visual clue to minimize resource requirements. However, if you wish to use an image file, you'll need to add code to read the image in the constructor and override the PopupButton component's paint() method to draw the image.) Next, a popup menu is created and its reference is saved to a private instance variable. Storage is allocated for an array of java.awt.MenuItem components whose array size is based on the size of the String array constructor parameter. A for() loop constructs the menu items, adds an action listener to each menu item, then adds the menu items to the popup menu. Finally, the popup menu is added to the container, and an action listener is added to the PopupButton component. This action listener, implemented via an anonymous inner class, is needed in order to respond to button clicks for the purpose of displaying the popup menu. It has no relation to the menu items' action listener.

Implementation
To use the class, extend it and provide a constructor that calls one of the superclass constructors. Since the abstract superclass doesn't provide an implementation for the java.awt.event.ActionListener interface method, actionPerformed(), a nonabstract direct descendant class, is "contractually" obligated to provide method implementations for any interfaces the abstract superclass implements. In the case of the PopupButton component this is desired, as the response to popup menu item selections should be provided in the descendant class.

I've provided a sample application (see Figure 1) that uses the PopupButton component. The sample application is made up of three classes located in PopupButtonTest.java (see Listing 2):

  • PopupButtonTest
  • PopupButtonTestFrame
  • MyPopupButton
Figure 1
Figure 1

The PopupButtonTest class simply contains a main() method and instantiates the PopupButtonTestFrame class. The PopupButtonTestFrame class extends the java.awt.Frame class and is the container for my implementation of the PopupButton class – MyPopupButton.

The MyPopupButton class contains a three-argument constructor that calls the superclass three-argument constructor and provides an implementation for the java.awt.event.ActionListener interface method actionPerformed(). If the actionPerformed() method is left out of the class definition, the compiler will generate the following error: class MyPopupButton must be declared abstract. It doesn't define void actionPerformed(java.awt.event.ActionEvent) from class PopupButton. The actionPerformed() method retrieves the "action command" (via the java.awt.event.ActionEvent class's getActionCommand() method) associated with the component that triggered the event. By default, the "action command" is the label of either a java.awt.Button or a java.awt.MenuItem component. You can use this label to perform a string comparison against the java.awt.MenuItem labels passed in the constructor to determine your course of action. For demonstration purposes I simply display the label in a console message when the PopupButton menu item is selected.

Summary
The PopupButton component is a simple yet functional component that provides the user with an intuitive interface to the popup menu's availability. This aids greatly in the usability of any application that provides popup menus.

Author Bio
Pat Paternostro is an associate partner with Tri-Com Consulting Group, Rocky Hill, Connecticut, which provides programming services for a wide variety of development tasks. He can be contacted at: [email protected]

	


Listing 1

import java.awt.*;
import java.awt.event.*;

public abstract class PopupButton extends Button implements ActionListener
{
 private PopupMenu popup;

 protected PopupButton(String[] items, Container parent)
 {
  this("",items,parent);
 }

 protected PopupButton(String label, String[] items, Container parent)
 {
  super(label + "  ");

  popup = new PopupMenu();

  MenuItem menuItems[] = new MenuItem[items.length];

  for(int i = 0; i < items.length; i++)
  {
   menuItems[i] = new MenuItem(items[i]);
   menuItems[i].addActionListener(this);
   popup.add(menuItems[i]);
  }

  parent.add(popup);

  addActionListener(new ActionListener() {
   public void actionPerformed(ActionEvent evt) {
    popup.show(PopupButton.this,0,PopupButton.this.getSize().height);}});
 }
}

Listing 2

import java.awt.event.*;
import java.awt.*;

public class PopupButtonTest {
 public static void main(String args[]) {
  new PopupButtonTestFrame();
 }
}

class PopupButtonTestFrame extends Frame {
 Panel panel = new Panel();
 MyPopupButton mpb1 = new MyPopupButton("Colors",new String[]{"Red","Green","Blue"},this);
 MyPopupButton mpb2 = new MyPopupButton("Fruit",new String[]{"Apples","-","Oranges","-","Bannanas"},this);

 PopupButtonTestFrame() {
  super();

  /* Add the window listener */
  addWindowListener(new WindowAdapter() {
   public void windowClosing(WindowEvent evt) {
    dispose(); System.exit(0);}});

  /* Size the frame */
  setSize(200,200);

  /* Center the frame */
  Dimension screenDim = Toolkit.getDefaultToolkit().getScreenSize();
  Rectangle frameDim = getBounds();
  setLocation((screenDim.width - frameDim.width) / 2,(screenDim.height - frameDim.height) / 2);

  panel.add(mpb1);
  panel.add(mpb2);
  add(BorderLayout.NORTH,panel);

  /* Show the frame */
  setVisible(true);
 }
}

class MyPopupButton extends PopupButton
{
 public MyPopupButton(String label, String[] items, Container parent)
 {
  super(label,items,parent);
 }

 public void actionPerformed(ActionEvent evt)
 {
  String command = evt.getActionCommand();
  
 
 

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.