Swing


Wie kann ich eine Eingabeprüfung mit Java machen?

Die hier vorgestellte Methode funktioniert mit Java 1.5 und ist als eine andere Alternative zur Implementation im Document (vgl. Wie kann ich ein Textfeld erstellen, indem nur Zahlen eingegeben werden können?) zu sehen. Beide Varianten haben Ihre Vor- und Nachteile.

Dieser Artikel beinhaltet hierbei im eigentlichen Sinne zwei Lösungen. Zum einem die Nutzung eines javax.swing.text.MaskFormatter als Möglichkeit auf einfache Art das Eingabeformat vorzugeben. Zum anderen wird der Mechanismus der javax.swing.InputVerifier erläutert, welcher eine wesentlich feinere Art der Eingabeprüfung zuläßt.

Wie kann ich eine einfache Eingabeprüfung mit Hilfe eines MaskFormatter vornehmen?

Der MaskFormatter bietet analog zum SimpleDateFormat eine einfache Möglichkeit eine Schablone festzulegen, welcher das Eingabeformat entsprechen muss. Im Gegensatz zu anderen Programmiersprachen (z.B. Dialog System von MicroFocus) wird hierbei die Schablone mitgeliefert.

        formatter = new MaskFormatter ("##.##.####");
        textField.setFormatterFactory(new DefaultFormatterFactory (formatter));
      
Mit der ersten Zeile legen wir eine Schablone fest, die zwischen die getrennt von ein paar Punkten - wie unschwer zu erkennen ist - das Datumsformat festlegt. Die zweite Zeile weist dem Eingabefeld unseren Formatter zu. Die "reine" Zuweisung geht auch etwas einfacher, die hier dargestellte Form ist jedoch auch bei Erstellung eigener Textkomponenten funktional (siehe abschließendes Beispiel).
Für eine schönere Darstellung können wir auch noch einen Platzhalter festlegen, um die Eingabe etwas komfortabler zu machen.

Wie kann ich mit einem InputVerifer eine konkrete Eingabeprüfung mit Java realisieren?

Mit Hilfe des MaskFormatter haben wir unseren ersten Schritt getan. Nicht immer reicht dieser jedoch aus. Unser Beispiel zeigt hier schon einige Grenzen des MaskFormatter auf. So wird der Anwender über inkorekte Eingaben nur schlecht informiert, indem das Eingabefeld im besten Fall leer bleibt. Die Lösung ist der javax.swing.InputVerifer. Dieses Interface hat nur zwei Methoden und die Implementation kann unserem Eingabefeld mit einer Zeile hinzugefügt werden.

        textfield.setInputVerifier(new DateInputVerifier());
      
Die zwei Methoden public boolean verify (final JComponent input) und public boolean shouldYieldFocus (final JComponent input) müssen dabei implementiert werden. Die verify Methode sollte die tatsächliche (sachliche) Prüfung vornehmen, ohne die Eingabekomponente zu verändern. Mit Hilfe von shouldYieldFocus können wir die Fokusweitergabe beeinflussen. Zudem ist hier der ideale Ort, um unseren Anwender über "unsere Auffassung eines korekten Eingabewertes" zu informieren.

Abschließendes Beispiel

Das abschließende Beispiel ist die Erweiterung eines JFormattedTextField zur Datumseingabe. Es kombiniert dabei die beiden oben genannten Möglichkeiten um eine halbwegs sinnvolle Eingabe des Datums zu ermöglichen. Eine Erweiterung des Verifier, so dass z.B. als Monat keine 13 eingegeben werden kann, kann jedoch auf Basis dieses Beispiels leicht implementiert werden.

Um die Klasse zu verwenden ist lediglich eine Instanz zu erzeugen und optional noch ein Platzhalter hinzuzufügen. Die beiden dargestellten Eingabefelder unterscheiden sich hierbei lediglich hinsichtlich der Frage, ob ein Platzhalter definiert wurde.

/**
 * Copyright  2006 Bastie - Sebastian Ritter
 */
package de.bastie.swing;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.logging.Logger;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.text.DefaultFormatterFactory;
import javax.swing.text.MaskFormatter;

/**
 * Simple TextField to input a date.
 *
 * @author Bastie - Sebastian Ritter
 * @version 1.0
 * @since Java 1.5
 */
public class DateInputTextField extends JFormattedTextField {

  public DateInputTextField () {
    this.setFormatterFactory(new DefaultFormatterFactory (this.getDateMask()));
    this.setInputVerifier(new DateInputVerifier());
  }

  /**
   * Preferred size for date mask
   * @return Dimension
   */
  public Dimension getPreferredSize () {
    final double height = super.getPreferredSize().getHeight();
    final FontMetrics fm = this.getFontMetrics(this.getFont());
    int breite = fm.charsWidth (this.getDateMask ().getMask().toCharArray(), 0, this.getDateMask ().getMask().length ());
    breite += this.getInsets().left+this.getInsets().right;
    if (this.getBorder() != null)
      breite += this.getBorder().getBorderInsets(this).left + this.getBorder().getBorderInsets(this).right;
    Dimension d = new Dimension();
    d.setSize((double) breite, height);
    return d;
  }

  /**
   * Format of input
   * @return MaskFormatter
   */
  protected MaskFormatter getDateMask () {
    MaskFormatter formatter = null;
    try {
      if (Locale.getDefault ().getLanguage ().equals (Locale.GERMANY.getLanguage())) {
        formatter = new MaskFormatter ("##.##.####");
      }
      else {
        formatter = new MaskFormatter ("####-##-##");
      }
      if (this.getPlaceHolder() != null) {
        formatter.setPlaceholderCharacter (this.getPlaceHolder());
      }
    }
    catch (final ParseException ignored) {
      Logger.getLogger(this.getClass().getName()).throwing (this.getClass().getName(),"getDateMask", ignored);
    }
    return formatter;
  }


  private Character placeholder = null;
  /**
   * Set an Empty Character for delete the Input. If Empty Character is null,
   * a valid value need to input.
   * @param c Character
   */
  public void setPlaceholder (final Character c) {
    this.placeholder = c;
  }

  /**
   * Return the char for delete the input or null if delete not allowed.
   * @return Character
   */
  public Character getPlaceHolder () {
    return this.placeholder;
  }


  /**
   * Simple Date Verifier
   * @author Bastie - Sebastian Ritter
   * @version 1.0
   */
  protected static class DateInputVerifier extends InputVerifier {
    public boolean verify (final JComponent input) {
      if (input instanceof DateInputTextField) {
        return this.isAlowedDate((DateInputTextField)input);
      }
      else {
        return true;
      }
    }

    /**
     * Check the incomming Date
     * @param input DateInputTextField
     * @return boolean
     */
    protected boolean isAlowedDate (final DateInputTextField input) {
      final DateFormat sdf = this.getDateFormat ();
      try {
        final Date d = sdf.parse (input.getText());
        SwingUtilities.invokeLater(new Runnable () {
          public void run () {
            input.setText(sdf.format(d));
          }
        });
        return true;
      }
      catch (final ParseException notValidOrDelete) {
        if (input.getPlaceHolder() != null) {
          String noMaskValue = null;
          if (Locale.getDefault ().getLanguage ().equals (Locale.GERMANY.getLanguage ())) {
            noMaskValue = input.getText().replace ('.',input.getPlaceHolder ());
          }
          else {
            noMaskValue = input.getText().replace ('-',input.getPlaceHolder ());
          }
          for (char c : noMaskValue.toCharArray()) {
            if (c != input.getPlaceHolder()) return false;
          }
          return true;
        }
        return false;
      }
    }

    /**
     * Return i18n DateFormat
     * @return DateFormat
     */
    protected DateFormat getDateFormat () {
      if (Locale.getDefault().getLanguage().equals(Locale.GERMANY.getLanguage())) {
        return new SimpleDateFormat ("dd.MM.yyyy");
      }
      else {
        return new SimpleDateFormat("yyyy-MM-dd");
      }
    }

    /**
     * Change the gui.
     * @param input the JComponent to verify
     * @return true when valid, false when invalid
     *
     */
    public boolean shouldYieldFocus (final JComponent input) {
      if (!verify(input)) {
        input.setForeground(Color.RED);
        input.setBorder(BorderFactory.createEtchedBorder(Color.RED, new Color (255,50,50)));
        return false;
      }
      else {
        input.setForeground(Color.BLACK);
        input.setBorder((Border)UIManager.getLookAndFeelDefaults().get("TextField.border"));
        return true;
      }
    }
  }
}
    
all rights reserved © Bastie - Sebastian Ritter @: w³: http://www.Bastie.de
Diese Seite ist Bestandteil der Internetpräsenz unter http://www.Bastie.de


Java Cobol Software Resourcen Service Links Über mich Zum Gästebuch