Experiments in Java


Session G3: Java's Abstract Windowing Toolkit, Continued

Obviously a user interface is more than buttons, windows, and labels. From a practical perspective, there are a number of other interface components. In addition, the design of a good interface involves careful consideration of the interaction paradigm, appropriate placement and design of the various interface components, and testing with actual users. But in order to build a good interface, you certainly need more components.

In particular, you need a way to get input from the user. Clearly, buttons provide one mechanism for getting input, but there are also a number of others. For example, menus also transmit information from the user to the program. Perhaps the most important input mechanism is the input field, in which users can type information.

The AWT, reviewed

As you may recall from the previous laboratory, the AWT takes a component-based approach to the construction of graphical user interfaces. You build components and place them inside of other components. Your programs will typically be based on Frame objects, which provide windows on the screen. A layout manager specifies how the objects are placed within the frame.

For example, here is how one might create a new Frame with two buttons labeled Help and Quit.

    Frame myFrame = new Frame("Example");
    Button help = new Button("Help");
    Button quit = new Button("Quit");
    myFrame.setLayout(new FlowLayout());
    myFrame.add(help);
    myFrame.add(quit);
    myFrame.pack();
    myFrame.show();

Importantly, the AWT provides an event-based control paradigm. When things happen to the various components of an interface, Java calls the appropriate method in the listener for the component. For example, we might create an object, Helper, that listens to the Help button and have it listen with

    Helper helper = new Helper(...);
    help.addActionListener(helper);

The Helper class will have the following structure.

import java.awt.*;
import java.awt.event.*;
public class Helper
  implements ActionListener {
  ...
  public actionPerformed(ActionEvent evt) {
    ...
  } // actionPerformed(ActionEvent)
} // class Helper 

One program design strategy we have used is to have the primary class listen for events on the various components it creates.

Putting it all together, here is a class that puts up a small piece of information along with Help and Quit buttons.


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

/**
 * Print ``Hello World'' using Java's AWT.  
 * Includes quit and help buttons.
 * <p>
 * The class serves as the listener for its own frame,
 * providing a windowClosing method.  It also serves as
 * a listener for the quit button.
 *
 * @author Samuel A. Rebelsky
 * @version 1.0 of February 1999
 */
public class HelpfulHelloGUI 
  extends WindowAdapter 
  implements ActionListener
{
  // +--------+--------------------------------------------------
  // | Fields |
  // +--------+

  /** The frame used for interaction. */
  protected Frame gui;
  /** The area used for output. */
  protected Label out;
  /** The help button. */
  protected Button help;
  /** The quit button. */
  protected Button quit;

  // +--------------+--------------------------------------------
  // | Constructors |
  // +--------------+

  /** Set up the frame for interaction. */
  protected HelpfulHelloGUI() {
    // Create the frame (the window).
    gui = new Frame("Greetings");
    gui.setLayout(new FlowLayout());
    gui.addWindowListener(this);

    // Create the output component. 
    out = new Label("Hello World!");

    // Create the help button.
    help = new Button("Help");
    help.addActionListener(this);

    // Create the quit button.
    quit = new Button("Quit");
    quit.addActionListener(this);

    // Add the output area to the interface.
    gui.add(out);
    gui.add(help);
    gui.add(quit);
    gui.pack();

    // And we're ready to go.
    gui.show();
  } // HelpfulHelloGUI()

  // +----------------+------------------------------------------
  // | Event Handlers |
  // +----------------+

  /** Decide what to do when the user clicks on a button. */
  public void actionPerformed(ActionEvent evt) {
    // Get the command.
    String command = evt.getActionCommand();
    // Should we quit?
    if (command.equals("Quit")) {
      gui.dispose();
      System.exit(0);
    }
    // Should we give help?
    else if (command.equals("Help")) {
      out.setText("Click quit!");
    }
  } // actionPerformed(ActionEvent)

  /** React to the closing of the window. */
  public void windowClosing(WindowEvent event) {
    gui.dispose();
    System.exit(0);
  } // windowClosing()

  // +------+----------------------------------------------------
  // | Main |
  // +------+

  /* Start the ball rolling by creating an object. */
  public static void main(String[] args) {
    new HelpfulHelloGUI();
  } // main(String[])
} // class HelpfulHelloGUI


In Experiment G3.1, you will refresh your memory of the Java AWT using this class.

Getting user input

You can generate output and observe when the user clicks on buttons. It is now time to consider other ways of getting input from the user. One particularly appropriate mechanism for getting user input is the text input field, an area on the screen in which users can type information. As you may recall from your own interactions with graphical user interfaces, one typically types information in the field and then clicks a button to key some action. (It is also possible to react as the user types in the field; we leave that as a topic for further study.) In Java's, AWT, text input fields are provided by the TextField class.

You create these objects just as you would create any other component.

    TextField myField = new TextField("Initial text");

Importantly, you can both get the contents of a text field with getText() and set the contents with setText(new-text). For example, here is some code that converts what the user typed into all upper-case letters.

    // Get the contents of the field.
    String contents = myField.getText();
    // Replace the contents of the field with the contents in
    // upper-case.
    myField.setText(contents.toUpperCase());

As an alternate example, here is a class that greets the user, based on a name typed in a field.


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

/**
 * Greet the user.
 *
 * The class serves as the listener for its own frame,
 * providing a windowClosing method.  It also serves as
 * the listener for its buttons, providing an appropriate
 * actionPerformed method.
 *
 * @author Samuel A. Rebelsky
 * @version 1.0 of February 1999
 */
public class GreetGUI 
  extends WindowAdapter 
  implements ActionListener 
{
  // +--------+--------------------------------------------------
  // | Fields |
  // +--------+

  /** The frame used for interaction. */
  protected Frame gui;
  /** The field in which the user enters a name. */
  protected TextField userName;
  /** The button the user presses. */
  protected Button greet;
  /** The area used for output. */
  protected Label out;

  // +--------------+--------------------------------------------
  // | Constructors |
  // +--------------+

  /** Set up the frame for interaction. */
  protected GreetGUI() {
    // Create the frame (the window).
    gui = new Frame("Greetings");
    gui.setLayout(new FlowLayout());
    gui.addWindowListener(this);
    // Create the entry field.  Initialized to have a number of
    // spaces so that there is room for the user to enter a name.
    userName = new TextField("          ");
    // Create the button.
    greet = new Button("Hi!");
    greet.addActionListener(this);
    // Create the output field.  Right now, we'll use it for
    // instructions.
    out = new Label("Enter your name and press the button.");
    // Add the components to the interface.
    gui.add(userName);
    gui.add(greet);
    gui.add(out);
    gui.pack();
    // And we're ready to go.
    gui.show();
  } // GreetGUI()

  // +----------------+------------------------------------------
  // | Event Handlers |
  // +----------------+

  /** React to a click on the button. */
  public void actionPerformed(ActionEvent evt) {
    // Update the output
    out.setText("Hi there " + userName.getText() + 
                ", welcome to this program.");
  } // actionPerformed(ActionEvent)

  /** React to the closing of the window. */
  public void windowClosing(WindowEvent event) {
    gui.dispose();
    System.exit(0);
  } // windowClosing()

  // +------+----------------------------------------------------
  // | Main |
  // +------+

  /* Start the ball rolling by creating an object. */
  public static void main(String[] args) {
    new GreetGUI();
  } // main(String[])
} // class GreetGUI


In Experiment G3.2, you will consider some of the details of this class. In Experiment G3.3, you will develop a class that can manipulate the contents of a text field.

Getting numeric input

What if we want to read a number rather than a string? We'll need to convert the string to a number. Fortunately, Java provides a number of library classes with methods that can be used for such conversions. These include Integer.valueOf(String str) and Double.valueOf(String str). Unfortunately, each of these methods can fail (say, for example, you used the string One or Hello). Hence, you must catch the exception that results from erroneous use of the method.

For example, here is how you might extract a double value from a field.

  String numStr = numberField.getText();
  double num = 0.0;
  try {
    num = Double.valueOf(num);
  }
  catch (Exception e) {
    // Do whatever is appropriate to handle the error.
  }

Putting it all together, here is a simple calculator that lets the user enter two integers and computes their sum.


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

/**
 * A very simple calculator.  This will read two integers from the user 
 * and display their sum.
 *
 * Uses a simple graphical user interface, rather than textual 
 * input and output.
 * 
 * The interface will present two text areas in which the user can
 * enter numbers, an ``equals'' button that the user presses to
 * request a result, and an area in which the program can write
 * output.
 * 
 * The class serves as the listener for its own frame and button,
 * providing actionPerformed and windowClosing methods.
 *
 * @author Samuel A. Rebelsky
 * @version 1.1 of February 1999
 */
public class SimpleCalc 
  extends WindowAdapter
  implements ActionListener 
{
  // +--------+--------------------------------------------------
  // | Fields |
  // +--------+

  /** The frame used for interaction. */
  protected Frame gui;
  /** The field used for input of the first value. */
  protected TextField val1;
  /** The field used for input of the second value. */
  protected TextField val2;
  /** The area used to show the plus sign. */
  protected Label plus;
  /** The area used for output. */
  protected Label out;
  /** The area used for messages (errors and others). */
  protected Label messages;
  /** The button used to tell it to compute. */
  protected Button equals;

  // +--------------+--------------------------------------------
  // | Constructors |
  // +--------------+

  /** Set up the frame for interaction. */
  protected SimpleCalc() {
    // Create the frame.
    gui = new Frame("Add");
    gui.setLayout(new FlowLayout());
    gui.addWindowListener(this);
    // Create the output field.  Leave sufficient space for output.
    out = new Label("     ");
    // Create the messages field.  Begin with instructions.
    messages = new Label("Enter two integers and click the = button.");
    // Create the input fields.  Note that we initialize them to have
    // some spaces to ensure that the layout manager gives us enough
    // space.  A little later, we'll clear them out.
    val1 = new TextField("   ");
    val2 = new TextField("   ");
    // Create the addition symbol.
    plus = new Label("+");
    // Create the button.
    equals = new Button("=");
    equals.addActionListener(this);
    // Add the various components
    gui.add(messages);
    gui.add(val1);
    gui.add(plus);
    gui.add(val2);
    gui.add(equals);
    gui.add(out);
    gui.pack();
    // Clear the text fields (see above).
    val1.setText("");
    val2.setText("");
    // And we're ready to go.
    gui.show();
  } // SimpleCalc()

  // +----------------+------------------------------------------
  // | Helper Methods |
  // +----------------+

  /** Do the simple computation. */
  public void doComputation() {
    // The two values we'll use to compute.
    int num1 = 0;
    int num2 = 0;
    // Read the strings the user entered.
    String str1 = val1.getText();
    String str2 = val2.getText();
    // Convert the first value to a number.
    try {
      num1 = Integer.valueOf(str1).intValue();
    }
    catch (Exception e) {
      // Whoops!  Bad input.  Tell the user.
      messages.setText("The left operand is not an integer!");
      // Reset the input.
      val1.setText("");
      // Give up.
      return;
    }
    // Convert the second value to a number.
    try {
      num2 = Integer.valueOf(str2).intValue();
    }
    catch (Exception e) {
      // Whoops!  Bad input.  Tell the user.
      messages.setText("The right operand is not an integer!");
      // Reset the input.
      val2.setText("");
      // Give up.
      return;
    }
    // Display the result.
    out.setText(Integer.toString(num1+num2));
  } // doComputation()

  // +----------------+------------------------------------------
  // | Event Handlers |
  // +----------------+

  /** React to a click on the button. */
  public void actionPerformed(ActionEvent evt) {
    doComputation();
  } // actionPerformed(ActionEvent)

  /** React to the closing of the window. */
  public void windowClosing(WindowEvent event) {
    gui.dispose();
    System.exit(0);
  } // windowClosing()

  // +------+----------------------------------------------------
  // | Main |
  // +------+

  /* Start the ball rolling by creating an object. */
  public static void main(String[] args) {
    new SimpleCalc();
  } // main(String[])
} // class SimpleCalc


In Experiment G3.4, you will investigate this class. In Experiment G3.5, you will update this class to compute with real numbers instead of just integers. In Experiment G3.6, you will consider the ramifications of adding a Quit button to this class.


Copyright (c) 1998 Samuel A. Rebelsky. All rights reserved.

Source text last modified Tue Oct 26 13:11:18 1999.

This page generated on Tue Oct 26 15:38:32 1999 by Siteweaver.

Contact our webmaster at rebelsky@math.grin.edu