![]() | Documentation Contents |
This document outlines the Swing implementation of formatted text fields. Formatted text fields provide a way for developers to specify the legal set of characters that can be input into a text component. This document is arranged in the following sections:
JFormattedTextField
will allow formatting of dates, numbers, Strings and arbitrary
Objects. JFormattedTextField will rely on the java.text.Format
classes to handle formatting of dates and numbers. To create a
JFormattedTextField to input dates in the current
locale-specific format:
new JFormattedTextField(new Date());
If you need to display the dates in a specific format, you can
use one of the SimpleDateFormat
constructors:
new JFormattedTextField(new SimpleDateFormat("MM/dd/yy"));
Numbers will be handled by an instance of java.text.NumberFormat.
The following shows several ways to create a
JFormattedTextField to edit numbers.
new JFormattedTextField(new Number(1000));
new JFormattedTextField(new DecimalFormat("#,###"));
new JFormattedTextField(new DecimalFormat("0.###E0"));
JFormattedTextField will also support editing of
strings given a mask that specifies what the legal characters are
at a given character position. To create a
JFormattedTextField to edit US phone numbers the
following could be used:
new JFormattedTextField(new MaskFormatter("(###) ###-####"));
JFormattedTextField itself exposes a minimal amount
of API in addition to that of its super class,
JTextField. In its simplest terms,
JFormattedTextField can be thought of as a
JTextField with an additional value property (of type
Object) and an object to handle the formatting (instance of
AbstractFormatter).
As the value property is of type Object, it is
necessary for the developer to cast the return type based on how
the JFormattedTextField has been configured. The
following shows a typical scenario of using a
JFormattedTextField with dates:
JFormattedTextField ftf = new JFormattedTextField(); ftf.setValue(new Date()); ... Date date = (Date)ftf.getValue();
A typical session for editing numbers looks like:
JFormattedTextField ftf = new JFormattedTextField(); ftf.setValue(new Integer(1000)); ... int intValue = ((Number)ftf.getValue()).intValue();
Constraining the input into a text component previously required
creating a subclass of Document. This is a rather
heavy operation for such a simple, and common, usage. To make this
task easier, we have created a class, DocumentFilter,
that can be plugged into a Document (Document
is an interface, which has not changed, instead AbstractDocument
now has a setter/getter for a DocumentFilter, and a
property is set for Documents that do not descend from
AbstractDocument so that others can support
DocumentFilter should they want to). When a
Document with a DocumentFilter is
messaged to remove or insert content, the Document
invokes the corresponding method on the
DocumentFilter. It is the
DocumentFilter's responsibility to issue a callback if
the operation should proceed. In this manner the
DocumentFilter has total control over how the
Document can be mutated. DocumentFilter
is defined by:
public void remove(FilterBypass fb, int offset, int length) throws BadLocationException; public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException; public void replace(FilterBypass fb, int offset, int length, String string, AttributeSet attr) throws BadLocationException;
If the DocumentFilter wants to mutate the
Document from inside the remove or
insertString methods, it should either invoke
super's implementation, or invoke the method on the
FilterBypass. Invoking the method on
super or FilterBypass provides a way to
circumvent the filter so that the caller doesn't get stuck in stack
recursion. The DocumentFilter is not limited to only
invoking one method back on the FilterBypass. It can
invoke any of the methods exposed by FilterBypass, and
can invoke them as many times as it wishes (within the scope of one
of DocumentFilter's methods).
FilterBypass is defined by:
public abstract Document getDocument(); public abstract void remove(int offset, int length) throws BadLocationException; public abstract void insertString(int offset, String string, AttributeSet attr) throws BadLocationException; public abstract void replace(int offset, int length, String string, AttributeSet attr) throws BadLocationException;
The following example illustrates creating a
DocumentFilter that maps lower case to upper case
letters:
DocumentFilter upperDF = new DocumentFilter() {
public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException {
super.insertString(fb, offset, string.toUpperCase(), attr);
}
public void replace(FilterBypass fb, int offset, int length, String string, AttributeSet attr) throws BadLocationException {
if (string != null) {
string = text.toUpperCase();
}
super.replace(fb, offset, length, string, attr);
}
};
Similar to DocumentFilter, a new class, NavigationFilter,
allows for filtering where the selection can be placed.
NavigationFilter is called by the navigation actions
(such as left, right, center) to determine the next position to
place the selection from a given position.
NavigationFilter is a property on JTextComponent,
and is defined by:
public void setDot(FilterBypass fb, int dot, Position.Bias bias);
public void moveDot(FilterBypass fb, int dot, Position.Bias bias);
public int getNextVisualPositionFrom(JTextComponent text, int pos, Position.Bias bias, int direction, Position.Bias[] biasRet) throws BadLocationException;
Note that getNextVisualPositionFrom is defined in
View;
for consistency, the method in NavigationFilter is
named the same.
Similar to DocumentFilter,
NavigationFilter is passed a FilterBypass
that should be invoked to handle the actual mutation.
NavigationFilter.FilterBypass is defined by:
public abstract Caret getCaret();
public abstract void setDot(int dot, Position.Bias bias);
public abstract void moveDot(int dot, Position.Bias bias);
As previously mentioned, an instance of
AbstractFormatter is used to format a particular
Object value. AbstractFormatter can also impose an
editing policy by defining a DocumentFilter; it can
also impose a navigation policy by defining a
NavigationFilter.
AbstractFormatter is defined by:
public void install(JFormattedTextField ftf);
public void uninstall();
public abstract Object stringToValue(String text) throws ParseException;
public abstract String valueToString(Object value) throws ParseException;
protected JFormattedTextField getFormattedTextField();
protected void setEditValid(boolean valid);
protected void invalidEdit();
protected Action[] getActions();
protected DocumentFilter getDocumentFilter();
protected NavigationFilter getNavigationFilter();
Once JFormattedTextField is ready to use an
AbstractFormatter it invokes install.
AbstractFormatter.install performs the following:
JFormattedTextField to the
return value of valueToString (if a
ParseException is thrown, an empty String is used and
setEditValid(false) is invoked).DocumentFilter returned from
getDocumentFilter onto the
JFormattedTextField's Document.NavigationFilter returned from
getNavigationFilter onto the
JFormattedTextField.Actions returned from
getActions onto the JFormattedTextField's
ActionMap.Subclasses will typically only override install if
they need to install additional Listeners beyond the
DocumentFilter and NavigationFilter, or
perhaps place the caret at an initial location.
Some AbstractFormatters allow the
JFormattedTextField to contain an invalid value when
editing. To allow the JFormattedTextField to provide
an indication of this, the AbstractFormatter should
invoke setEditValid(false) when the user enters an
invalid value, and then invoke setEditValid(true) when
the value is valid again.
When JFormattedTextField is done with an
AbstractFormatter, it invokes uninstall.
uninstall removes the previously installed
Listeners.
JFormattedTextField delegates the creation of
AbstractFormatters to an instance of
AbstractFormatterFactory (a public static inner
class of JFormattedTextField). This makes it easy for
developers to provide different formatters for different states of
the JFormattedTextField. For example, you could
provide a special AbstractFormatter if the current
value is null, or one formatter when editing and
another when displaying. AbstractFormatterFactory is
defined by:
public abstract AbstractFormatter getFormatter(JFormattedTextField ftf);
If the developer has not supplied an
AbstractFormatterFactory, one will be created based on
the Class of the value.
DefaultFormatter
extends JFormattedTextField.AbstractFormatter and is
the superclass for all of the formatter implementations we provide.
DefaultFormatter formats Objects using
toString and creates the Object using the constructor
that takes a String. DefaultFormatter allows a number
of configuration options:
|
Option |
Description |
|---|---|
| CommitsOnValidEdit | Determines when edits are published back to the
JFormattedTextField. If true,
commitEdit is invoked on the
JFormattedTextField after every successful edit,
otherwise commitEdit is invoked only when return is
pressed. |
| OverwriteMode | Configures the behavior when inserting characters. If
overwriteMode is true (the default), new
characters overwrite existing characters in the model as they are
inserted. |
| AllowsInvalid | Determines whether the value being edited is allowed to be invalid. It is often convenient to allow the user to enter invalid values until a commit is attempted. |
The following table lists the AbstractFormatter
implementations that we provide, as well as intended use:
|
AbstractFormatter |
Object Type |
Notes |
|---|---|---|
| DefaultFormatter | Object | valueToString uses Object.toString(),
and stringToValue uses the single argument constructor
that takes a String. |
| MaskFormatter | Strings | Behavior is dictated by a per character mask that specifies legal values (e.g. "###-####"). |
| InternationalFormatter | Objects | Uses an instance of java.text.Format to handle
valueToString and stringToValue. |
| NumberFormatter | Numbers | Uses an instance of NumberFormat to handle
formatting, descends from InternationalFormatter. |
| DateFormatter | Date | Uses an instance of DateFormat to handle
formatting, descends from InternationalFormatter. |
The Swing support for formatted dates and numbers made extensive
use of the Format classes in the
java.text package. The following problems were
encountered using the previous API:
format repeatedly.Format
subclasses out there that we didn't know about. Note that the
constants for DateFormat and NumberFormat
already overlap, so a NumberFormat would have happily
interpreted YEAR_FIELD as FRACTION_FIELD.
The problem was exacerbated by the existence of the polymorphic
Format.format(Object, StringBuffer, FieldPosition)
method.NumberFormat for the MONTH_FIELD (the
actual implementation of this case returned 0 for both begin index
and end index).Format subclass actually supported unless it knew the
specific subclass. This, along with the fact that not all
characters in a formatted string are part of fields, makes the
implementation of a generic method that returns all fields
impossible.These issues have largely been addressed by adding the following
method to java.text.Format:
public AttributedCharacterIterator formatToCharacterIterator(Object obj);
Each Format class uses a type safe enumeration for
the constants it supports.
The following classes are new to the 1.4 release:
The bugtraq report that corresponds to this change is: 4468474.
The following constants have been replaced to conform Java to naming conventions:
CommitValueOnFocusLost has been replaced with
COMMIT.CommitOrRevertValueOnFocusLost has been replaced
with
COMMIT_OR_REVERT.RevertValueOnFocusLost has been replaced with
REVERT.PersistValueOnFocusLost has been replaced with
PERSIST.Copyright © 1993, 2010, Oracle and/or its affiliates. All rights reserved. Please send comments using this Feedback page. |
Java Technology |