Contents:
Text Component
TextField
TextArea
Extending TextField
There are two fundamental ways for users to provide input to a program: they can type on a keyboard, or they can select something (a button, a menu item, etc.) using a mouse. When you want a user to provide input to your program, you can display a list of choices to choose from or allow the user to interact with your program by typing with the keyboard. Presenting choices to the user is covered in Chapter 9, Pick Me. As far as keyboard input goes, the java.awt package provides two options. The TextField class is a single line input field, while the TextArea class is a multiline one. Both TextField and TextArea are subclasses of the class TextComponent, which contains all the common functionality of the two. TextComponent is a subclass of Component, which is a subclass of Object. So you inherit all of these methods when you work with either TextField or TextArea.
By themselves, the TextField and TextArea classes are fairly robust. However, in order to reduce duplication between the classes, they both inherit a number of methods from the TextComponent class. The constructor for TextComponent is package private, so you cannot create an instance of it yourself. Some of the activities shared by TextField and TextArea through the TextComponent methods include setting the text, getting the text, selecting the text, and making it read-only.
Both TextField and TextArea contain a set of characters whose content determines the current value of the TextComponent. The following methods are usually called in response to an external event.
The getText() method returns the current contents of the TextComponent as a String object.
The setText() method sets the content of the TextComponent to text. If the TextComponent is a TextArea, you can embed newline characters (\n) in the text so that it will appear on multiple lines.
Users can select text in TextComponents by pressing a mouse button at a starting point and dragging the cursor across the text. The selected text is displayed in reverse video. Only one block of text can be selected at any given time within a single TextComponent. Once selected, this block could be used to provide the user with some text-related operation such as cut and paste (on a PopupMenu).
Depending on the platform, you might or might not be able to get selected text when a TextComponent does not have the input focus. In general, the component with selected text must have input focus in order for you to retrieve any information about the selection. However, in some environments, the text remains selected when the component no longer has the input focus.
The getSelectionStart() method returns the initial position of any selected text. The position can be considered the number of characters preceding the first selected character. If there is no selected text, getSelectionStart() returns the current cursor position. If the start of the selection is at beginning of the text, the return value is 0.
The getSelectionEnd() method returns the ending cursor position of any selected text--that is, the number of characters preceding the end of the selection. If there is no selected text, getSelectionEnd() returns the current cursor position.
The getSelectedText() method returns the currently selected text of the TextComponent as a String. If nothing is selected, getSelectedText() returns an empty String, not null.
The setSelectionStart() method changes the beginning of the current selection to position. If position is after getSelectionEnd(), the cursor position moves to getSelectionEnd(), and nothing is selected.
The setSelectionEnd() method changes the end of the current selection to position. If position is before getSelectionStart(), the cursor position moves to position, and nothing is selected.
The select() method selects the text in the TextComponent from selectionStart to selectionEnd. If selectionStart is after selectionEnd, the cursor position moves to selectionEnd. Some platforms allow you to use select() to ensure that a particular position is visible on the screen.
The selectAll() method selects all the text in the TextComponent. It basically does a select() call with a selectionStart position of 0 and a selectionEnd position of the length of the contents.
Introduced in Java 1.1 is the ability to set and get the current insertion position within the text object.
The getCaretPosition() method returns the current text insertion position (often called the "cursor") of the TextComponent. You can use this position to paste text from the clipboard with the java.awt.datatransfer package described in Chapter 16, Data Transfer.
The setCaretPosition() method moves the current text insertion location of the TextComponent to position. If the TextComponent does not have a peer yet, setCaretPosition() throws the IllegalComponentStateException run-time exception. If position < 0, this method throws the run-time exception IllegalArgumentException. If position is too big, the text insertion point is positioned at the end.
Prior to Java version 1.1, the insertion location was usually set by calling select(position, position).
By default, a TextComponent is editable. If a user types while the component has input focus, its contents will change. A TextComponent can also be used in an output-only (read-only) mode.
The setEditable() method allows you to change the current editable state of the TextComponent to state. true means the component is editable; false means read-only.
The isEditable() method tells you if the TextComponent is editable (true) or read-only (false).
The following listing is an applet that toggles the editable status for a TextArea and sets a label to show the current status. As you can see in Figure 8.1, platforms can change the display characteristics of the TextComponent to reflect whether the component is editable. (Windows 95 darkens the background. Motif and Windows NT do nothing.)
import java.awt.*; import java.applet.*; public class readonly extends Applet { TextArea area; Label label; public void init () { setLayout (new BorderLayout (10, 10)); add ("South", new Button ("toggleState")); add ("Center", area = new TextArea ("Help Me", 5, 10)); add ("North", label = new Label ("Editable", Label.CENTER)); } public boolean action (Event e, Object o) { if (e.target instanceof Button) { if ("toggleState".equals(o)) { area.setEditable (!area.isEditable ()); label.setText ((area.isEditable () ? "Editable" : "Read-only")); return true; } } return false; } }
The removeNotify() method destroys the peer of the TextComponent and removes it from the screen. Prior to the TextComponent peer's destruction, the current state is saved so that a subsequent call to addNotify() will put it back. (TextArea and TextField each have their own addNotify() methods.) These methods deal with the peer object, which hides the native platform's implementation of the component. If you override this method for a specific TextComponent, put in the customizations for your new class first, and call super.removeNotify() last.
When you call the toString() method of a TextField or TextArea, the default toString() method of Component is called. This in turn calls paramString(), which builds up the string to display. The TextComponent level potentially adds four items. The first is the current contents of the TextComponent (getText()). If the text is editable, paramString() adds the word editable to the string. The last two items included are the current selection range (getSelectionStart() and getSelectionEnd()).
With the 1.1 event model, you can register listeners for text events. A text event occurs when the component's content changes, either because the user typed something or because the program called a method like setText(). Listeners are registered with the addTextListener() method. When the content changes, the TextListener.textValueChanges() method is called through the protected method processTextEvent(). There is no equivalent to TextEvent in Java 1.0; you would have to direct keyboard changes and all programmatic changes to a common method yourself.
In addition to TextEvent listeners, Key, mouse, and focus listeners are registered through the Component methods addKeyListener(), addMouseListener(), addMouseMotionListener(), and addFocusListener(), respectively. Listeners and 1.1 event handling
The addTextListener() method registers listener as an object interested in receiving notifications when a TextEvent passes through the EventQueue with this TextComponent as its target. The listener.textValueChanged() method is called when these events occur. Multiple listeners can be registered.
The following applet, text13, demonstrates how to use a TextListener to handle the events that occur when a TextField is changed. Whenever the user types into the TextField, a TextEvent is delivered to the textValueChanged() method, which prints a message on the Java console. The applet includes a button that, when pressed, modifies the text field tf by calling setText(). These changes also generate a TextEvent.
// Java 1.1 only import java.applet.*; import java.awt.*; import java.awt.event.*; class TextFieldSetter implements ActionListener { TextField tf; TextFieldSetter (TextField tf) { this.tf = tf; } public void actionPerformed(ActionEvent e) { if (e.getActionCommand().equals ("Set")) { tf.setText ("Hello"); } } } public class text13 extends Applet implements TextListener { TextField tf; int i=0; public void init () { Button b; tf = new TextField ("Help Text", 20); add (tf); tf.addTextListener (this); add (b = new Button ("Set")); b.addActionListener (new TextFieldSetter (tf)); } public void textValueChanged(TextEvent e) { System.out.println (++i + ": " + e); } }
The removeTextListener() method removes listener as an interested listener. If listener is not registered, nothing happens.
The processEvent() method receives all AWTEvents with this TextComponent as its target. processEvent() then passes the events along to any listeners for processing. When you subclass TextComponent, overriding processEvent() allows you to process all events yourself, before sending them to any listeners. In a way, overriding processEvent() is like overriding handleEvent() using the 1.0 event model.
If you override processEvent(), remember to call super.processEvent(e) last to ensure that regular event processing can occur. If you want to process your own events, it's a good idea to call enableEvents() (inherited from Component) to ensure that events are delivered even in the absence of registered listeners.
The processTextEvent() method receives all TextEvents with this TextComponent as its target. processTextEvent() then passes them along to any listeners for processing. When you subclass TextField or TextArea, overriding the processTextEvent() method allows you to process all text events yourself, before sending them to any listeners. There is no equivalent to processTextEvent() within the 1.0 event model.
If you override processTextEvent(), remember to call the method super.processTextEvent(e) last to ensure that regular event processing can occur. If you want to process your own events, it's a good idea to call enableEvents() (inherited from Component) to ensure that events are delivered even in the absence of registered listeners.