Concepts / Handling User Input in Swing Components

Handling User Input in Swing Components

JTextField and JTextArea are both subclasses of the abstract class JTextComponent, which provides their shared behavior such as setText(), getText(), and setEditable().

  • Programming

A Form That Does Not Behave as Expected

Imagine a form with two entry boxes. You expect the cursor to be waiting in the second box, but the user types and nothing appears there, or the text sits jammed against the border of the box. Problems like these almost always come from a small number of calls on the text component itself. This article works through those calls in the order a program would make them, so you can predict what each call changes and find the exact point where a result stops matching your expectation.

Keep one question in mind as you read: at which line does the component's state stop matching what you expected? Each section below adds one piece of that picture, and the final trace puts them together.

The Shared Parent: JTextComponent

JTextField and JTextArea are both components that hold text the user can edit. A JTextField holds a single line of text. A JTextArea can hold multiple lines. Both classes are subclasses of an abstract class named JTextComponent, and that parent class defines the properties they have in common. Because the shared behavior lives in one place, the methods you learn for one text component apply to the other as well.

JTextComponentsetText, getText,setEditableJTextFieldsingle line, sized bycolumnsJTextAreamultiple lines, rows andcolumnsextendsextends
Which class contains the shared methods like setText(), getText(), and setEditable(), and which classes inherit them?

The diagram shows the relationship that matters for this article. Methods such as setText() and getText() are shared through the parent. Constructors are different: each subclass declares its own constructors, and those constructors take parameters that suit that subclass. A JTextField is described by a number of characters, while a JTextArea is described by rows and columns. Keep this split in mind when you choose a constructor.

Reading and Changing Contents

Two methods handle the contents of a text component. The setText() method takes a String parameter and changes the text that is displayed in the component. The getText() method takes no parameters and returns the contents as a String. Calling setText() replaces what is shown, and calling getText() later returns whatever the component holds at that moment.

The setEditable() method controls whether the user can change the text. Calling setEditable(false) makes the component read-only, so the user can still read the text it contains but cannot edit it. Calling setEditable(true) makes it editable again. The method only controls the user's ability to edit. Your program can still change the text with setText() while the component is read-only.

java
Notes on the code
  • setText stores a new String in the field and replaces what is shown
  • getText returns whatever the field holds at the moment it is called
  • setEditable(false) blocks typing by the user only
  • The final setText still succeeds, because the program is the caller

Why a Read-Only Field Can Still Change

What do you think happens?

A field has been set to setEditable(false). The program then calls setText with a new value. Does the new text appear?

Reveal answer
Answer:

Yes. The new text appears.

The restriction applies to typing by the user, not to calls made by the program. A read-only component cannot be typed into, but setText() can still change what it displays.

Choosing a Constructor: Columns and Rows

The rows parameter specifies how many lines of text should be visible in the text area. It determines the preferred height of the text area, just as columns determines the preferred width of a text field. The text area can still hold more lines than are visible, because the user can scroll to reveal lines that are not currently on screen. So rows describes what is visible, not the total amount of text the component can contain. The same reasoning applies to columns for a text field.

ComponentSizing argumentWhat it controlsTypical choice
JTextFieldcolumnsPreferred width, measured in charactersSingle-line input such as a name or number
JTextArearows and columnsPreferred height (visible lines) and widthMulti-line input such as notes or a message
JTextArea in a BorderLayout CENTER positionOften none neededThe layout decides the sizeA resizable window where the text area should fill the space

Sizing arguments for the two text components

A JTextArea is commonly placed in the CENTER position of a BorderLayout. In that position it expands to fill all the space available in the center area of the container. Specifying rows and columns is then less useful, because the layout decides the size. This is a practical difference between a text area in a fixed-size window and one placed in a resizable layout.

Moving Focus and Adding Margins

A text component accepts typing only when it has the input focus. The user can give a text component the input focus by clicking it with the mouse. Sometimes the program should move focus itself. For instance, when the program finds an error in what the user entered, it can give focus to the field that holds the error so the user sees where the problem is and can start typing the correction right away.

The program requests focus by calling requestFocusInWindow() on the text component. This is the single call that moves focus to a text field programmatically. If the text component does not appear to receive keystrokes, check whether this request was made, and whether it was made on the component you intended, before assuming the component itself is broken.

By default, there is no space between the text in a text component and the edge of the component. This usually does not look very good. The setMargin() method adds blank space between the edge of the component and its text. The method takes a parameter of type java.awt.Insets. An Insets object holds four integer values that specify the margins on the top, left, bottom, and right edges of the component, in that order.

java
Notes on the code
  • Insets(top, left, bottom, right) gives a uniform 5-pixel-style gap in this example
  • The margin changes only the space inside the edge, not the text or editability
  • requestFocusInWindow() asks for keyboard focus on this field

In this example the same margin of 5 is used on all four sides, which gives a uniform gap around the text. Because each side is a separate argument, you can also make the gaps unequal. The margin changes only the space inside the component's edge. It does not change what the text says or whether the component is editable.

Tracing Where Behavior Diverges

Now follow the calls in the order a program makes them. The sequence below mixes program calls, the window appearing, and a user keystroke. Read it from top to bottom and ask at each step whether the field's state still matches what the code requested.

Programmakes the callsText fieldJTextFieldWindowshown on screenUsertypes on keyboard1. setEditable(false)2. setText(Total)3. requestFocusInWindow()4. window becomes visible5. user types a key
Follow the calls in order and mark the step where the field stops matching the request. The focus request happens before the window is on screen, which is the first place to check.

Walk the trace step by step. Step 1 makes the field read-only, which blocks typing but not later program changes. Step 2 replaces the displayed text, and that still succeeds because the program is the caller. Step 3 asks for focus, but the window is not yet on screen at that point, because step 4 comes after it. Step 5 is where the user's keystroke arrives. If the typed text does not land where the code seemed to point, step 3 is the first place to check: the focus request was made before the window existed on screen, and you should confirm the request reached the component you intended.

Mistakes Beginners Make

  • Common mistake

    Assuming setEditable(false) also stops the program from changing the text

    What it looks like
    nameField.setEditable(false); nameField.setText("Saved");
    Why it fails

    The restriction applies to typing by the user. The program can still change the text with setText().

    Do this instead

    Use setEditable(false) to block user edits, and expect setText() calls to still update what is displayed.

  • Common mistake

    Treating rows as the total number of lines the text area can hold

    Why it fails

    Rows describes how many lines are visible. The user can scroll to reach additional lines.

    Do this instead

    Think of rows as the visible height, and expect scrolling for longer content.

  • Common mistake

    Blaming the component when keystrokes do not appear

    Why it fails

    A text component accepts typing only when it has the input focus, so the focus request may have been missing or aimed at the wrong component.

    Do this instead

    Check whether requestFocusInWindow() was called, on which component, and at what point in the sequence.

  • Common mistake

    Expecting setMargin() to change the text content or editability

    Why it fails

    The margin only adds space between the component's edge and its text.

    Do this instead

    Use setMargin() for spacing only, and use setText() or setEditable() for content and editing behavior.

Practice: Find the Divergence

MEDIUM

A program builds a form with a read-only JTextArea for displaying a status message and an editable JTextField for a user's name. The name field should have focus when the window opens, but the user reports that typing does nothing in the name field. List the calls in the order the program makes them, and identify the first call where the component's state may stop matching what the code requested.

Hints
  • Start by listing the calls in the order they appear in the code, then add the window appearing and the user typing.
  • Ask which call is supposed to give the name field focus, and whether that call was made on the name field.
  • Remember that setEditable(false) on the text area does not affect the name field.

Summary of the Key Calls

JTextField and JTextArea share their behavior through the abstract class JTextComponent, so setText(), getText(), and setEditable() work the same way on both.

At a glance

  • JTextField and JTextArea are subclasses of JTextComponent, which provides shared methods such as setText(), getText(), and setEditable().
  • setEditable(false) blocks only the user's typing, while the program can still change the text with setText().
  • requestFocusInWindow() is the call that moves typing focus to a text component, and setMargin() with an Insets object adds space between the edge and the text.
  • When behavior seems wrong, trace the calls in order and find the first step where the component's state stops matching what the code requested.