このドキュメントでは、書式付きテキストフィールドの Swing での実装の概略を説明します。書式付きテキストフィールドによって、開発者は、テキストコンポーネントに入力できる正当な文字セットを指定できるようになります。このドキュメントは、以下の節で構成されています。
JFormattedTextField によって、日付、数値、文字列および任意のオブジェクトの書式を設定することができます。JFormattedTextField は、java.text.Format クラスに基づいて、日付と数値に書式を設定します。現在のロケール固有の書式で日付を入力するための JFormattedTextField を作成するには、次のようにします。
new JFormattedTextField(new Date());
特定の書式で日付を表示することが必要な場合は、SimpleDateFormat コンストラクタの 1 つを使用できます。
new JFormattedTextField(new SimpleDateFormat("MM/dd/yy"));
数値は、java.text.NumberFormat のインスタンスによって処理されます。以下に、数値を編集する JFormattedTextField を作成する方法をいくつか示します。
new JFormattedTextField(new Number(1000));
new JFormattedTextField(new DecimalFormat("#,###"));
new JFormattedTextField(new DecimalFormat("0.###E0"));
JFormattedTextField は、マスクが指定された文字列の編集もサポートします。このマスクで、指定した文字位置に置く有効な文字を指定します。米国の電話番号を編集する JFormattedTextField を作成するには、次のコードを使用することができます。
new JFormattedTextField(new MaskFormatter("(###) ###-####"));
JFormattedTextField 自体は、そのスーパークラスである JTextField の API のほかは、最小限の API を公開します。もっとも単純に説明すれば、JFormattedTextField は、JTextField に追加の Object 型の値のプロパティ、および書式を設定するオブジェクト (AbstractFormatter のインスタンス) が付いたものと見なすことができます。
値のプロパティが Object 型であるため、開発者にとっては、JFormattedTextField がどのように構成されたかに基づいて戻り値の型をキャストする必要があります。以下に、日付と JFormattedTextField の使用法についての典型的なシナリオを示します。
JFormattedTextField ftf = new JFormattedTextField(); ftf.setValue(new Date()); ... Date date = (Date)ftf.getValue();
数値を編集する典型的なセッションは、次のようになります。
JFormattedTextField ftf = new JFormattedTextField(); ftf.setValue(new Integer(1000)); ... int intValue = ((Number)ftf.getValue()).intValue();
テキストコンポーネントにデータを入力するには、以前は Document のサブクラスを作成することが必要でした。この作業は、単純で一般的な使用法としては、負荷が多い操作でした。この作業を簡略化するために、Document にプラグインできる DocumentFilter クラスが作成されました。Document は、変更されなかったインタフェースです。代わりに、現在は AbstractDocument に DocumentFilter 用のセッタ/ゲッタがあり、AbstractDocument から派生しなかった Document のためにプロパティが設定されるので、DocumentFilter をサポートできます。DocumentFilter 付きの Document がコンテンツを削除または挿入するようにメッセージを受け取ると、Document は DocumentFilter 上でメッセージに応じたメソッドを呼び出します。操作を進行させる必要がある場合にコールバックを呼び出すことが、DocumentFilter の役割になります。この方法で、DocumentFilter が Document を変更できる方法についての全体的な制御権を持ちます。DocumentFilter は、次のようにして定義されます。
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;
DocumentFilter が remove または insertString メソッドの内部から Document を変更したい場合は、super 実装を呼び出すか、FilterBypass 上でそのメソッドを呼び出す必要があります。super または FilterBypass 上でメソッドを呼び出すと、フィルタを迂回する方法が提供されるので、呼び出し側はスタック再帰から抜け出せなくなることがありません。DocumentFilter には、FilterBypass 上で 1 つだけメソッドを呼び戻すという制限はありません。FilterBypass によって開示されたどのメソッドでも呼び出すことができ、DocumentFilter のメソッドの 1 つの適用範囲内で必要なだけ何回でも呼び出すことができます。FilterBypass は、次のようにして定義されます。
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;
次の例で、英小文字を英大文字にマッピングする DocumentFilter を作成する方法を示します。
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);
}
};
DocumentFilter と同様に、新規クラスの NavigationFilter によって、選択範囲を置き換えることが可能な場所でフィルタリングを実行できるようになります。NavigationFilter は、ある位置から選択範囲を設定する次の位置を決定するナビゲーション操作 (左、右、中央など) によって呼び出されます。NavigationFilter は JTextComponent のプロパティであり、次のように定義されています。
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;
getNextVisualPositionFrom は View 内に定義されており、一貫性を保つために、NavigationFilter 内のメソッドと同じ名前が付けられています。
DocumentFilter と同様に、NavigationFilter は、実際の変更を処理するために呼び出される FilterBypass に渡されます。NavigationFilter.FilterBypass は、次のように定義されています。
public abstract Caret getCaret(); public abstract void setDot(int dot, Position.Bias bias); public abstract void moveDot(int dot, Position.Bias bias);
前述したように、AbstractFormatter のインスタンスは特定の Object 値の書式を設定するために使用されます。AbstractFormatter は、DocumentFilter を定義して編集ポリシーを指定したり、NavigationFilter を定義してナビゲーションポリシーを指定したりすることもできます。AbstractFormatter は、次のように定義されています。
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();
JFormattedTextField で AbstractFormatter を使用する準備ができると、install を呼び出します。AbstractFormatter.install は、次の作業を実行します。
JFormattedTextField のテキストを valueToString の戻り値に設定します (ParseException がスローされた場合は空の文字列が使用され、setEditValid(false) が呼び出される)。
getDocumentFilter から返された DocumentFilter を JFormattedTextField の Document にインストールします。
getNavigationFilter から返された NavigationFilter を JFormattedTextField にインストールします。
getActions から返された Action を JFormattedTextField の ActionMap にインストールします。
サブクラスで DocumentFilter および NavigationFilter の範囲を超えた追加の Listener をインストールする必要がある場合は、サブクラスは install をオーバーライドするだけか、または最初の位置にキャレットを配置することがあります。
ある種の AbstractFormatter では、JFormattedTextField が編集中に無効な値を含むことが許容されます。JFormattedTextField で無効な値を含んでいることを示すことができるように、AbstractFormatter は、ユーザが無効な値を入力したときに setEditValid(false) を呼び出します。有効な値が入力されると、setEditValid(true) が呼び出されます。
JFormattedTextField が AbstractFormatter で処理される場合は、uninstall を呼び出します。uninstall によって、以前にインストールされた Listener が削除されます。
JFormattedTextField は、AbstractFormatter の作成を AbstractFormatterFactory (JFormattedTextField の公開されている static の内部クラス) のインスタンスに委譲します。この委譲によって、開発者がさまざまな状態の JFormattedTextField に多様なフォーマッタを提供することが簡単になります。たとえば、現在の値が null の場合は特殊な AbstractFormatter、または編集中にはあるフォーマッタ、表示中には別のフォーマッタを提供することができます。AbstractFormatterFactory は、次のように定義されています。
public abstract AbstractFormatter getFormatter(JFormattedTextField ftf);
開発者が AbstractFormatterFactory を供給しなかった場合は、値の Class に基づいたフォーマッタが作成されます。
DefaultFormatter は JFormattedTextField.AbstractFormatter を拡張します。これは、提供されたフォーマッタ実装のすべてに対応するスーパークラスです。DefaultFormatter は toString を使用して Object の書式を設定し、文字列をとるコンストラクタを使用して Object を作成します。DefaultFormatter では、多数の構成オプションを使用できます。
Option |
説明 |
|---|---|
| CommitsOnValidEdit |
編集が JFormattedTextField に公開されて戻される時点を決定する。true の場合は、各編集が成功したあとに JFormattedTextField 上で commitEdit が呼び出される。そうでない場合は、Return キーが押されたときにだけ commitEdit が呼び出される
|
| OverwriteMode |
文字を挿入するときの動作を構成する。overwriteMode が true の場合 (デフォルト) は、新しい文字が挿入されたときにモデル内の既存の文字がオーバーライドされる
|
| AllowsInvalid | 編集中の値が無効であっても許容されるかどうかを決定する。確定が試行されるまでユーザが無効な値を入力できるようにしておくと、便利な場合が多い |
次の表に、使用されることを目的として提供する AbstractFormatter の実装を示します。
AbstractFormatter |
オブジェクトの型 |
説明 |
|---|---|---|
| DefaultFormatter | オブジェクト |
valueToString が Object.toString() を使用し、stringToValue が文字列をとる単一引数のコンストラクタを使用する
|
| MaskFormatter | 文字列 | 動作は、適切な値 (###-#### など) を指定する文字単位のマスクで示される |
| InternationalFormatter | オブジェクト |
java.text.Format のインスタンスを使用して、valueToString および stringToValue を処理する
|
| NumberFormatter | 数値 |
InternationalFormatter から派生した NumberFormat のインスタンスを使用して、書式を設定する
|
| DateFormatter | 日付 |
InternationalFormatter から派生した DateFormat のインスタンスを使用して、書式を設定する
|
Swing では、java.text パッケージ内の Format クラスの拡張使用が可能な、書式付きの日付と数値がサポートされています。以前の API では、次のような問題点がありました。
format を繰り返し呼び出す必要があった
Format のサブクラスと競合する可能性が、潜在的にあった。DateFormat と NumberFormat の定数がすでに重なり合っているので、NumberFormat では幸いなことに、YEAR_FIELD が FRACTION_FIELD として解釈されることに留意する。問題点が、多様な形式を持つ Format.format(Object, StringBuffer, FieldPosition) メソッドの存在によって悪化した
MONTH_FIELD 用に NumberFormat を要求した場合など (この例の実装では、開始インデックスと終了インデックスの両方に 0 が返された)
Format のサブクラスでサポートされるかがわからなかった。書式付き文字列内ですべての文字がフィールドの一部ではないという事実に加え、このことが、すべてのフィールドを返す汎用メソッドの実装を不可能にした
これらの問題点は、以下のメソッドを java.text.Format に追加することで、大幅に対処されました。
public AttributedCharacterIterator formatToCharacterIterator(Object obj);
各 Format クラスでは、サポートする定数のために型保証された列挙を使用しています。
以下のクラスが 1.4 リリースでの新規クラスです。
この変更に関連するバグ追跡レポート: 4468474
次の定数の名前は、Java の命名規則に準拠するように変更されました。
CommitValueOnFocusLost を COMMIT に変更
CommitOrRevertValueOnFocusLost を COMMIT_OR_REVERT に変更
RevertValueOnFocusLost を REVERT に変更
PersistValueOnFocusLost を PERSIST に変更