13.6 Text Input and Output

Although Swing provides many powerful tools for handling text, we will, as usual, only look at a very small subset. Our attention will be limited to the JTextField class which allows us to read and write single lines of text.

A JTextField object appears to a user as an area in which text can (normally) be typed as it would in any single-line text editor in which text can be entered and edited (by backspacing, inserting, or deleting).

Example 1

To create a JTextField object called inField, we could write

JTextField inField = new JTextField(20); 
This would create a field whose appearance would be about wide enough to hold at least twenty of the widest characters in the current font (if the field is displayed at its preferred size).

The size specified in the constructor does not affect the number of characters that can by typed in the field, only the number that we can see at one time. If the size of a window is changed, the size of any JTextField may be changed by the layout manager. You can, in fact, leave all display size decisions up to the layout manager by using a constructor with no argument.

JTextField objects behave in many ways like JButton objects. Both generate event objects from the class ActionEvent — a JButton object generates its events when it is pressed while a JTextField object generates its events when the user presses the key while the cursor is in the text entry area. To register as a listener to JTextField events, we must do as we did for JButton events: implement the ActionListener interface by writing an actionPerformed method.

To determine which button was the source of an action event, we used the getSource method. We can also use that for JTextField objects. We can initialize the text in a JTextField by using a slightly different constructor. For example, if we wanted inField to have the text "Input", then we would constuct inField by writing
JTextField inField = new JTextField("Input", 20);

If a field is only to be used for output, we can prevent a user from using the field for input by making the field non-editable.

Example 2

To create a field that can only be used to display output, we could write

JTextField outField = new JTextField("result",10);
outField.setEditable(false); 
When displayed, outField will have an appearance that is different from fields that can be edited.

To work with the contents of a JTextField, we can convert the value to a string using the getText method. To get rid of extra white space that the user may have inserted at either the beginning or end of the input, it is a good idea to use the trim method of the String class.

Example 3

To convert the JTextField object inField to a string, we could write

String inString = inField.getText();
inString = inString.trim(); 

Taking advantage of Java’s facility for chaining methods, we usually abbreviate this to

String inString = inField.getText().trim();

If a JTextField object represents a numerical value, we can obtain that value using methods available in the wrapper classes associated with each primitive numerical type. We saw wrapper classes earlier when we used them to enclose primitive types in objects. The classes also have a number of utility methods for type conversions. The methods that we are interested in are those that convert strings to the appropriate numerical value. These are all class methods that have the form parse. The table shows the headers of these methods and the classes that contain them.

Example 4

If a JTextField object called inField represents an integer, we could extract that value by writing

int inValue = Integer.parseInt(inField.getText().trim()); 

which first converts the field to a string, then trims off any leading or trailing white space, and finally converts the trimmed string value to an integer.

If the argument of a parse... method is not a string of the appropriate form, then Java throws a NumberFormatException at execution time. If the programmer does not catch such exceptions, the program will crash.

To display values in a JTextField that is being used for output, we must make conversions in the opposite direction. As we have seen before, the String class contains an overloaded class method valueOf that can be used to convert the value of any primitive type or object to a string. Values of strings can be converted to JTextField values using the method setText, as shown in the next example.

Example 5

To display the double value result in the JTextField called outField, we could write

outField.setText(String.valueOf(result));

As an alternative to using the valueOf method to convert result to a string, we could simply concatenate result onto an empty string.

outField.setText("" + result);

By default, values are written left-justified in the display area.

To identify a JButton, we had a label that appeared on the button. To label a JTextField, we usually use some text in an area adjacent to the field. In order to do this, we can create a JLabel object that can display either text, an image, or both. A label does not react to input events. Text labels are, by default, located at the left side of their display area, centred vertically.

Example 6

To create a display area showing the text Age in years: and add it to a panel called inputPane, we could write

inputPane.add(new JLabel("Age in years:")); 

The result would be an area like the following.

The next example gives a simple illustration of both input and output of text, the use of labels, and a button to control the display of the output. The example also illustrates the use of the method pack which requests the layout manager to display components at their preferred sizes rather than at some size specified by us using setSize.

Example 7

The program shown here allows a user to supply a given name and a family name into separate JTextField objects. Whenever the user presses a button to submit the component names, the program displays the combined name in a third JTextField.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class TextFields implements ActionListener
{
   JTextField givenName;
   JTextField familyName;
   JTextField fullName;
   JButton submitButton = new JButton("Submit");

   public TextFields()
   {
      JFrame frame = new JFrame("Text Fields");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      // Create fields for I/O
      givenName = new JTextField(10);
      familyName = new JTextField(10);
      fullName = new JTextField(10);
      fullName.setEditable(false);
      // Add labelled input fields to display
      JPanel inFieldPane = new JPanel();
      inFieldPane.setLayout(new GridLayout(2,2));
      inFieldPane.add(new JLabel("Given Name"));
      inFieldPane.add(givenName);
      givenName.addActionListener(this);
      inFieldPane.add(new JLabel("Family Name"));
      inFieldPane.add(familyName);
      familyName.addActionListener(this);
      frame.add(inFieldPane,BorderLayout.NORTH);
      // Add submission button
      JPanel submitPane = new JPanel();
      submitPane.setLayout(new FlowLayout());
      submitPane.add(new JLabel("Press Button to Enter Names"));
      submitButton.addActionListener(this);
      submitPane.add(submitButton);
      frame.add(submitPane,BorderLayout.CENTER);
      // Add Output fields
      JPanel outFieldPane = new JPanel();
      outFieldPane.setLayout(new GridLayout(1,2));
      outFieldPane.add(new JLabel("Full Name"));
      outFieldPane.add(fullName);
      frame.add(outFieldPane,BorderLayout.SOUTH);
      // Display the final product
      frame.pack();
      frame.setVisible(true);
   }
   
   public void actionPerformed (ActionEvent e)
   {
      // Display full name if and only if button was pushed
      if (e.getSource() == submitButton)
      {
         String fullString = familyName.getText().trim() + ", "
                                    + givenName.getText().trim();
         fullName.setText(fullString);
      }
   }

   public static void main(String[] args)
   {
      new TextFields();
   }
} 

Here is a typical window produced by the program.

Notice that the non-editable output field is displayed differently from the editable input fields.

As we have stated many times, there are far more features in Swing than we have space to cover. For those interested in exploring further, there are many resources available. One book that provides a clear and much more thorough treatment is Learning Java by Patrick Niemeyer and Jonathan Knudsen, published by O’Reilly.

Sun’s Java web site, located at http://java.sun.com is another source of assistance. There you will find, among other things, thorough documentation of all classes in the API. At first you may find this resource to be quite intimidating as it often tells you far more than you might ever want to know but those who persist usually find it to be extremely useful.

Exercise 13.6

  1. What would you have to do to prevent a user from using a JTextField called result for input?
  2. What changes would be needed in the actionPerformed method of Example 7 in order to have the full name updated every time either the given name or the family name was updated and the <enter> key was pressed?
  3. Write a program that displays a window showing a labelled text input field at the bottom of the screen and a large blank area above this. The label should prompt the user to enter a positive integer. After the value is entered and the <enter> key is pressed, the program should draw that number of small solid circular regions in the window. The circular regions should be located at randomly chosen points in the window and should be drawn in randomly selected colours.
  4. Write a program that will produce a window that can be used as a simple calculator. The window should have two input fields and one output field plus buttons for each of the operations +, -, *, and /. The illustration shows the window that would be produced by calculating 7 × 5.