8.6.14 | JFormattedTextField |
Neu in Version
1.4 ist diese Erweiterung des JTextField, die eine Validierung der Eingabe ermöglicht. Dies geschieht über ein Exemplar der Klasse JFormattedTextField.AbstractFormatter. Typischerweise benutzt man hier die zwei Standard-Implementierungen DateFormatter (für Datumseingaben), NumberFormatter (für Zahlenwerte) und MaskFormatter (bei dem man Texteingaben nur nach einem bestimmbaren Muster eingeben kann). Alle drei Klassen sind im Paket javax.swing.text definiert. Neben der Möglichkeit, den Formatter direkt anzugeben, kann man auch eine JFormattedTextField.AbstractFormatterFactory angeben. Der Vorteil davon (wie bei allen Factories) ist, dass die Anzahl der Formatter-Exemplare von der Factory überwacht werden kann. Typischerweise hat die Factory nur ein Exemplar, welches von verschiedenen JFormattedTextFields gleichzeitig verwendet werden kann. Zu diesem Zweck wird beim Hin- und Herwechseln zwischen den Textfeldern die Methode install(JFormattedTextField field) bzw. uninstall() aufgerufen.
Die Überprüfung der Eingabe geschieht auf zwei Ebenen. Zum einen während der Eingabe der Zeichen (siehe JFormattedTextField.AbstractFormatter), wie auch bei dem Versuch, das Textfeld zu verlassen. In diesem Fall wird das schon bei Java 1.3 eingerführte Konzept des InputVerifier verwendet.
Ein InputVerifier verhindert das Versetzen des Fokus weg von einer Komponente, wenn diese falsche Eingaben hat. Zu diesem Zweck kann bei jeder Swing-Komponente die Methode setInputVerifier(InputVerifier verifier) aufgerufen werden. Über die Methode setVerifyInputWhenFocusTarget(boolean state) kann man bei einer Komponente verhindern, dass der InputVerifier aufgerufen wird - sinnvoll beispielsweise beim Abbrechen-Button.
// Überprüft, ob "pass" eingegeben wurde class PassVerifier extends InputVerifier { public boolean verify(JComponent input) { JTextField tf = (JTextField) input; return "pass".equals(tf.getText()); } } JTextField f = new JTextField(); f.setInputVerifier(new PassVerifier());
Man kann dabei über die Methode setFocusLostBehavior(int behavior) zwischen vier Möglichkeiten wählen, was passieren soll, wenn versucht wird, das Textfeld zu verlassen:
- JFormattedTextField.REVERT
Es wird der Wert zurückgeschrieben, den das Textfeld vor dem Editierversuch hatte, egal, ob der neue Wert syntaktisch korrekt ist.- JFormattedTextField.COMMIT
Falls der eingegebene Wert korrekt ist, wird der Wert festgeschrieben und dementsprechend auch angezeigt. Falls der Eingabewert falsch ist, wird zwar der falsche Text angezeigt, die getValue()-Methode liefert jedoch noch den alten Wert zurück.- JFormattedTextField.COMMIT_OR_REVERT
Die Standardeinstellung verhält sich wie COMMIT, allerdings wird bei einer falschen Eingabe auch der zuletzt richtige Wert angezeigt.- JFormattedTextField.PERSIST
In diesem Fall wird auch bei korrekter Eingabe der Wert nicht geändert. Dementsprechend wird der Text angezeigt, der eingegeben wurde.
All diesen Varianten ist gemeinsam, dass die Komponente verlassen wird. Wenn gewünscht wird, dass der Fokus erst die Komponente verlassen kann, wenn die Eingabe korrekt ist, kann man folgenden InputVerifier dafür benutzen:
public class FormattedTextFieldVerifier extends InputVerifier { public boolean verify(JComponent input) { JFormattedTextField ftf = (JFormattedTextField)input; JFormattedTextField.AbstractFormatter formatter = ftf.getFormatter(); if (formatter != null) { String text = ftf.getText(); try { // Wenn die Konvertierung // des Textes zum gewünschten // Datum geht, liefert die Methode // ein positives Ergebnis formatter.stringToValue(text); return true; } catch (ParseException pe) { return false; } } return true; } }
Um eine implementierende Klasse dieser abstrakten Klasse zu bilden, müssen die Methode valueToString(Object obj) und stringToValue(String str) implementiert werden.
Dies wird nötig, da das Textfeld intern mit Strings arbeitet, die Daten aber beliebig sein können. Daher wird zu Beginn das Objekt in eine String-Repräsentation umgewandelt und nach dem Editiervorgang der neue String in das entsprechende, beliebige Daten-Objekt umgewandelt.
Zusätzlich kann der Programmierer ein Exemplar der Klasse javax.swing.text.DocumentFilter angeben, mit dem die Eingabe von bestimmten Zeichen validiert werden kann (s. Ausführungen zu JTextField).
Ein javax.swing.text.NavigationFilter hingegen bietet die Möglichkeit, die zulässigen Positionen für den Cursor innerhalb des Textfeldes zu definieren.
Der DateFormatter bietet die Möglichkeit, Datumseingaben vorzunehmen. Zu diesem Zweck kann der Programmierer das Datumsformat im Konstruktor angeben. Das Format liefert dabei ein Exemplar der Klasse java.text.DateFormat. Um bspw. ein Datum der deutschen Form TT.MM.JJ editieren zu können, reicht folgender Code:
JFormattedTextField tf = new JFormattedTextField( new DateFormatter( DateFormat.getDateInstance (DateFormat.SHORT, Locale.GERMAN)));
Im Gegensatz zu dem MaskFormatter wird die Eingabe erst überprüft, wenn versucht wird, das Textfeld zu verlassen. Es ist also im obigen Beispiel möglich, zunächst Buchstaben statt Zahlen einzugeben.
Ähnlich wie beim DateFormatter wird die Eingabe erst beim bevorstehenden Verlust des Fokus überprüft. Mit Hilfe des Formates, das die Klasse java.text.NumberFormat vorgibt, können Zahlen nach einem bestimmten Schema editiert werden.
Im Gegensatz zu den vorher genannten Formatierern, werden hier die Tastatureingaben direkt überprüft. Dazu bildet man die passenden Muster anhand der in Tabelle 8.2 angegebenen Platzhalter.
Tabelle 8.2: Die Pattern des MaskFormatters Platzhalter Bedeutung # Eine gültige Zahl ' Escape-Zeichen, so dass eingeschlossener Text nicht als Platzhalter angesehen werden U Ein großgeschriebener Buchstabe. Bei der Eingabe eines kleinen Buchstaben wird dieser in einen großen umgewandelt. L Ein kleingeschriebener Buchstabe. Bei der Eingabe eines großen Buchstaben wird dieser in einen kleinen umgewandelt. A Ein Buchstabe oder eine Zahl ? Ein beliebiger Buchstabe * Alles H Ein hexadezimales Zeichen (0-9, A-F bzw. a-f)
Um die Eingabe noch weiter einzugrenzen, können die gültigen Zeichen mit Hilfe der Methode setValidCharacters(String chars) als String-Aufzählung angegeben werden:
// Nur hexadezimale Zahlen zulassen formatter.setValidCharacters("0123456789abcdefABCDEF");
JFormattedTextField dateField = new JFormattedTextField( new MaskFormatter("##.##.####"));