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().
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.
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.
setTextstores a new String in the field and replaces what is showngetTextreturns whatever the field holds at the moment it is calledsetEditable(false)blocks typing by the user only- The final
setTextstill 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
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.
| Component | Sizing argument | What it controls | Typical choice |
|---|---|---|---|
| JTextField | columns | Preferred width, measured in characters | Single-line input such as a name or number |
| JTextArea | rows and columns | Preferred height (visible lines) and width | Multi-line input such as notes or a message |
| JTextArea in a BorderLayout CENTER position | Often none needed | The layout decides the size | A 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.
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.
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 likenameField.setEditable(false); nameField.setText("Saved");Why it failsThe restriction applies to typing by the user. The program can still change the text with
setText().Do this insteadUse 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 failsRows describes how many lines are visible. The user can scroll to reach additional lines.
Do this insteadThink of rows as the visible height, and expect scrolling for longer content.
Common mistake Blaming the component when keystrokes do not appear
Why it failsA 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 insteadCheck 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 failsThe margin only adds space between the component's edge and its text.
Do this insteadUse setMargin() for spacing only, and use setText() or setEditable() for content and editing behavior.
Practice: Find the Divergence
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
JTextFieldandJTextAreaare subclasses ofJTextComponent, which provides shared methods such assetText(),getText(), andsetEditable().setEditable(false)blocks only the user's typing, while the program can still change the text withsetText().requestFocusInWindow()is the call that moves typing focus to a text component, andsetMargin()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.