|
|
Using the JFC/Swing Packages |
Text fields display a single line of selectable, optionally editable text. Generally you use theJTextFieldclass to provide text fields. If you need to provide a password field -- an editable text field that doesn't show the characters the user types -- use the
JPasswordFieldclass instead. This section discusses both text fields and password fields.If you want a text field that also provides a menu of strings to choose from, consider using an editable combo box. If you need to obtain more than one line of input from the user, then you should use one of the classes that implements a general-purpose text area.
The applet below is the Swing version of an AWT example program described in How to Use TextAreas and TextFields
.
The applet displays a basic text field and a text area. The text field is editable; the text area isn't. When the user presses Return in the text field, the field fires an action event
Note: Because the preceding applet runs using Java Plug-in 1.1.1, it is a Swing 1.0.3 version of the applet. To run the Swing 1.1 Beta 3 version of the applet, you can use the JDK Applet Viewer to viewTextDemo.html, specifyingswing.jarin the Applet Viewer's class path. For more information about running applets, refer to About Our Examples.. The applet reacts to the event by copying the text field's contents to the text area, and then selecting all the text in the text field.
You can find the source for the program in
TextDemo.java. The corresponding HTML file,TextDemo.html, contains an<APPLET>tag for running the applet. Here's the code fromTextDemothat creates the text field in the applet:ThetextField = new JTextField(20); ... getContentPane().add(textField); ... textField.addActionListener(this);JTextFieldconstructor takes an integer parameter indicating the desired number of columns in the text field. The next lines of code add the text field to the applet's content pane, and then register the applet as an action listener for the text field. Here's theactionPerformedmethod that handles action events from the text field:This example illustrates using a basic, off-the-shelf text field for entering textual data and performing some task when the text field fires an action event. This is sufficient for many programs. Other programs, however, need more advanced behavior. As a subclass ofpublic void actionPerformed(ActionEvent evt) { String text = textField.getText(); textArea.append(text + newline); textField.selectAll(); }JTextComponent,
JTextFieldcan be configured and customized. One common customization is to provide a text field whose contents are validated. This topic and others are covered in the sections that follow:
- Creating a Validated Text Field
- Using a Document Listener on a Text Field
- Laying Out Label/Text Field Pairs
- Providing a Password Field
- The Text Field API
- Examples that Use Text Fields
Creating a Validated Field
Many programs require users to enter textual data of a certain type or format. For example, a program might provide a text field for entering a date, a decimal number, or a phone number. The contents of such a text field must be validated before being used for any purpose. A text field can be action-validated or keystroke-validated.The data in an action-validated field is checked each time the field fires an action event (each time the user presses the return key). An action-validated field might, at any given point in time, contain invalid data. However, the data is validated before it's used for anything. To create an action-validated field, provide an action listener for your field and implement its
actionPerformedmethod as follows:The data in a keystroke-validated field is checked each time the field changes. A field that is keystroke-validated can never contain invalid data because every keystroke that causes the data to be invalid is rejected. To create a keystroke-validated text field you need to provide a custom document for your text field. If you aren't familiar with documents yet, see Working With a Text Component's Document.
- Use
getTextto get the contents of the text field.- Evaluate the value returned by
getText.- If the value is valid, do whatever task or calculation is required. If the value is invalid, report an error and return without performing a task or calculation.
The application shown in the following figure has four keystroke-validated text fields. The user enters loan information into the first three text fields. Each time the user types a character, the program validates the input and updates the result in the fourth text field.
Warning: Do not use a document listener for keystroke validation. By the time a document listener has been notified of a change, it's too late, the change has already taken place. See the last couple of paragraphs in Listening for Changes on a Document for more information.
[PENDING: retake this snapshot with the smaller loan amount.]The Years field is an instance of
Try this:
- Compile and run the application. The source file is
TextFieldDemo.java. You will also needWholeNumberField.java,DecimalField.java, andFormattedDocument.java.
See Getting Started with Swing if you need help.- Enter information into the text fields and see the results.
If attempt to you enter invalid data, the program beeps.- Try to type into the fourth text field.
You can't because it isn't editable. However, you can select the text.- Resize the window.
Note how the labels and text fields remain aligned. Laying Out Label/Text Field Pairs talks more about this feature of the program.
WholeNumberField.java, which is a subclass ofJTextField. By overriding thecreateDefaultModelmethod,WholeNumberFieldestablishes a customDocumentsubclass -- an instance ofWholeNumberDocument-- as the document for eachWholeNumberFieldcreated:Here's the implementation ofprotected Document createDefaultModel() { return new WholeNumberDocument(); }WholeNumberDocument:This class overrides theprotected class WholeNumberDocument extends PlainDocument { public void insertString(int offs, String str, AttributeSet a) throws BadLocationException { char[] source = str.toCharArray(); char[] result = new char[source.length]; int j = 0; for (int i = 0; i < result.length; i++) { if (Character.isDigit(source[i])) result[j++] = source[i]; else { toolkit.beep(); System.err.println("insertString: " + source[i]); } } super.insertString(offs, new String(result, 0, j), a); } }insertStringmethod which is called every time any string or character is about to be inserted into the document.WholeNumberDocument's implementation ofinsertStringevaluates each character to be inserted into the text field. If the character is a digit, the document allows it to be inserted. Otherwise, the method beeps and prints an error message. ThusWholeNumberDocumentallows the numbers in the range 0, 1, 2, ...An interesting implementation detail is that our custom document class does not have to override the
removemethod. Theremovemethod is called each time a character or group of characters is removed from the text field. Because removing a digit from an integer cannot produce an invalid result, this class does not pay attention to removals.The other two input fields in the example, as well as the uneditable Monthly Payment field, are all instances of
DecimalField.java, a customJTextFieldsubclass.DecimalFielduses a custom document,FormattedDocument, that allows only data of a particular format to be entered.
FormattedDocumenthas no knowledge of the actual format of its content. Instead,FormattedDocumentrelies on a format, an instance of a subclass ofFormat, to accept or reject a proposed change. The text field that uses the
FormattedDocumentmust specify which format theFormattedDocumentuses.The Loan Amount and Monthly Payment text fields use a
NumberFormatobject created like this:
The following code creates the APR text field's format:moneyFormat = NumberFormat.getCurrencyInstance(Locale.US); ((DecimalFormat)moneyFormat).setPositiveSuffix(" ");As the code shows, the same class (percentFormat = NumberFormat.getPercentInstance(Locale.US); percentFormat.setMinimumFractionDigits(3);NumberFormat) can support a currency format and a percentage format. Furthermore,Formatand its subclasses are locale-sensitive, so decimal field can be made to support formats for other countries and regions. Refer to Formattingin the internationalization trail for detailed information about formats.
Here is
FormattedDocument's implementation ofinsertString:The method uses the format to parse the result of the proposed insertion. If the result is properly formatted, this method calls its superclass'spublic void insertString(int offs, String str, AttributeSet a) throws BadLocationException { String currentText = getText(0, getLength()); String beforeOffset = currentText.substring(0, offs); String afterOffset = currentText.substring(offs, currentText.length()); String proposedResult = beforeOffset + str + afterOffset; try { format.parseObject(proposedResult); super.insertString(offs, str, a); } catch (ParseException e) { Toolkit.getDefaultToolkit().beep(); System.err.println("insertString: could not parse: " + proposedResult); } }insertmethod to do the insertion. If the result is not properly formatted, the computer beeps.In addition to overriding
insertString,FormattedDocumentalso overrides theremovemethod. Recall that theremovemethod is called each time a character or group of characters is to be removed from the document.Thepublic void remove(int offs, int len) throws BadLocationException { String currentText = getText(0, getLength()); String beforeOffset = currentText.substring(0, offs); String afterOffset = currentText.substring(len + offs, currentText.length()); String proposedResult = beforeOffset + afterOffset; try { if (proposedResult.length() != 0) format.parseObject(proposedResult); super.remove(offs, len); } catch (ParseException e) { Toolkit.getDefaultToolkit().beep(); System.err.println("remove: could not parse: " + proposedResult); } }FormattedDocumentimplementation of theremovemethod is similar to its implementation of theinsertStringmethod. The format parses the result of the proposed change and performs the removal or not, depending on whether the result is valid.Using a Document Listener on a Text Field
So, if you can't use a document listener for field validation, what can you use it for? Use it to listen to, but not interfere with, changes to the document's content. The loan calculator uses the following document listener to update the monthly payment after every change:This is an appropriate use of a document listener.class MyDocumentListener implements DocumentListener { public void insertUpdate(DocumentEvent e) { update(e); } public void removeUpdate(DocumentEvent e) { update(e); } public void changedUpdate(DocumentEvent e) { // we won't ever get this with a PlainDocument } private void update(DocumentEvent e) { Document whatsup = e.getDocument(); if (whatsup.getProperty("name").equals("amount")) amount = amountField.getValue(); else if (whatsup.getProperty("name").equals("rate")) rate = rateField.getValue(); else if (whatsup.getProperty("name").equals("numPeriods")) numPeriods = numPeriodsField.getValue(); payment = computePayment(amount, rate, numPeriods); paymentField.setValue(payment); } }For general information about document listeners refer to How to Write a Document Listener.
Laying Out Label/Text Field Pairs
Rows of label and text field pairs such as those found in the loan calculator are quite common on preference panels and panels that implement forms. Here's the code that lays out the label and text field pairs.You may be surprised to find that the labels are laid out without reference to the text fields and, in fact, are in a different panel, yet align correctly with them. This is a side effect of the layout managers used by the program.. . . //Layout the labels in a panel JPanel labelPane = new JPanel(); labelPane.setLayout(new GridLayout(0, 1)); labelPane.add(amountLabel); labelPane.add(rateLabel); labelPane.add(numPeriodsLabel); labelPane.add(paymentLabel); //Layout the text fields in a panel JPanel fieldPane = new JPanel(); fieldPane.setLayout(new GridLayout(0, 1)); fieldPane.add(amountField); fieldPane.add(rateField); fieldPane.add(numPeriodsField); fieldPane.add(paymentField); //Put the panels in another panel, labels on left, //text fields on right JPanel contentPane = new JPanel(); contentPane.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); contentPane.setLayout(new BorderLayout()); contentPane.add(labelPane); contentPane.add(fieldPane, "East"); setContentPane(contentPane); . . .As the diagram illustrates, the program uses twoGridLayoutmanagers, one to lay out the column of labels and one for the column of text fields.GridLayoutguarantees that all of its components are the same size, so all of the text fields are the same height and all of the labels are the same height.To get the labels and the text fields to align, the program uses a third layout manager, a
BorderLayout. With just two components at East and Center,BorderLayoutguarantees the columns are the same height. Thus, the labels and the text fields align.Another way to get labels and text fields to align is to use the AWT's most flexible, complex layout manager:
GridBagLayout.
Providing a Password Field
Swing provides theJPasswordFieldclass, a subclass of
JTextField, to use in place of a text field when the text entered by a user is a password. For security reasons, a password field doesn't show the characters the user types. Instead the field displays another character such as an asterisk '*'.The
PasswordDemoexample described in Using the SwingWorker Class uses aJPasswordField. The program brings up a small window to prompt the user to type in a password:Here's the code fromPasswordDemothat creates and sets up the password field.The argument passed into theJPasswordField password = new JPasswordField(10); password.setEchoChar('#'); password.addActionListener(showSwingWorkerDialog);JPasswordFieldconstructor indicates that the field should be 10 columns wide. By default a password field displays an asterisk '*' for each character typed. The call tosetEchoCharchanges it to a pound sign '#'. Finally, the code adds an action listener to the password field. The action listener'sactionPerformedmethod gets the password typed by the user and verifies it with this code:This method uses the password field'spublic void actionPerformed(ActionEvent e) { JPasswordField input = (JPasswordField)e.getSource(); char[] password = input.getPassword(); if (isPasswordCorrect(password)) JOptionPane.showMessageDialog(f, worker.get()); else JOptionPane.showMessageDialog(f, new JLabel("Invalid password.")); }getPasswordmethod to get the contents of the field. Note thatgetPasswordreturns a character array. Password information should not be stored or passed around in strings because strings are not secure. So don't [PENDING: or you can't] usegetTextorsetTexton a password field. Instead usegetPasswordorsetPasswordbecause these methods use character arrays instead of strings.
Note: ThegetPasswordmethod and its companion setter,setPassword, did not exist in Swing 1.0.3 and earlier releases. In these releases, usegetTextandsetText. Your program should store any password as a character array, and convert the value to a temporary string when calling eithergetTextorsetText.
The Text Field API
The following tables list the commonly usedJTextFieldconstructors and methods. Other methods you're likely to call are defined by theJComponentand
Componentclasses. They include
Component'ssetForeground,setBackground, andsetFontmethods. [CHECK: is that right? any other particularly useful Component/JComponent methods?] [Link to JComponent and Component discussions.]Additionally, you might want to call some of the methods defined in
JTextField's parent class,JTextComponent. Refer to the API tables in the section on text components: The Text API.The API for using text fields falls into three categories:
- Setting or Getting the Text Field's Contents
- Fine Tuning the Text Field's Appearance
- Implementing the Text Field's Functionality
Setting or Getting the Text Field's Contents Method or Constructor Purpose
JTextField()
JTextField(String)
JTextField(String, int)
JTextField(int)
JTextField(Document, String, int)Create a JTextFieldinstance, initializing it to contain the specified text. Theintargument sets the number of columns. This is used to compute the component's preferred width and may not be the actual number of columns displayed [CHECK].void setText(String)
String getText()Set or get the text displayed by the text field.
Fine Tuning the Text Field's Appearance Method or Constructor Purpose void setEditable(boolean)
boolean isEditable()Set or get whether the user can edit the text in the text field. void setForeground(Color)
Color getForeground()Set or get the color of the text within the text field. void setBackground(Color);
Color getBackground()Set or get the background color of the text field. void setFont(Font);
Font getFont()Set or get the font used by the text field. void setColumns(int);
int getColumns()Set or get the number of columns displayed by the text field. int getColumnWidth()Get the width of the text field's columns. This value is extablished implicitly by the font. void setHorizontalAlignment(int);
int getHorizontalAlignment()Set or get how the text is aligned horizontally within its area. You can use JTextField.LEFT,JTextField.CENTER, andJTextField.RIGHTfor arguments.
Implementing the Text Field's Functionality Method or Constructor Purpose void addActionListener(ActionListener)
void removeActionListener(ActionListener)Add or remove an action listener. Document createDefaultModel()Override this method to provide the text field with a custom document. Examples that Use Text Fields
This table shows the examples that useJTextFieldand where those examples are described.
Example Where Described Notes TextDemo.javaThis page Uses a text field with an action listener. TextFieldDemo.javaThis page Implements two different keystroke-validated fields. PasswordDemo.javaThis page and Using the SwingWorkerClass Uses a password field. ControlPane.java,Utilities.javaLet's Play Uses a grid bag layout to align labels with text fields. See the addParameterRowmethod inUtilities.java. Part of the BINGO player application.CustomDialog.javaHow to Make Dialogs Includes a text field whose value is checked. Part of DialogDemo (under the More Dialogs tab).
|
|
Using the JFC/Swing Packages |