Java/Swing JFC/Formatted TextField

Материал из Java эксперт
Перейти к: навигация, поиск

A BigDecimal object custom formatter

  

import java.math.BigDecimal;
import java.text.DecimalFormat;
import javax.swing.JFormattedTextField;
import javax.swing.text.DefaultFormatter;
import javax.swing.text.DefaultFormatterFactory;
import javax.swing.text.NumberFormatter;
public class Main {
  public static void main(String[] argv) {
    JFormattedTextField f = new JFormattedTextField(new BigDecimal("123.4567"));
    DefaultFormatter fmt = new NumberFormatter(new DecimalFormat("#.0###############"));
    fmt.setValueClass(f.getValue().getClass());
    DefaultFormatterFactory fmtFactory = new DefaultFormatterFactory(fmt, fmt, fmt);
    f.setFormatterFactory(fmtFactory);
    BigDecimal bigValue = (BigDecimal) f.getValue();
  }
}





Accepting Formatted Input

  
import java.awt.BorderLayout;
import java.awt.Container;
import java.util.Date;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
public class FormattedTest {
  public static void main(String args[]) {
    JFrame frame = new JFrame("Formatted");
    Container contentPane = frame.getContentPane();
    JFormattedTextField ftf1 = new JFormattedTextField(new Integer(0));
    contentPane.add(ftf1, BorderLayout.NORTH);
    JFormattedTextField ftf2 = new JFormattedTextField(new Date());
    contentPane.add(ftf2, BorderLayout.SOUTH);
    frame.setSize(200, 100);
    frame.show();
  }
}





A decimal number with one digit following the decimal point;

  
import java.text.DecimalFormat;
import javax.swing.JFormattedTextField;
public class Main {
  public static void main(String[] argv) throws Exception {
    JFormattedTextField tft2 = new JFormattedTextField(new DecimalFormat("#.0"));
    tft2.setValue(new Float(123.4F));
    // Retrieve the value from the text field
    Float floatValue = (Float) tft2.getValue();
  }
}





A formatter for regular expressions to be used with JFormattedTextField

  
/*
Java Swing, 2nd Edition
By Marc Loy, Robert Eckstein, Dave Wood, James Elliott, Brian Cole
ISBN: 0-596-00408-7
Publisher: O"Reilly 
*/
// RegexPatternFormatter.java
//A formatter for regular expressions to be used with JFormattedTextField.
//
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.text.DefaultFormatter;
public class RegexPatternFormatter extends DefaultFormatter {
  protected java.util.regex.Matcher matcher;
  public RegexPatternFormatter(java.util.regex.Pattern regex) {
    setOverwriteMode(false);
    matcher = regex.matcher(""); // create a Matcher for the regular
                   // expression
  }
  public Object stringToValue(String string) throws java.text.ParseException {
    if (string == null)
      return null;
    matcher.reset(string); // set "string" as the matcher"s input
    if (!matcher.matches()) // Does "string" match the regular expression?
      throw new java.text.ParseException("does not match regex", 0);
    // If we get this far, then it did match.
    return super.stringToValue(string); // will honor the "valueClass"
                      // property
  }
  public static void main(String argv[]) {
    // a demo main() to show how RegexPatternFormatter could be used
    JLabel lab1 = new JLabel("even length strings:");
    java.util.regex.Pattern evenLength = java.util.regex.Pattern
        .rupile("(..)*");
    JFormattedTextField ftf1 = new JFormattedTextField(
        new RegexPatternFormatter(evenLength));
    JLabel lab2 = new JLabel("no vowels:");
    java.util.regex.Pattern noVowels = java.util.regex.Pattern.rupile(
        "[^aeiou]*", java.util.regex.Pattern.CASE_INSENSITIVE);
    RegexPatternFormatter noVowelFormatter = new RegexPatternFormatter(
        noVowels);
    noVowelFormatter.setAllowsInvalid(false); // don"t allow user to type
                          // vowels
    JFormattedTextField ftf2 = new JFormattedTextField(noVowelFormatter);
    JFrame f = new JFrame("RegexPatternFormatter Demo");
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    JPanel pan1 = new JPanel(new java.awt.BorderLayout());
    pan1.add(lab1, java.awt.BorderLayout.WEST);
    pan1.add(ftf1, java.awt.BorderLayout.CENTER);
    lab1.setLabelFor(ftf1);
    f.getContentPane().add(pan1, java.awt.BorderLayout.NORTH);
    JPanel pan2 = new JPanel(new java.awt.BorderLayout());
    pan2.add(lab2, java.awt.BorderLayout.WEST);
    pan2.add(ftf2, java.awt.BorderLayout.CENTER);
    lab2.setLabelFor(ftf2);
    f.getContentPane().add(pan2, java.awt.BorderLayout.SOUTH);
    f.setSize(300, 80);
    f.setVisible(true);
  }
}





A quick demonstration of JFormattedTextField

  
/*
Java Swing, 2nd Edition
By Marc Loy, Robert Eckstein, Dave Wood, James Elliott, Brian Cole
ISBN: 0-596-00408-7
Publisher: O"Reilly 
*/
// SimpleFTF.java
//A quick demonstration of JFormattedTextField.
//
import javax.swing.BoxLayout;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class SimpleFTF extends JPanel {
  public SimpleFTF() {
    JFormattedTextField ftf[] = new JFormattedTextField[7];
    String des[] = new String[ftf.length]; // description of each field
    des[0] = "Date";
    ftf[0] = new JFormattedTextField(new java.util.Date());
    des[1] = "Integer";
    ftf[1] = new JFormattedTextField(new Integer(90032221));
    des[2] = "Float";
    ftf[2] = new JFormattedTextField(new Float(3.14));
    des[3] = "Float work-around"; // manually specify a NumberFormat
    ftf[3] = new JFormattedTextField(java.text.NumberFormat.getInstance());
    ftf[3].setValue(new Float(3.14));
    des[4] = "currency";
    ftf[4] = new JFormattedTextField(java.text.NumberFormat
        .getCurrencyInstance());
    ftf[4].setValue(new Float(5.99));
    des[5] = "percent";
    ftf[5] = new JFormattedTextField(java.text.NumberFormat
        .getPercentInstance());
    ftf[5].setValue(new Float(0.33));
    des[6] = "java.net.URL"; // works via 1-arg String constructor and
                 // toString()
    java.net.URL u = null;
    try {
      u = new java.net.URL("http://www.ora.ru/");
    } catch (java.net.MalformedURLException ignored) {
    }
    ftf[6] = new JFormattedTextField(u);
    ftf[6].setColumns(24);
    // add each ftf[] to a BoxLayout
    setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
    for (int j = 0; j < ftf.length; j += 1) {
      JPanel borderPanel = new JPanel(new java.awt.BorderLayout());
      borderPanel.setBorder(new javax.swing.border.TitledBorder(des[j]));
      borderPanel.add(ftf[j], java.awt.BorderLayout.CENTER);
      add(borderPanel);
    }
  }
  public static void main(String argv[]) {
    if (argv.length > 0) { // change to command-line locale
      if (argv[0].equalsIgnoreCase("canada"))
        java.util.Locale.setDefault(java.util.Locale.CANADA);
      if (argv[0].equalsIgnoreCase("canada_french"))
        java.util.Locale.setDefault(java.util.Locale.CANADA_FRENCH);
      if (argv[0].equalsIgnoreCase("china"))
        java.util.Locale.setDefault(java.util.Locale.CHINA);
      if (argv[0].equalsIgnoreCase("france"))
        java.util.Locale.setDefault(java.util.Locale.FRANCE);
      if (argv[0].equalsIgnoreCase("germany"))
        java.util.Locale.setDefault(java.util.Locale.GERMANY);
      if (argv[0].equalsIgnoreCase("italy"))
        java.util.Locale.setDefault(java.util.Locale.ITALY);
      if (argv[0].equalsIgnoreCase("japan"))
        java.util.Locale.setDefault(java.util.Locale.JAPAN);
      if (argv[0].equalsIgnoreCase("korea"))
        java.util.Locale.setDefault(java.util.Locale.KOREA);
      if (argv[0].equalsIgnoreCase("prc"))
        java.util.Locale.setDefault(java.util.Locale.PRC);
      if (argv[0].equalsIgnoreCase("taiwan"))
        java.util.Locale.setDefault(java.util.Locale.TAIWAN);
      if (argv[0].equalsIgnoreCase("uk"))
        java.util.Locale.setDefault(java.util.Locale.UK);
      if (argv[0].equalsIgnoreCase("us"))
        java.util.Locale.setDefault(java.util.Locale.US);
    }
    String localeString = java.util.Locale.getDefault().getDisplayName();
    JFrame f = new JFrame("SimpleFTF " + localeString);
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.setContentPane(new SimpleFTF());
    f.pack();
    f.setVisible(true);
  }
}





Creating a Text Field to Display and Edit a Date

  
import java.text.DateFormat;
import java.util.Date;
import javax.swing.JFormattedTextField;
public class Main {
  public static void main(String[] argv) {
    JFormattedTextField tft2 = new JFormattedTextField(DateFormat.getDateInstance(DateFormat.SHORT));
    tft2.setValue(new Date());
  }
}





Creating a Text Field to Display and Edit a Number

  
import java.text.NumberFormat;
import javax.swing.JFormattedTextField;
public class Main {
  public static void main(String[] argv) {
    JFormattedTextField tft1 = new JFormattedTextField(NumberFormat.getIntegerInstance());
    tft1.setValue(new Integer(123));
    Integer intValue = (Integer) tft1.getValue();
  }
}





Creating a Text Field to Display and Edit a Phone Number

  
import javax.swing.JFormattedTextField;
import javax.swing.text.MaskFormatter;
public class Main {
  public static void main(String[] argv) throws Exception {
    MaskFormatter fmt = new MaskFormatter("###-###-####");
    JFormattedTextField tft1 = new JFormattedTextField(fmt);
  }
}





Creating a Text Field to Display and Edit a social security number

  
import javax.swing.JFormattedTextField;
import javax.swing.text.MaskFormatter;
public class Main {
  public static void main(String[] argv) throws Exception{
    MaskFormatter fmt = new MaskFormatter("###-###-####");
    JFormattedTextField tft1 = new JFormattedTextField(fmt);
    fmt = new MaskFormatter("###-##-####");
    JFormattedTextField tft2 = new JFormattedTextField(fmt);
  }
}





Different configurations of JFormattedTextField: Date

  
/*
 * Copyright (c) 2003-2005 JGoodies Karsten Lentzsch. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions are met:
 * 
 *  o Redistributions of source code must retain the above copyright notice, 
 *    this list of conditions and the following disclaimer. 
 *     
 *  o Redistributions in binary form must reproduce the above copyright notice, 
 *    this list of conditions and the following disclaimer in the documentation 
 *    and/or other materials provided with the distribution. 
 *     
 *  o Neither the name of JGoodies Karsten Lentzsch nor the names of 
 *    its contributors may be used to endorse or promote products derived 
 *    from this software without specific prior written permission. 
 *     
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 */
package com.jgoodies.validation.tutorial.formatted;
import java.text.DateFormat;
import java.text.Format;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import javax.swing.*;
import javax.swing.text.DateFormatter;
import javax.swing.text.DefaultFormatter;
import javax.swing.text.DefaultFormatterFactory;
import com.jgoodies.binding.value.ValueHolder;
import com.jgoodies.binding.value.ValueModel;
import com.jgoodies.forms.builder.DefaultFormBuilder;
import com.jgoodies.forms.layout.FormLayout;
import com.jgoodies.validation.formatter.EmptyDateFormatter;
import com.jgoodies.validation.formatter.RelativeDateFormatter;
import com.jgoodies.validation.tutorial.formatted.format.DisplayFormat;
import com.jgoodies.validation.tutorial.formatted.format.RelativeDateFormat;
import com.jgoodies.validation.tutorial.util.ExampleComponentFactory;
import com.jgoodies.validation.tutorial.util.MyFocusTraversalPolicy;
import com.jgoodies.validation.tutorial.util.TutorialUtils;
/**
 * Demonstrates different configurations of <code>JFormattedTextField</code>
 * to display and edit numbers. Shows <ul>
 * <li>how to use a custom DateFormat
 * <li>how to use a custom DateFormatter
 * <li>how to use a custom FormatterFactory
 * <li>how to reset a date to <code>null</code>
 * <li>how to map the empty string to a special date
 * <li>how to commit values on valid texts
 * </ul><p>
 * 
 * To look under the hood of this component, this class exposes 
 * the bound properties <em>text</em>, <em>value</em> and <em>editValid</em>. 
 *
 * @author  Karsten Lentzsch
 * @version $Revision: 1.8 $
 * 
 * @see     JFormattedTextField
 * @see     JFormattedTextField.AbstractFormatter
 */
public final class DateExample {
    
    public static void main(String[] args) {
        try {
            UIManager.setLookAndFeel("com.jgoodies.looks.plastic.PlasticXPLookAndFeel");
        } catch (Exception e) {
            // Likely Plastic is not in the classpath; ignore it.
        }
        JFrame frame = new JFrame();
        frame.setTitle("Formatted :: Dates");
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        JComponent panel = new DateExample()
                .buildPanel();
        frame.getContentPane().add(panel);
        frame.pack();
        TutorialUtils.locateOnScreenCenter(frame);
        frame.setVisible(true);
    }
    /**
     * Builds and returns a panel with a header row and the sample rows.
     * 
     * @return the example panel with a header and the sample rows
     */
    public JComponent buildPanel() {
        FormLayout layout = new FormLayout(
                "r:max(80dlu;pref), 4dlu, 45dlu, 1dlu, pref, 4dlu, pref, 0:grow");
        DefaultFormBuilder builder = new DefaultFormBuilder(layout);
        builder.setDefaultDialogBorder();
        builder.getPanel().setFocusTraversalPolicy(
                MyFocusTraversalPolicy.INSTANCE);
                
        Utils.appendTitleRow(builder, "Description");
        List fields = appendDemoRows(builder);
        
        String validText   = DateFormat.getDateInstance().format(new Date(67, 11, 5));
        String invalidText = "aa" + validText;
        Utils.appendButtonBar(builder, fields, validText, invalidText);
        return builder.getPanel();
    }
    
    
    /**
     * Appends the demo rows to the given builder and returns the List of
     * formatted text fields.
     * 
     * @param builder  the builder used to add components to
     * @return the List of formatted text fields
     */
    private List appendDemoRows(DefaultFormBuilder builder) {
        // The Formatter is choosen by the initial value.
        JFormattedTextField defaultDateField = 
            new JFormattedTextField(new Date());
        
        // The Formatter is choosen by the given Format.
        JFormattedTextField noInitialValueField = 
            new JFormattedTextField(DateFormat.getDateInstance());
        
        // Uses a custom DateFormat.
        DateFormat customFormat = DateFormat.getDateInstance(DateFormat.SHORT);
        JFormattedTextField customFormatField =
            new JFormattedTextField(new DateFormatter(customFormat));
        
        // Uses a RelativeDateFormat.
        DateFormat relativeFormat = new RelativeDateFormat();
        JFormattedTextField relativeFormatField =
            new JFormattedTextField(new DateFormatter(relativeFormat));
        
        // Uses a custom DateFormatter that allows relative input and
        // prints natural language strings.
        JFormattedTextField relativeFormatterField =
            new JFormattedTextField(new RelativeDateFormatter());
        
        // Uses a custom FormatterFactory that used different formatters
        // for the display and while editing.
        DefaultFormatterFactory formatterFactory = 
            new DefaultFormatterFactory(new RelativeDateFormatter(false, true),
                                        new RelativeDateFormatter(true, true));
        JFormattedTextField relativeFactoryField =
            new JFormattedTextField(formatterFactory);
        
        // Wraps a DateFormatter to map empty strings to null and vice versa.
        JFormattedTextField numberOrNullField =
            new JFormattedTextField(new EmptyDateFormatter());
        
        // Wraps a DateFormatter to map empty strings to -1 and vice versa.
        Date epoch = new Date(0); // January 1, 1970
        JFormattedTextField numberOrEmptyValueField =
            new JFormattedTextField(new EmptyDateFormatter(epoch));
        numberOrEmptyValueField.setValue(epoch);
        
        // Commits value on valid edit text
        DefaultFormatter formatter = new RelativeDateFormatter();
        formatter.setCommitsOnValidEdit(true);
        JFormattedTextField commitOnValidEditField =
            new JFormattedTextField(formatter);
        
        // A date field as created by the BasicComponentFactory:
        // Uses relative date input, and maps empty strings to null.
        ValueModel dateHolder = new ValueHolder();
        JFormattedTextField componentFactoryField =
            ExampleComponentFactory.createDateField(dateHolder);
        
        Format displayFormat = new DisplayFormat(DateFormat.getDateInstance());
        List fields = new LinkedList();
        fields.add(Utils.appendRow(builder, "Default",               defaultDateField,        displayFormat));
        fields.add(Utils.appendRow(builder, "No initial value",      noInitialValueField,     displayFormat));
        fields.add(Utils.appendRow(builder, "Empty <->  null",       numberOrNullField,       displayFormat));
        fields.add(Utils.appendRow(builder, "Empty <-> epoch",       numberOrEmptyValueField, displayFormat));
        fields.add(Utils.appendRow(builder, "Short format",          customFormatField,       displayFormat));
        fields.add(Utils.appendRow(builder, "Relative format",       relativeFormatField,     displayFormat));
        fields.add(Utils.appendRow(builder, "Relative formatter",    relativeFormatterField,  displayFormat));
        fields.add(Utils.appendRow(builder, "Relative factory",      relativeFactoryField,    displayFormat));
        fields.add(Utils.appendRow(builder, "Commits on valid edit", commitOnValidEditField,  displayFormat));
        fields.add(Utils.appendRow(builder, "Relative, maps null",   componentFactoryField,   displayFormat));
        
        return fields;
    }
       
}





different configurations of JFormattedTextField: Number

  
/*
 * Copyright (c) 2003-2005 JGoodies Karsten Lentzsch. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions are met:
 * 
 *  o Redistributions of source code must retain the above copyright notice, 
 *    this list of conditions and the following disclaimer. 
 *     
 *  o Redistributions in binary form must reproduce the above copyright notice, 
 *    this list of conditions and the following disclaimer in the documentation 
 *    and/or other materials provided with the distribution. 
 *     
 *  o Neither the name of JGoodies Karsten Lentzsch nor the names of 
 *    its contributors may be used to endorse or promote products derived 
 *    from this software without specific prior written permission. 
 *     
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 */
package com.jgoodies.validation.tutorial.formatted;
import java.text.Format;
import java.text.NumberFormat;
import java.util.LinkedList;
import java.util.List;
import javax.swing.*;
import javax.swing.text.DefaultFormatter;
import javax.swing.text.DefaultFormatterFactory;
import javax.swing.text.NumberFormatter;
import com.jgoodies.forms.builder.DefaultFormBuilder;
import com.jgoodies.forms.layout.FormLayout;
import com.jgoodies.validation.formatter.EmptyNumberFormatter;
import com.jgoodies.validation.tutorial.formatted.format.DisplayFormat;
import com.jgoodies.validation.tutorial.formatted.formatter.CustomNumberFormatter;
import com.jgoodies.validation.tutorial.util.MyFocusTraversalPolicy;
import com.jgoodies.validation.tutorial.util.TutorialUtils;
/**
 * Demonstrates different configurations of <code>JFormattedTextField</code>
 * to display and edit numbers. Shows<ul>
 * <li>how to use a custom NumberFormat
 * <li>how to use a custom NumberFormatter
 * <li>how to use a custom FormatterFactory
 * <li>how to reset a number to <code>null</code>
 * <li>how to map the empty string to a special number
 * <li>how to commit values on valid texts
 * <li>how to set the class of the result
 * </ul><p>
 * 
 * To look under the hood of this component, this class exposes 
 * the bound properties <em>text</em>, <em>value</em> and <em>editValid</em>. 
 *
 * @author  Karsten Lentzsch
 * @version $Revision: 1.9 $
 * 
 * @see     JFormattedTextField
 * @see     JFormattedTextField.AbstractFormatter
 */
public final class NumberExample {
    
    public static void main(String[] args) {
        try {
            UIManager.setLookAndFeel("com.jgoodies.looks.plastic.PlasticXPLookAndFeel");
        } catch (Exception e) {
            // Likely Plastic is not in the classpath; ignore it.
        }
        JFrame frame = new JFrame();
        frame.setTitle("Formatted :: Numbers");
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        JComponent panel = new NumberExample()
                .buildPanel();
        frame.getContentPane().add(panel);
        frame.pack();
        TutorialUtils.locateOnScreenCenter(frame);
        frame.setVisible(true);
    }
    /**
     * Builds and returns a panel with a header row and the sample rows.
     * 
     * @return the example panel with a header and the sample rows
     */
    public JComponent buildPanel() {
        FormLayout layout = new FormLayout(
                "r:max(80dlu;pref), 4dlu, 45dlu, 1dlu, pref, 4dlu, pref, 0:grow");
        DefaultFormBuilder builder = new DefaultFormBuilder(layout);
        builder.setDefaultDialogBorder();
        builder.getPanel().setFocusTraversalPolicy(
                MyFocusTraversalPolicy.INSTANCE);
                
        Utils.appendTitleRow(builder, "Description");
        List fields = appendDemoRows(builder);
        Utils.appendButtonBar(builder, fields, "42", "aa42");
        return builder.getPanel();
    }
    
    
    /**
     * Appends the demo rows to the given builder and returns the List of
     * formatted text fields.
     * 
     * @param builder  the builder used to add components to
     * @return the List of formatted text fields
     */
    private List appendDemoRows(DefaultFormBuilder builder) {
        // The Formatter is choosen by the initial value.
        JFormattedTextField defaultNumberField = 
            new JFormattedTextField(new Long(42));
        
        // The Formatter is choosen by the given Format.
        JFormattedTextField noInitialValueField = 
            new JFormattedTextField(NumberFormat.getIntegerInstance());
        
        // Uses a custom NumberFormat.
        NumberFormat customFormat = NumberFormat.getIntegerInstance();
        customFormat.setMinimumIntegerDigits(3);
        JFormattedTextField customFormatField =
            new JFormattedTextField(new NumberFormatter(customFormat));
        
        // Uses a custom NumberFormatter that prints natural language strings.
        JFormattedTextField customFormatterField =
            new JFormattedTextField(new CustomNumberFormatter());
        
        // Uses a custom FormatterFactory that used different formatters
        // for the display and while editing.
        DefaultFormatterFactory formatterFactory = 
            new DefaultFormatterFactory(new NumberFormatter(),
                                        new CustomNumberFormatter());
        JFormattedTextField formatterFactoryField =
            new JFormattedTextField(formatterFactory);
        
        // Wraps a NumberFormatter to map empty strings to null and vice versa.
        JFormattedTextField numberOrNullField =
            new JFormattedTextField(new EmptyNumberFormatter());
        
        // Wraps a NumberFormatter to map empty strings to -1 and vice versa.
        Integer emptyValue = new Integer(-1);
        JFormattedTextField numberOrEmptyValueField =
            new JFormattedTextField(new EmptyNumberFormatter(emptyValue));
        numberOrEmptyValueField.setValue(emptyValue);
        
        // Commits values on valid edit texts.
        DefaultFormatter formatter = new NumberFormatter();
        formatter.setCommitsOnValidEdit(true);
        JFormattedTextField commitOnValidEditField =
            new JFormattedTextField(formatter);
        // Returns number values of type Integer
        NumberFormatter numberFormatter = new NumberFormatter();
        numberFormatter.setValueClass(Integer.class);
        JFormattedTextField integerField = 
            new JFormattedTextField(numberFormatter);
        
        Format displayFormat = new DisplayFormat(NumberFormat.getIntegerInstance());
        Format typedDisplayFormat = new DisplayFormat(NumberFormat.getIntegerInstance(), true);
        List fields = new LinkedList();
        fields.add(Utils.appendRow(builder, "Default",               defaultNumberField,      typedDisplayFormat));
        fields.add(Utils.appendRow(builder, "No initial value",      noInitialValueField,     displayFormat));
        fields.add(Utils.appendRow(builder, "Empty <-> null",        numberOrNullField,       displayFormat));
        fields.add(Utils.appendRow(builder, "Empty <->   -1",        numberOrEmptyValueField, displayFormat));
        fields.add(Utils.appendRow(builder, "Custom format",         customFormatField,       displayFormat));
        fields.add(Utils.appendRow(builder, "Custom formatter",      customFormatterField,    displayFormat));
        fields.add(Utils.appendRow(builder, "Formatter factory",     formatterFactoryField,   displayFormat));
        fields.add(Utils.appendRow(builder, "Commits on valid edit", commitOnValidEditField,  displayFormat));
        fields.add(Utils.appendRow(builder, "Integer Result",        integerField,            typedDisplayFormat));
        
        return fields;
    }
       
}





Dynamically change the format

  
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.swing.JFormattedTextField;
import javax.swing.text.DateFormatter;
public class Main {
  public static void main(String[] argv) {
    JFormattedTextField f = new JFormattedTextField(new SimpleDateFormat("yyyy-M-d"));
    f.setValue(new Date());
    DateFormatter fmt = (DateFormatter) f.getFormatter();
    fmt.setFormat(new SimpleDateFormat("d/M/yyyy"));
    f.setValue(f.getValue());
  }
}





Field with different formats with focus and without

  
/*
Java Swing, 2nd Edition
By Marc Loy, Robert Eckstein, Dave Wood, James Elliott, Brian Cole
ISBN: 0-596-00408-7
Publisher: O"Reilly 
*/
// FactoryDemo.java
//Demo 1: field with different formats with focus and without.<br>
//Demo 2: Change the format of a field when the user presses a button.
//
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.ParseException;
import javax.swing.JButton;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.TitledBorder;
import javax.swing.text.DefaultFormatterFactory;
import javax.swing.text.MaskFormatter;
public class FactoryDemo {
  public static JPanel demo1() {
    // Demo 1: field with different formats with focus and without
    JPanel pan = new JPanel(new BorderLayout());
    pan.setBorder(new TitledBorder("Demo 1: format toggles with focus"));
    MaskFormatter withFocus = null, withoutFocus = null;
    try {
      withFocus = new MaskFormatter("LLLL");
      withoutFocus = new MaskFormatter("UUUU");
    } catch (ParseException pe) {
    }
    DefaultFormatterFactory factory = new DefaultFormatterFactory(
        withoutFocus, null, withFocus);
    JFormattedTextField field = new JFormattedTextField(factory);
    field.setValue("Four");
    pan.add(field, BorderLayout.CENTER);
    return pan;
  }
  public static JPanel demo2() {
    // Demo 2: Change the format of a field when the user presses a button.
    // We can"t call field.setFormatter() because that"s a protected method.
    // (Plus it wouldn"t work anyway. The old factory would replace our new
    // formatter with an "old" one next time the field gains or loses
    // focus.)
    // The thing to do is send a new factory to field.setFormatterFactory().
    JPanel pan = new JPanel(new BorderLayout());
    pan.setBorder(new TitledBorder("Demo 2: change format midstream"));
    MaskFormatter lowercase = null;
    try {
      lowercase = new MaskFormatter("LLLL");
    } catch (ParseException pe) {
    }
    final JFormattedTextField field = new JFormattedTextField(lowercase);
    field.setValue("Fore");
    pan.add(field, BorderLayout.CENTER);
    final JButton change = new JButton("change format");
    JPanel changePanel = new JPanel();
    changePanel.add(change);
    pan.add(changePanel, BorderLayout.SOUTH);
    change.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent ae) {
        try {
          field.rumitEdit(); // commit current edit (if any)
          MaskFormatter uppercase = new MaskFormatter("UUUU");
          DefaultFormatterFactory factory = new DefaultFormatterFactory(
              uppercase);
          field.setFormatterFactory(factory);
          change.setEnabled(false);
        } catch (ParseException pe) {
        }
      }
    });
    return pan;
  }
  public static void main(String argv[]) {
    JFrame f = new JFrame("FactoryDemo");
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.getContentPane().add(demo1(), BorderLayout.NORTH);
    f.getContentPane().add(demo2(), BorderLayout.SOUTH);
    f.setSize(240, 160);
    f.setVisible(true);
  }
}





Format and validate input field in Java Swing

  
import java.awt.BorderLayout;
import java.text.NumberFormat;
import javax.swing.JButton;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Main extends JFrame {
  public Main() {
    JPanel panel = new JPanel();
    JLabel label = new JLabel("Number :");
    JFormattedTextField tf = new JFormattedTextField(NumberFormat.getIntegerInstance());
    tf.setColumns(10);
    panel.add(label);
    panel.add(tf);
    JButton button = new JButton("Click Me");
    panel.add(button);
    getContentPane().add(panel, BorderLayout.SOUTH);
    pack();
  }
  public static void main(String[] args) {
    Main tfe = new Main();
    tfe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    tfe.setVisible(true);
  }
}





Formatted TextField Demo

  
/* From http://java.sun.ru/docs/books/tutorial/index.html */
/*
 * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * -Redistribution of source code must retain the above copyright notice, this
 *  list of conditions and the following disclaimer.
 *
 * -Redistribution in binary form must reproduce the above copyright notice,
 *  this list of conditions and the following disclaimer in the documentation
 *  and/or other materials provided with the distribution.
 *
 * Neither the name of Sun Microsystems, Inc. or the names of contributors may
 * be used to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
 * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN")
 * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
 * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
 * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
 * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
 * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 *
 * You acknowledge that this software is not designed, licensed or intended
 * for use in the design, construction, operation or maintenance of any
 * nuclear facility.
 */
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.NumberFormat;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
/**
 * FormattedTextFieldDemo.java is a 1.4 example that
 * requires no other files.
 *
 * It implements a mortgage calculator that uses four
 * JFormattedTextFields.
 */
public class FormattedTextFieldDemo extends JPanel
                                    implements PropertyChangeListener {
    //Values for the fields
    private double amount = 100000;
    private double rate = 7.5;  //7.5%
    private int numPeriods = 30;
    //Labels to identify the fields
    private JLabel amountLabel;
    private JLabel rateLabel;
    private JLabel numPeriodsLabel;
    private JLabel paymentLabel;
    //Strings for the labels
    private static String amountString = "Loan Amount: ";
    private static String rateString = "APR (%): ";
    private static String numPeriodsString = "Years: ";
    private static String paymentString = "Monthly Payment: ";
    //Fields for data entry
    private JFormattedTextField amountField;
    private JFormattedTextField rateField;
    private JFormattedTextField numPeriodsField;
    private JFormattedTextField paymentField;
    //Formats to format and parse numbers
    private NumberFormat amountFormat;
    private NumberFormat percentFormat;
    private NumberFormat paymentFormat;
    public FormattedTextFieldDemo() {
        super(new BorderLayout());
        setUpFormats();
        double payment = computePayment(amount,
                                        rate,
                                        numPeriods);
        //Create the labels.
        amountLabel = new JLabel(amountString);
        rateLabel = new JLabel(rateString);
        numPeriodsLabel = new JLabel(numPeriodsString);
        paymentLabel = new JLabel(paymentString);
        //Create the text fields and set them up.
        amountField = new JFormattedTextField(amountFormat);
        amountField.setValue(new Double(amount));
        amountField.setColumns(10);
        amountField.addPropertyChangeListener("value", this);
        rateField = new JFormattedTextField(percentFormat);
        rateField.setValue(new Double(rate));
        rateField.setColumns(10);
        rateField.addPropertyChangeListener("value", this);
        numPeriodsField = new JFormattedTextField();
        numPeriodsField.setValue(new Integer(numPeriods));
        numPeriodsField.setColumns(10);
        numPeriodsField.addPropertyChangeListener("value", this);
        paymentField = new JFormattedTextField(paymentFormat);
        paymentField.setValue(new Double(payment));
        paymentField.setColumns(10);
        paymentField.setEditable(false);
        paymentField.setForeground(Color.red);
        //Tell accessibility tools about label/textfield pairs.
        amountLabel.setLabelFor(amountField);
        rateLabel.setLabelFor(rateField);
        numPeriodsLabel.setLabelFor(numPeriodsField);
        paymentLabel.setLabelFor(paymentField);
        //Lay out the labels in a panel.
        JPanel labelPane = new JPanel(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(new GridLayout(0,1));
        fieldPane.add(amountField);
        fieldPane.add(rateField);
        fieldPane.add(numPeriodsField);
        fieldPane.add(paymentField);
        //Put the panels in this panel, labels on left,
        //text fields on right.
        setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
        add(labelPane, BorderLayout.CENTER);
        add(fieldPane, BorderLayout.LINE_END);
    }
    /** Called when a field"s "value" property changes. */
    public void propertyChange(PropertyChangeEvent e) {
        Object source = e.getSource();
        if (source == amountField) {
            amount = ((Number)amountField.getValue()).doubleValue();
        } else if (source == rateField) {
            rate = ((Number)rateField.getValue()).doubleValue();
        } else if (source == numPeriodsField) {
            numPeriods = ((Number)numPeriodsField.getValue()).intValue();
        }
        double payment = computePayment(amount, rate, numPeriods);
        paymentField.setValue(new Double(payment));
    }
    /**
     * Create the GUI and show it.  For thread safety,
     * this method should be invoked from the
     * event-dispatching thread.
     */
    private static void createAndShowGUI() {
        //Make sure we have nice window decorations.
        JFrame.setDefaultLookAndFeelDecorated(true);
        //Create and set up the window.
        JFrame frame = new JFrame("FormattedTextFieldDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        //Create and set up the content pane.
        JComponent newContentPane = new FormattedTextFieldDemo();
        newContentPane.setOpaque(true); //content panes must be opaque
        frame.setContentPane(newContentPane);
        //Display the window.
        frame.pack();
        frame.setVisible(true);
    }
    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application"s GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
    //Compute the monthly payment based on the loan amount,
    //APR, and length of loan.
    double computePayment(double loanAmt, double rate, int numPeriods) {
        double I, partial1, denominator, answer;
        numPeriods *= 12;        //get number of months
        if (rate > 0.01) {
            I = rate / 100.0 / 12.0;         //get monthly rate from annual
            partial1 = Math.pow((1 + I), (0.0 - numPeriods));
            denominator = (1 - partial1) / I;
        } else { //rate ~= 0
            denominator = numPeriods;
        }
        answer = (-1 * loanAmt) / denominator;
        return answer;
    }
    //Create and set up number formats. These objects also
    //parse numbers input by user.
    private void setUpFormats() {
        amountFormat = NumberFormat.getNumberInstance();
        percentFormat = NumberFormat.getNumberInstance();
        percentFormat.setMinimumFractionDigits(3);
        paymentFormat = NumberFormat.getCurrencyInstance();
    }
}





Formatted TextField Example

  
/*
Core SWING Advanced Programming 
By Kim Topley
ISBN: 0 13 083292 8       
Publisher: Prentice Hall  
*/

import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.event.DocumentEvent;
import javax.swing.plaf.ruponentUI;
import javax.swing.plaf.metal.MetalTextFieldUI;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Caret;
import javax.swing.text.Document;
import javax.swing.text.Element;
import javax.swing.text.FieldView;
import javax.swing.text.JTextComponent;
import javax.swing.text.PlainDocument;
import javax.swing.text.Position;
import javax.swing.text.Segment;
import javax.swing.text.Utilities;
import javax.swing.text.View;
import javax.swing.text.ViewFactory;
public class FormattedTextFieldExample {
  public static void main(String[] args) {
    try {
        UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
    } catch (Exception evt) {}
  
    JFrame f = new JFrame("Formatted Text Field");
    final FormattedTextField tf = new FormattedTextField();
    FormattedTextField.FormatSpec formatSpec = new FormattedTextField.FormatSpec(
        "(...)-...-....", "(***)-***-****");
    tf.setFormatSpec(formatSpec);
    f.getContentPane().add(tf, "Center");
    f.getContentPane().add(new JLabel("Phone Number: ", JLabel.RIGHT),
        "West");
    tf.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent evt) {
        System.out.println("Field content is <" + tf.getText() + ">");
      }
    });
    f.pack();
    f.setVisible(true);
  }
}
class FormattedTextField extends JTextField {
  public FormattedTextField() {
    this(null, null, 0, null);
  }
  public FormattedTextField(String text, FormatSpec spec) {
    this(null, text, 0, spec);
  }
  public FormattedTextField(int columns, FormatSpec spec) {
    this(null, null, columns, spec);
  }
  public FormattedTextField(String text, int columns, FormatSpec spec) {
    this(null, text, columns, spec);
  }
  public FormattedTextField(Document doc, String text, int columns,
      FormatSpec spec) {
    super(doc, text, columns);
    setFont(new Font("monospaced", Font.PLAIN, 14));
    if (spec != null) {
      setFormatSpec(spec);
    }
  }
  public void updateUI() {
    setUI(new FormattedTextFieldUI());
  }
  public FormatSpec getFormatSpec() {
    return formatSpec;
  }
  public void setFormatSpec(FormattedTextField.FormatSpec formatSpec) {
    FormatSpec oldFormatSpec = this.formatSpec;
    // Do nothing if no change to the format specification
    if (formatSpec.equals(oldFormatSpec) == false) {
      this.formatSpec = formatSpec;
      // Limit the input to the number of markers.
      Document doc = getDocument();
      if (doc instanceof BoundedPlainDocument) {
        ((BoundedPlainDocument) doc).setMaxLength(formatSpec
            .getMarkerCount());
      }
      // Notify a change in the format spec
      firePropertyChange(FORMAT_PROPERTY, oldFormatSpec, formatSpec);
    }
  }
  // Use a model that bounds the input length
  protected Document createDefaultModel() {
    BoundedPlainDocument doc = new BoundedPlainDocument();
    doc
        .addInsertErrorListener(new BoundedPlainDocument.InsertErrorListener() {
          public void insertFailed(BoundedPlainDocument doc,
              int offset, String str, AttributeSet a) {
            // Beep when the field is full
            Toolkit.getDefaultToolkit().beep();
          }
        });
    return doc;
  }
  public static class FormatSpec {
    public FormatSpec(String format, String mask) {
      this.format = format;
      this.mask = mask;
      this.formatSize = format.length();
      if (formatSize != mask.length()) {
        throw new IllegalArgumentException(
            "Format and mask must be the same size");
      }
      for (int i = 0; i < formatSize; i++) {
        if (mask.charAt(i) == MARKER_CHAR) {
          markerCount++;
        }
      }
    }
    public String getFormat() {
      return format;
    }
    public String getMask() {
      return mask;
    }
    public int getFormatSize() {
      return formatSize;
    }
    public int getMarkerCount() {
      return markerCount;
    }
    public boolean equals(Object fmt) {
      return fmt != null && (fmt instanceof FormatSpec)
          && ((FormatSpec) fmt).getFormat().equals(format)
          && ((FormatSpec) fmt).getMask().equals(mask);
    }
    public String toString() {
      return "FormatSpec with format <" + format + ">, mask <" + mask
          + ">";
    }
    private String format;
    private String mask;
    private int formatSize;
    private int markerCount;
    public static final char MARKER_CHAR = "*";
  }
  protected FormatSpec formatSpec;
  public static final String FORMAT_PROPERTY = "format";
}
class BoundedPlainDocument extends PlainDocument {
  public BoundedPlainDocument() {
    // Default constructor - must use setMaxLength later
    this.maxLength = 0;
  }
  public BoundedPlainDocument(int maxLength) {
    this.maxLength = maxLength;
  }
  public BoundedPlainDocument(AbstractDocument.Content content, int maxLength) {
    super(content);
    if (content.length() > maxLength) {
      throw new IllegalArgumentException(
          "Initial content larger than maximum size");
    }
    this.maxLength = maxLength;
  }
  public void setMaxLength(int maxLength) {
    if (getLength() > maxLength) {
      throw new IllegalArgumentException(
          "Current content larger than new maximum size");
    }
    this.maxLength = maxLength;
  }
  public int getMaxLength() {
    return maxLength;
  }
  public void insertString(int offset, String str, AttributeSet a)
      throws BadLocationException {
    if (str == null) {
      return;
    }
    // Note: be careful here - the content always has a
    // trailing newline, which should not be counted!
    int capacity = maxLength + 1 - getContent().length();
    if (capacity >= str.length()) {
      // It all fits
      super.insertString(offset, str, a);
    } else {
      // It doesn"t all fit. Add as much as we can.
      if (capacity > 0) {
        super.insertString(offset, str.substring(0, capacity), a);
      }
      // Finally, signal an error.
      if (errorListener != null) {
        errorListener.insertFailed(this, offset, str, a);
      }
    }
  }
  public void addInsertErrorListener(InsertErrorListener l) {
    if (errorListener == null) {
      errorListener = l;
      return;
    }
    throw new IllegalArgumentException(
        "InsertErrorListener already registered");
  }
  public void removeInsertErrorListener(InsertErrorListener l) {
    if (errorListener == l) {
      errorListener = null;
    }
  }
  public interface InsertErrorListener {
    public abstract void insertFailed(BoundedPlainDocument doc, int offset,
        String str, AttributeSet a);
  }
  protected InsertErrorListener errorListener; // Unicast listener
  protected int maxLength;
}
class FormattedTextFieldUI extends MetalTextFieldUI implements
    PropertyChangeListener {
  public static ComponentUI createUI(JComponent c) {
    return new FormattedTextFieldUI();
  }
  public FormattedTextFieldUI() {
    super();
  }
  public void installUI(JComponent c) {
    super.installUI(c);
    if (c instanceof FormattedTextField) {
      c.addPropertyChangeListener(this);
      editor = (FormattedTextField) c;
      formatSpec = editor.getFormatSpec();
    }
  }
  public void uninstallUI(JComponent c) {
    super.uninstallUI(c);
    c.removePropertyChangeListener(this);
  }
  public void propertyChange(PropertyChangeEvent evt) {
    if (evt.getPropertyName().equals(FormattedTextField.FORMAT_PROPERTY)) {
      // Install the new format specification
      formatSpec = editor.getFormatSpec();
      // Recreate the View hierarchy
      modelChanged();
    }
  }
  // ViewFactory method - creates a view
  public View create(Element elem) {
    return new FormattedFieldView(elem, formatSpec);
  }
  protected FormattedTextField.FormatSpec formatSpec;
  protected FormattedTextField editor;
}
class FormattedFieldView extends FieldView {
  public FormattedFieldView(Element elem,
      FormattedTextField.FormatSpec formatSpec) {
    super(elem);
    this.contentBuff = new Segment();
    this.measureBuff = new Segment();
    this.workBuff = new Segment();
    this.element = elem;
    buildMapping(formatSpec); // Build the model -> view map
    createContent(); // Update content string
  }
  // View methods start here
  public float getPreferredSpan(int axis) {
    int widthFormat;
    int widthContent;
    if (formatSize == 0 || axis == View.Y_AXIS) {
      return super.getPreferredSpan(axis);
    }
    widthFormat = Utilities.getTabbedTextWidth(measureBuff,
        getFontMetrics(), 0, this, 0);
    widthContent = Utilities.getTabbedTextWidth(contentBuff,
        getFontMetrics(), 0, this, 0);
    return Math.max(widthFormat, widthContent);
  }
  public Shape modelToView(int pos, Shape a, Position.Bias b)
      throws BadLocationException {
    a = adjustAllocation(a);
    Rectangle r = new Rectangle(a.getBounds());
    FontMetrics fm = getFontMetrics();
    r.height = fm.getHeight();
    int oldCount = contentBuff.count;
    if (pos < offsets.length) {
      contentBuff.count = offsets[pos];
    } else {
      // Beyond the end: point to the location
      // after the last model position.
      contentBuff.count = offsets[offsets.length - 1] + 1;
    }
    int offset = Utilities.getTabbedTextWidth(contentBuff, metrics, 0,
        this, element.getStartOffset());
    contentBuff.count = oldCount;
    r.x += offset;
    r.width = 1;
    return r;
  }
  public int viewToModel(float fx, float fy, Shape a, Position.Bias[] bias) {
    a = adjustAllocation(a);
    bias[0] = Position.Bias.Forward;
    int x = (int) fx;
    int y = (int) fy;
    Rectangle r = a.getBounds();
    int startOffset = element.getStartOffset();
    int endOffset = element.getEndOffset();
    if (y < r.y || x < r.x) {
      return startOffset;
    } else if (y > r.y + r.height || x > r.x + r.width) {
      return endOffset - 1;
    }
    // The given position is within the bounds of the view.
    int offset = Utilities.getTabbedTextOffset(contentBuff,
        getFontMetrics(), r.x, x, this, startOffset);
    // The offset includes characters not in the model,
    // so get rid of them to return a true model offset.
    for (int i = 0; i < offsets.length; i++) {
      if (offset <= offsets[i]) {
        offset = i;
        break;
      }
    }
    // Don"t return an offset beyond the data
    // actually in the model.
    if (offset > endOffset - 1) {
      offset = endOffset - 1;
    }
    return offset;
  }
  public void insertUpdate(DocumentEvent changes, Shape a, ViewFactory f) {
    super.insertUpdate(changes, adjustAllocation(a), f);
    createContent(); // Update content string
  }
  public void removeUpdate(DocumentEvent changes, Shape a, ViewFactory f) {
    super.removeUpdate(changes, adjustAllocation(a), f);
    createContent(); // Update content string
  }
  // End of View methods
  // View drawing methods: overridden from PlainView
  protected void drawLine(int line, Graphics g, int x, int y) {
    // Set the colors
    JTextComponent host = (JTextComponent) getContainer();
    unselected = (host.isEnabled()) ? host.getForeground() : host
        .getDisabledTextColor();
    Caret c = host.getCaret();
    selected = c.isSelectionVisible() ? host.getSelectedTextColor()
        : unselected;
    int p0 = element.getStartOffset();
    int p1 = element.getEndOffset() - 1;
    int sel0 = ((JTextComponent) getContainer()).getSelectionStart();
    int sel1 = ((JTextComponent) getContainer()).getSelectionEnd();
    try {
      // If the element is empty or there is no selection
      // in this view, just draw the whole thing in one go.
      if (p0 == p1 || sel0 == sel1 || inView(p0, p1, sel0, sel1) == false) {
        drawUnselectedText(g, x, y, 0, contentBuff.count);
        return;
      }
      // There is a selection in this view. Draw up to three regions:
      //  (a) The unselected region before the selection.
      //  (b) The selected region.
      //  (c) The unselected region after the selection.
      // First, map the selected region offsets to be relative
      // to the start of the region and then map them to view
      // offsets so that they take into account characters not
      // present in the model.
      int mappedSel0 = mapOffset(Math.max(sel0 - p0, 0));
      int mappedSel1 = mapOffset(Math.min(sel1 - p0, p1 - p0));
      if (mappedSel0 > 0) {
        // Draw an initial unselected region
        x = drawUnselectedText(g, x, y, 0, mappedSel0);
      }
      x = drawSelectedText(g, x, y, mappedSel0, mappedSel1);
      if (mappedSel1 < contentBuff.count) {
        drawUnselectedText(g, x, y, mappedSel1, contentBuff.count);
      }
    } catch (BadLocationException e) {
      // Should not happen!
    }
  }
  protected int drawUnselectedText(Graphics g, int x, int y, int p0, int p1)
      throws BadLocationException {
    g.setColor(unselected);
    workBuff.array = contentBuff.array;
    workBuff.offset = p0;
    workBuff.count = p1 - p0;
    return Utilities.drawTabbedText(workBuff, x, y, g, this, p0);
  }
  protected int drawSelectedText(Graphics g, int x, int y, int p0, int p1)
      throws BadLocationException {
    workBuff.array = contentBuff.array;
    workBuff.offset = p0;
    workBuff.count = p1 - p0;
    g.setColor(selected);
    return Utilities.drawTabbedText(workBuff, x, y, g, this, p0);
  }
  // End of View drawing methods
  // Build the model-to-view mapping
  protected void buildMapping(FormattedTextField.FormatSpec formatSpec) {
    formatSize = formatSpec != null ? formatSpec.getFormatSize() : 0;
    if (formatSize != 0) {
      // Save the format string as a character array
      formatChars = formatSpec.getFormat().toCharArray();
      // Allocate a buffer to store the formatted string
      formattedContent = new char[formatSize];
      contentBuff.offset = 0;
      contentBuff.count = formatSize;
      contentBuff.array = formattedContent;
      // Keep the mask for computing
      // the preferred horizontal span, but use
      // a wide character for measurement
      char[] maskChars = formatSpec.getMask().toCharArray();
      measureBuff.offset = 0;
      measureBuff.array = maskChars;
      measureBuff.count = formatSize;
      // Get the number of markers
      markerCount = formatSpec.getMarkerCount();
      // Allocate an array to hold the offsets
      offsets = new int[markerCount];
      // Create the offset array
      markerCount = 0;
      for (int i = 0; i < formatSize; i++) {
        if (maskChars[i] == FormattedTextField.FormatSpec.MARKER_CHAR) {
          offsets[markerCount++] = i;
          // Replace marker with a wide character
          // in the array used for measurement.
          maskChars[i] = WIDE_CHARACTER;
        }
      }
    }
  }
  // Use the document content and the format
  // string to build the display content
  protected void createContent() {
    try {
      Document doc = getDocument();
      int startOffset = element.getStartOffset();
      int endOffset = element.getEndOffset();
      int length = endOffset - startOffset - 1;
      // If there is no format, use the raw data.
      if (formatSize != 0) {
        // Get the document content
        doc.getText(startOffset, length, workBuff);
        // Initialize the output buffer with the
        // format string.
        System.arraycopy(formatChars, 0, formattedContent, 0,
            formatSize);
        // Insert the model content into
        // the target string.
        int count = Math.min(length, markerCount);
        int firstOffset = workBuff.offset;
        // Place the model data into the output array
        for (int i = 0; i < count; i++) {
          formattedContent[offsets[i]] = workBuff.array[i
              + firstOffset];
        }
      } else {
        doc.getText(startOffset, length, contentBuff);
      }
    } catch (BadLocationException bl) {
      contentBuff.count = 0;
    }
  }
  // Map a document offset to a view offset.
  protected int mapOffset(int pos) {
    pos -= element.getStartOffset();
    if (pos >= offsets.length) {
      return contentBuff.count;
    } else {
      return offsets[pos];
    }
  }
  // Determines whether the selection intersects
  // a given range of model offsets.
  protected boolean inView(int p0, int p1, int sel0, int sel1) {
    if (sel0 >= p0 && sel0 < p1) {
      return true;
    }
    if (sel0 < p0 && sel1 >= p0) {
      return true;
    }
    return false;
  }
  protected char[] formattedContent; // The formatted content for display
  protected char[] formatChars; // The format string as characters
  protected Segment contentBuff; // Segment pointing to formatted content
  protected Segment measureBuff; // Segment pointing to mask string
  protected Segment workBuff; // Segment used for scratch purposes
  protected Element element; // The mapped element
  protected int[] offsets; // Model-to-view offsets
  protected Color selected; // Selected text color
  protected Color unselected; // Unselected text color
  protected int formatSize; // Length of the formatting string
  protected int markerCount; // Number of markers in the format
  protected static final char WIDE_CHARACTER = "m";
}





Formatter Factory Demo

  
/* From http://java.sun.ru/docs/books/tutorial/index.html */
/*
 * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * -Redistribution of source code must retain the above copyright notice, this
 *  list of conditions and the following disclaimer.
 *
 * -Redistribution in binary form must reproduce the above copyright notice,
 *  this list of conditions and the following disclaimer in the documentation
 *  and/or other materials provided with the distribution.
 *
 * Neither the name of Sun Microsystems, Inc. or the names of contributors may
 * be used to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
 * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN")
 * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
 * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
 * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
 * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
 * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 *
 * You acknowledge that this software is not designed, licensed or intended
 * for use in the design, construction, operation or maintenance of any
 * nuclear facility.
 */
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.NumberFormat;
import java.text.ParseException;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.text.DefaultFormatterFactory;
import javax.swing.text.NumberFormatter;
/**
 * FormatterFactoryDemo.java is a 1.4 example that
 * requires no other files.
 */
public class FormatterFactoryDemo extends JPanel
                                  implements PropertyChangeListener {
    //Values for the text fields
    private double amount = 100000;
    private double rate = .075;  //7.5 %
    private int numPeriods = 30;
    //Labels to identify the fields
    private JLabel amountLabel;
    private JLabel rateLabel;
    private JLabel numPeriodsLabel;
    private JLabel paymentLabel;
    //Strings for the labels
    private static String amountString = "Loan Amount: ";
    private static String rateString = "APR (%): ";
    private static String numPeriodsString = "Years: ";
    private static String paymentString = "Monthly Payment: ";
    //Fields for data entry
    private JFormattedTextField amountField;
    private JFormattedTextField rateField;
    private JFormattedTextField numPeriodsField;
    private JFormattedTextField paymentField;
    //Formats to format and parse numbers
    private NumberFormat amountDisplayFormat;
    private NumberFormat amountEditFormat;
    private NumberFormat percentDisplayFormat;
    private NumberFormat percentEditFormat;
    private NumberFormat paymentFormat;
    public FormatterFactoryDemo() {
        super(new BorderLayout());
        setUpFormats();
        double payment = computePayment(amount,
                                        rate,
                                        numPeriods);
        //Create the labels.
        amountLabel = new JLabel(amountString);
        rateLabel = new JLabel(rateString);
        numPeriodsLabel = new JLabel(numPeriodsString);
        paymentLabel = new JLabel(paymentString);
        //Create the text fields and set them up.
        amountField = new JFormattedTextField(
                            new DefaultFormatterFactory(
                                new NumberFormatter(amountDisplayFormat),
                                new NumberFormatter(amountDisplayFormat),
                                new NumberFormatter(amountEditFormat)));
        amountField.setValue(new Double(amount));
        amountField.setColumns(10);
        amountField.addPropertyChangeListener("value", this);
        NumberFormatter percentEditFormatter =
                new NumberFormatter(percentEditFormat) {
            public String valueToString(Object o)
                  throws ParseException {
                Number number = (Number)o;
                if (number != null) {
                    double d = number.doubleValue() * 100.0;
                    number = new Double(d);
                }
                return super.valueToString(number);
            }
            public Object stringToValue(String s)
                   throws ParseException {
                Number number = (Number)super.stringToValue(s);
                if (number != null) {
                    double d = number.doubleValue() / 100.0;
                    number = new Double(d);
                }
                return number;
            }
        };
        rateField = new JFormattedTextField(
                             new DefaultFormatterFactory(
                                new NumberFormatter(percentDisplayFormat),
                                new NumberFormatter(percentDisplayFormat),
                                percentEditFormatter));
        rateField.setValue(new Double(rate));
        rateField.setColumns(10);
        rateField.addPropertyChangeListener("value", this);
        numPeriodsField = new JFormattedTextField();
        numPeriodsField.setValue(new Integer(numPeriods));
        numPeriodsField.setColumns(10);
        numPeriodsField.addPropertyChangeListener("value", this);
        paymentField = new JFormattedTextField(paymentFormat);
        paymentField.setValue(new Double(payment));
        paymentField.setColumns(10);
        paymentField.setEditable(false);
        paymentField.setForeground(Color.red);
        //Tell accessibility tools about label/textfield pairs.
        amountLabel.setLabelFor(amountField);
        rateLabel.setLabelFor(rateField);
        numPeriodsLabel.setLabelFor(numPeriodsField);
        paymentLabel.setLabelFor(paymentField);
        //Lay out the labels in a panel.
        JPanel labelPane = new JPanel(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(new GridLayout(0,1));
        fieldPane.add(amountField);
        fieldPane.add(rateField);
        fieldPane.add(numPeriodsField);
        fieldPane.add(paymentField);
        //Put the panels in this panel, labels on left,
        //text fields on right.
        setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
        add(labelPane, BorderLayout.CENTER);
        add(fieldPane, BorderLayout.LINE_END);
    }
    /** Called when a field"s "value" property changes. */
    public void propertyChange(PropertyChangeEvent e) {
        Object source = e.getSource();
        if (source == amountField) {
            amount = ((Number)amountField.getValue()).doubleValue();
        } else if (source == rateField) {
            rate = ((Number)rateField.getValue()).doubleValue();
        } else if (source == numPeriodsField) {
            numPeriods = ((Number)numPeriodsField.getValue()).intValue();
        }
        double payment = computePayment(amount, rate, numPeriods);
        paymentField.setValue(new Double(payment));
    }
    /**
     * Create the GUI and show it.  For thread safety,
     * this method should be invoked from the
     * event-dispatching thread.
     */
    private static void createAndShowGUI() {
        //Make sure we have nice window decorations.
        JFrame.setDefaultLookAndFeelDecorated(true);
        //Create and set up the window.
        JFrame frame = new JFrame("FormatterFactoryDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        //Create and set up the content pane.
        JComponent newContentPane = new FormatterFactoryDemo();
        newContentPane.setOpaque(true); //content panes must be opaque
        frame.setContentPane(newContentPane);
        //Display the window.
        frame.pack();
        frame.setVisible(true);
    }
    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application"s GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
    //Compute the monthly payment based on the loan amount,
    //APR, and length of loan.
    double computePayment(double loanAmt, double rate, int numPeriods) {
        double I, partial1, denominator, answer;
        numPeriods *= 12;        //get number of months
        if (rate > 0.001) {
            I = rate / 12.0;         //get monthly rate from annual
            partial1 = Math.pow((1 + I), (0.0 - numPeriods));
            denominator = (1 - partial1) / I;
        } else { //rate ~= 0
            denominator = numPeriods;
        }
        answer = (-1 * loanAmt) / denominator;
        return answer;
    }
    //Create and set up number formats. These objects also
    //parse numbers input by user.
    private void setUpFormats() {
        amountDisplayFormat = NumberFormat.getCurrencyInstance();
        amountDisplayFormat.setMinimumFractionDigits(0);
        amountEditFormat = NumberFormat.getNumberInstance();
        percentDisplayFormat = NumberFormat.getPercentInstance();
        percentDisplayFormat.setMinimumFractionDigits(2);
        percentEditFormat = NumberFormat.getNumberInstance();
        percentEditFormat.setMinimumFractionDigits(2);
        paymentFormat = NumberFormat.getCurrencyInstance();
    }
}





Input: any number of hyphen-delimeted numbers. Output: int array

  
/*
Java Swing, 2nd Edition
By Marc Loy, Robert Eckstein, Dave Wood, James Elliott, Brian Cole
ISBN: 0-596-00408-7
Publisher: O"Reilly 
*/
// CombinationFormatter.java
//Input: string of form "15-45-22" (any number of hyphen-delimeted numbers)
//<br>Output: int array
//
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.text.DefaultFormatter;
public class CombinationFormatter extends DefaultFormatter {
  public CombinationFormatter() {
    setOverwriteMode(false);
  }
  public Object stringToValue(String string) throws java.text.ParseException {
    // input: string of form "15-45-22" (any number of hyphen-delimeted
    // numbers)
    // output: int array
    String s[] = string.split("-");
    int a[] = new int[s.length];
    for (int j = 0; j < a.length; j += 1)
      try {
        a[j] = Integer.parseInt(s[j]);
      } catch (NumberFormatException nfe) {
        throw new java.text.ParseException(s[j] + " is not an int", 0);
      }
    return a;
  }
  public String valueToString(Object value) throws java.text.ParseException {
    //  input: int array
    // output: string of numerals separated by hyphens
    if (value == null)
      return null;
    if (!(value instanceof int[]))
      throw new java.text.ParseException("expected int[]", 0);
    int a[] = (int[]) value;
    StringBuffer sb = new StringBuffer();
    for (int j = 0; j < a.length; j += 1) {
      if (j > 0)
        sb.append("-");
      sb.append(a[j]);
    }
    return sb.toString();
  }
  protected Action[] getActions() {
    Action[] actions = { new CombinationIncrementer("increment", 1),
        new CombinationIncrementer("decrement", -1) };
    return actions;
  }
  // begin inner class ----------------------------------------
  public class CombinationIncrementer extends AbstractAction {
    protected int delta;
    public CombinationIncrementer(String name, int delta) { // constructor
      super(name); // "name" must match something in the component"s
             // InputMap
      // or else this Action will not get invoked automatically.
      // Valid names include: "reset-field-edit", "increment",
      // "decrement", and "unselect" (see appendix B)
      this.delta = delta;
    }
    public void actionPerformed(java.awt.event.ActionEvent ae) {
      JFormattedTextField ftf = getFormattedTextField(); // from
                                 // AbstractFormtter
      if (ftf == null)
        return;
      String text = ftf.getText();
      if (text == null)
        return;
      int pos = ftf.getCaretPosition();
      int hyphenCount = 0;
      for (int j = 0; j < pos; j += 1)
        // how many hyphens precede the caret?
        if (text.charAt(j) == "-")
          hyphenCount += 1;
      try {
        int a[] = (int[]) stringToValue(text);
        a[hyphenCount] += delta; // change the number at caret position
        if (a[hyphenCount] < 0)
          a[hyphenCount] = 0;
        String newText = valueToString(a);
        ftf.setText(newText); // does not retain caret position
        if ((text.charAt(pos) == "-")
            && (newText.length() < text.length()))
          pos -= 1; // don"t let caret move past "-" when "10" changes
                // to "9"
        ftf.setCaretPosition(pos);
      } catch (Exception e) {
        return;
      }
    }
  }
  // end inner class ----------------------------------------
  public static void main(String argv[]) {
    // a demo main() to show how CombinationFormatter could be used
    int comb1[] = { 35, 11, 19 };
    int comb2[] = { 10, 20, 30 };
    final JFormattedTextField field1 = new JFormattedTextField(
        new CombinationFormatter());
    field1.setValue(comb1);
    final JFormattedTextField field2 = new JFormattedTextField(
        new CombinationFormatter());
    field2.setValue(comb2);
    JPanel pan = new JPanel();
    pan.add(new JLabel("Change the combination from"));
    pan.add(field1);
    pan.add(new JLabel("to"));
    pan.add(field2);
    JButton b = new JButton("Submit");
    b.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent ae) {
        try {
          field1.rumitEdit(); // make sure current edit (if any) gets
                     // committed
          field2.rumitEdit();
        } catch (java.text.ParseException pe) {
        }
        int oldc[] = (int[]) field1.getValue();
        int newc[] = (int[]) field2.getValue();
        //
        // code to validate oldc[] and change to newc[] goes here
        //
      }
    });
    pan.add(b);
    JFrame f = new JFrame("CombinationFormatter Demo");
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.setContentPane(pan);
    f.setSize(360, 100);
    f.setVisible(true);
  }
}





Input Verification Demo

  
/* From http://java.sun.ru/docs/books/tutorial/index.html */
/*
 * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * -Redistribution of source code must retain the above copyright notice, this
 *  list of conditions and the following disclaimer.
 *
 * -Redistribution in binary form must reproduce the above copyright notice,
 *  this list of conditions and the following disclaimer in the documentation
 *  and/or other materials provided with the distribution.
 *
 * Neither the name of Sun Microsystems, Inc. or the names of contributors may
 * be used to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
 * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN")
 * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
 * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
 * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
 * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
 * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 *
 * You acknowledge that this software is not designed, licensed or intended
 * for use in the design, construction, operation or maintenance of any
 * nuclear facility.
 */
/*
 * InputVerificationDemo.java is a 1.4 example that
 * requires no other files.
 */
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import javax.swing.BorderFactory;
import javax.swing.InputVerifier;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
/**
 * InputVerificationDemo.java is a 1.4 example that requires no other files.
 * 
 * Yet another mortgage calculator. However, instead of using a formatted text
 * field, as shown in FormattedTextFieldDemo, this example uses input
 * verification to validate user input.
 */
public class InputVerificationDemo extends JPanel {
  //Default values
  private static double DEFAULT_AMOUNT = 100000;
  private static double DEFAULT_RATE = 7.5; //7.5%
  private static int DEFAULT_PERIOD = 30;
  //Labels to identify the text fields
  private JLabel amountLabel;
  private JLabel rateLabel;
  private JLabel numPeriodsLabel;
  private JLabel paymentLabel;
  //Strings for the labels
  private static String amountString = "Loan Amount (10,000-10,000,000): ";
  private static String rateString = "APR (>= 0%): ";
  private static String numPeriodsString = "Years (1-40): ";
  private static String paymentString = "Monthly Payment: ";
  //Text fields for data entry
  private JTextField amountField;
  private JTextField rateField;
  private JTextField numPeriodsField;
  private JTextField paymentField;
  //Formats to format and parse numbers
  private NumberFormat moneyFormat;
  private NumberFormat percentFormat;
  private DecimalFormat decimalFormat;
  private DecimalFormat paymentFormat;
  private MyVerifier verifier = new MyVerifier();
  public InputVerificationDemo() {
    super(new BorderLayout());
    setUpFormats();
    double payment = computePayment(DEFAULT_AMOUNT, DEFAULT_RATE,
        DEFAULT_PERIOD);
    //Create the labels.
    amountLabel = new JLabel(amountString);
    rateLabel = new JLabel(rateString);
    numPeriodsLabel = new JLabel(numPeriodsString);
    paymentLabel = new JLabel(paymentString);
    //Create the text fields and set them up.
    amountField = new JTextField(moneyFormat.format(DEFAULT_AMOUNT), 10);
    amountField.setInputVerifier(verifier);
    rateField = new JTextField(percentFormat.format(DEFAULT_RATE), 10);
    rateField.setInputVerifier(verifier);
    numPeriodsField = new JTextField(decimalFormat.format(DEFAULT_PERIOD),
        10);
    numPeriodsField.setInputVerifier(verifier);
    paymentField = new JTextField(paymentFormat.format(payment), 10);
    paymentField.setInputVerifier(verifier);
    paymentField.setEditable(false);
    //Remove this component from the focus cycle.
    paymentField.setFocusable(false);
    paymentField.setForeground(Color.red);
    //Register an action listener to handle Return.
    amountField.addActionListener(verifier);
    rateField.addActionListener(verifier);
    numPeriodsField.addActionListener(verifier);
    //Tell accessibility tools about label/textfield pairs.
    amountLabel.setLabelFor(amountField);
    rateLabel.setLabelFor(rateField);
    numPeriodsLabel.setLabelFor(numPeriodsField);
    paymentLabel.setLabelFor(paymentField);
    //Lay out the labels in a panel.
    JPanel labelPane = new JPanel(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(new GridLayout(0, 1));
    fieldPane.add(amountField);
    fieldPane.add(rateField);
    fieldPane.add(numPeriodsField);
    fieldPane.add(paymentField);
    //Put the panels in this panel, labels on left,
    //text fields on right.
    setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
    add(labelPane, BorderLayout.CENTER);
    add(fieldPane, BorderLayout.LINE_END);
  }
  class MyVerifier extends InputVerifier implements ActionListener {
    double MIN_AMOUNT = 10000.0;
    double MAX_AMOUNT = 10000000.0;
    double MIN_RATE = 0.0;
    int MIN_PERIOD = 1;
    int MAX_PERIOD = 40;
    public boolean shouldYieldFocus(JComponent input) {
      boolean inputOK = verify(input);
      makeItPretty(input);
      updatePayment();
      if (inputOK) {
        return true;
      } else {
        Toolkit.getDefaultToolkit().beep();
        return false;
      }
    }
    protected void updatePayment() {
      double amount = DEFAULT_AMOUNT;
      double rate = DEFAULT_RATE;
      int numPeriods = DEFAULT_PERIOD;
      double payment = 0.0;
      //Parse the values.
      try {
        amount = moneyFormat.parse(amountField.getText()).doubleValue();
      } catch (ParseException pe) {
      }
      try {
        rate = percentFormat.parse(rateField.getText()).doubleValue();
      } catch (ParseException pe) {
      }
      try {
        numPeriods = decimalFormat.parse(numPeriodsField.getText())
            .intValue();
      } catch (ParseException pe) {
      }
      //Calculate the result and update the GUI.
      payment = computePayment(amount, rate, numPeriods);
      paymentField.setText(paymentFormat.format(payment));
    }
    //This method checks input, but should cause no side effects.
    public boolean verify(JComponent input) {
      return checkField(input, false);
    }
    protected void makeItPretty(JComponent input) {
      checkField(input, true);
    }
    protected boolean checkField(JComponent input, boolean changeIt) {
      if (input == amountField) {
        return checkAmountField(changeIt);
      } else if (input == rateField) {
        return checkRateField(changeIt);
      } else if (input == numPeriodsField) {
        return checkNumPeriodsField(changeIt);
      } else {
        return true; //shouldn"t happen
      }
    }
    //Checks that the amount field is valid. If it is valid,
    //it returns true; otherwise, returns false. If the
    //change argument is true, this method reigns in the
    //value if necessary and (even if not) sets it to the
    //parsed number so that it looks good -- no letters,
    //for example.
    protected boolean checkAmountField(boolean change) {
      boolean wasValid = true;
      double amount = DEFAULT_AMOUNT;
      //Parse the value.
      try {
        amount = moneyFormat.parse(amountField.getText()).doubleValue();
      } catch (ParseException pe) {
        wasValid = false;
      }
      //Value was invalid.
      if ((amount < MIN_AMOUNT) || (amount > MAX_AMOUNT)) {
        wasValid = false;
        if (change) {
          if (amount < MIN_AMOUNT) {
            amount = MIN_AMOUNT;
          } else { // amount is greater than MAX_AMOUNT
            amount = MAX_AMOUNT;
          }
        }
      }
      //Whether value was valid or not, format it nicely.
      if (change) {
        amountField.setText(moneyFormat.format(amount));
        amountField.selectAll();
      }
      return wasValid;
    }
    //Checks that the rate field is valid. If it is valid,
    //it returns true; otherwise, returns false. If the
    //change argument is true, this method reigns in the
    //value if necessary and (even if not) sets it to the
    //parsed number so that it looks good -- no letters,
    //for example.
    protected boolean checkRateField(boolean change) {
      boolean wasValid = true;
      double rate = DEFAULT_RATE;
      //Parse the value.
      try {
        rate = percentFormat.parse(rateField.getText()).doubleValue();
      } catch (ParseException pe) {
        wasValid = false;
      }
      //Value was invalid.
      if (rate < MIN_RATE) {
        wasValid = false;
        if (change) {
          rate = MIN_RATE;
        }
      }
      //Whether value was valid or not, format it nicely.
      if (change) {
        rateField.setText(percentFormat.format(rate));
        rateField.selectAll();
      }
      return wasValid;
    }
    //Checks that the numPeriods field is valid. If it is valid,
    //it returns true; otherwise, returns false. If the
    //change argument is true, this method reigns in the
    //value if necessary and (even if not) sets it to the
    //parsed number so that it looks good -- no letters,
    //for example.
    protected boolean checkNumPeriodsField(boolean change) {
      boolean wasValid = true;
      int numPeriods = DEFAULT_PERIOD;
      //Parse the value.
      try {
        numPeriods = decimalFormat.parse(numPeriodsField.getText())
            .intValue();
      } catch (ParseException pe) {
        wasValid = false;
      }
      //Value was invalid.
      if ((numPeriods < MIN_PERIOD) || (numPeriods > MAX_PERIOD)) {
        wasValid = false;
        if (change) {
          if (numPeriods < MIN_PERIOD) {
            numPeriods = MIN_PERIOD;
          } else { // numPeriods is greater than MAX_PERIOD
            numPeriods = MAX_PERIOD;
          }
        }
      }
      //Whether value was valid or not, format it nicely.
      if (change) {
        numPeriodsField.setText(decimalFormat.format(numPeriods));
        numPeriodsField.selectAll();
      }
      return wasValid;
    }
    public void actionPerformed(ActionEvent e) {
      JTextField source = (JTextField) e.getSource();
      shouldYieldFocus(source); //ignore return value
      source.selectAll();
    }
  }
  /**
   * Create the GUI and show it. For thread safety, this method should be
   * invoked from the event-dispatching thread.
   */
  private static void createAndShowGUI() {
    //Make sure we have nice window decorations.
    JFrame.setDefaultLookAndFeelDecorated(true);
    //Create and set up the window.
    JFrame frame = new JFrame("InputVerificationDemo");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    //Create and set up the content pane.
    JComponent newContentPane = new InputVerificationDemo();
    newContentPane.setOpaque(true); //content panes must be opaque
    frame.setContentPane(newContentPane);
    //Display the window.
    frame.pack();
    frame.setVisible(true);
  }
  public static void main(String[] args) {
    //Schedule a job for the event-dispatching thread:
    //creating and showing this application"s GUI.
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        createAndShowGUI();
      }
    });
  }
  //Compute the monthly payment based on the loan amount,
  //APR, and length of loan.
  double computePayment(double loanAmt, double rate, int numPeriods) {
    double I, partial1, denominator, answer;
    numPeriods *= 12; //get number of months
    if (rate > 0.01) {
      I = rate / 100.0 / 12.0; //get monthly rate from annual
      partial1 = Math.pow((1 + I), (0.0 - numPeriods));
      denominator = (1 - partial1) / I;
    } else { //rate ~= 0
      denominator = numPeriods;
    }
    answer = (-1 * loanAmt) / denominator;
    return answer;
  }
  //Create and set up number formats. These objects are used
  //for both parsing input and formatting output.
  private void setUpFormats() {
    moneyFormat = (NumberFormat) NumberFormat.getNumberInstance();
    percentFormat = NumberFormat.getNumberInstance();
    percentFormat.setMinimumFractionDigits(3);
    decimalFormat = (DecimalFormat) NumberFormat.getNumberInstance();
    decimalFormat.setParseIntegerOnly(true);
    paymentFormat = (DecimalFormat) NumberFormat.getNumberInstance();
    paymentFormat.setMaximumFractionDigits(2);
    paymentFormat.setNegativePrefix("(");
    paymentFormat.setNegativeSuffix(")");
  }
}





Input Verification Dialog Demo

  
/* From http://java.sun.ru/docs/books/tutorial/index.html */
/*
 * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * -Redistribution of source code must retain the above copyright notice, this
 *  list of conditions and the following disclaimer.
 *
 * -Redistribution in binary form must reproduce the above copyright notice,
 *  this list of conditions and the following disclaimer in the documentation
 *  and/or other materials provided with the distribution.
 *
 * Neither the name of Sun Microsystems, Inc. or the names of contributors may
 * be used to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
 * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN")
 * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
 * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
 * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
 * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
 * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 *
 * You acknowledge that this software is not designed, licensed or intended
 * for use in the design, construction, operation or maintenance of any
 * nuclear facility.
 */
/*
 * InputVerificationDialogDemo.java is a 1.4 example that
 * requires no other files.
 */
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import javax.swing.BorderFactory;
import javax.swing.InputVerifier;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
/**
 * InputVerificationDialogDemo.java is a 1.4 example that requires no other
 * files.
 * 
 * Yet another mortgage calculator. However, instead of using a formatted text
 * field, as shown in FormattedTextFieldDemo, this example uses input
 * verification to validate user input. This one uses a dialog to warn people
 * when their input is bad.
 */
public class InputVerificationDialogDemo extends JPanel {
  //Default values
  private static double DEFAULT_AMOUNT = 100000;
  private static double DEFAULT_RATE = 7.5; //7.5 %
  private static int DEFAULT_PERIOD = 30;
  //Labels to identify the text fields
  private JLabel amountLabel;
  private JLabel rateLabel;
  private JLabel numPeriodsLabel;
  private JLabel paymentLabel;
  //Strings for the labels
  private static String amountString = "Loan Amount (10,000 - 10,000,000): ";
  private static String rateString = "APR (>= 0%): ";
  private static String numPeriodsString = "Years (1-40): ";
  private static String paymentString = "Monthly Payment: ";
  //Text fields for data entry
  private JTextField amountField;
  private JTextField rateField;
  private JTextField numPeriodsField;
  private JTextField paymentField;
  //Formats to format and parse numbers
  private NumberFormat moneyFormat;
  private NumberFormat percentFormat;
  private DecimalFormat decimalFormat;
  private DecimalFormat paymentFormat;
  private NumberFormat integerFormat;
  private MyVerifier verifier = new MyVerifier();
  public InputVerificationDialogDemo() {
    super(new BorderLayout());
    setUpFormats();
    double payment = computePayment(DEFAULT_AMOUNT, DEFAULT_RATE,
        DEFAULT_PERIOD);
    //Create the labels.
    amountLabel = new JLabel(amountString);
    rateLabel = new JLabel(rateString);
    numPeriodsLabel = new JLabel(numPeriodsString);
    paymentLabel = new JLabel(paymentString);
    //Create the text fields and set them up.
    amountField = new JTextField(moneyFormat.format(DEFAULT_AMOUNT), 10);
    amountField.setInputVerifier(verifier);
    rateField = new JTextField(percentFormat.format(DEFAULT_RATE), 10);
    rateField.setInputVerifier(verifier);
    numPeriodsField = new JTextField(decimalFormat.format(DEFAULT_PERIOD),
        10);
    numPeriodsField.setInputVerifier(verifier);
    paymentField = new JTextField(paymentFormat.format(payment), 10);
    paymentField.setInputVerifier(verifier);
    paymentField.setEditable(false);
    //Remove this component from the focus cycle.
    paymentField.setFocusable(false);
    paymentField.setForeground(Color.red);
    //Register an action listener to handle Return.
    amountField.addActionListener(verifier);
    rateField.addActionListener(verifier);
    numPeriodsField.addActionListener(verifier);
    //Tell accessibility tools about label/textfield pairs.
    amountLabel.setLabelFor(amountField);
    rateLabel.setLabelFor(rateField);
    numPeriodsLabel.setLabelFor(numPeriodsField);
    paymentLabel.setLabelFor(paymentField);
    //Lay out the labels in a panel.
    JPanel labelPane = new JPanel(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(new GridLayout(0, 1));
    fieldPane.add(amountField);
    fieldPane.add(rateField);
    fieldPane.add(numPeriodsField);
    fieldPane.add(paymentField);
    //Put the panels in this panel, labels on left,
    //text fields on right.
    setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
    add(labelPane, BorderLayout.CENTER);
    add(fieldPane, BorderLayout.LINE_END);
  }
  class MyVerifier extends InputVerifier implements ActionListener {
    double MIN_AMOUNT = 10000.0;
    double MAX_AMOUNT = 10000000.0;
    double MIN_RATE = 0.0;
    int MIN_PERIOD = 1;
    int MAX_PERIOD = 40;
    String message = null;
    public boolean shouldYieldFocus(JComponent input) {
      boolean inputOK = verify(input);
      makeItPretty(input);
      updatePayment();
      if (inputOK) {
        return true;
      }
      //Avoid possible focus-transfer problems when bringing up
      //the dialog by temporarily removing the input verifier.
      //This is a workaround for bug #4532517.
      input.setInputVerifier(null);
      //Pop up the message dialog.
      message += ".\nPlease try again.";
      JOptionPane.showMessageDialog(null, //no owner frame
          message, //text to display
          "Invalid Value", //title
          JOptionPane.WARNING_MESSAGE);
      //Reinstall the input verifier.
      input.setInputVerifier(this);
      //Beep and then tell whoever called us that we don"t
      //want to yield focus.
      Toolkit.getDefaultToolkit().beep();
      return false;
    }
    protected void updatePayment() {
      double amount = DEFAULT_AMOUNT;
      double rate = DEFAULT_RATE;
      int numPeriods = DEFAULT_PERIOD;
      double payment = 0.0;
      //Parse the values.
      try {
        amount = moneyFormat.parse(amountField.getText()).doubleValue();
      } catch (ParseException pe) {
      }
      try {
        rate = percentFormat.parse(rateField.getText()).doubleValue();
      } catch (ParseException pe) {
      }
      try {
        numPeriods = decimalFormat.parse(numPeriodsField.getText())
            .intValue();
      } catch (ParseException pe) {
      }
      //Calculate the result and update the GUI.
      payment = computePayment(amount, rate, numPeriods);
      paymentField.setText(paymentFormat.format(payment));
    }
    //This method checks input, but should cause no side effects.
    public boolean verify(JComponent input) {
      return checkField(input, false);
    }
    protected void makeItPretty(JComponent input) {
      checkField(input, true);
    }
    protected boolean checkField(JComponent input, boolean changeIt) {
      if (input == amountField) {
        return checkAmountField(changeIt);
      } else if (input == rateField) {
        return checkRateField(changeIt);
      } else if (input == numPeriodsField) {
        return checkNumPeriodsField(changeIt);
      } else {
        return true; //shouldn"t happen
      }
    }
    //Checks that the amount field is valid. If it is valid,
    //it returns true, otherwise it sets the message field and
    //returns false. If the change argument is true, set
    //the textfield to the parsed number so that it looks
    //good -- no letters, for example.
    public boolean checkAmountField(boolean change) {
      boolean wasValid = true;
      double amount = DEFAULT_AMOUNT;
      //Parse the value.
      try {
        amount = moneyFormat.parse(amountField.getText()).doubleValue();
      } catch (ParseException pe) {
        message = "Invalid money format in Loan Amount field";
        return false;
      }
      //Value was invalid.
      if ((amount < MIN_AMOUNT) || (amount > MAX_AMOUNT)) {
        wasValid = false;
        if (amount < MIN_AMOUNT) {
          message = "Loan Amount was < "
              + integerFormat.format(MIN_AMOUNT);
        } else { //amount is greater than MAX_AMOUNT
          message = "Loan Amount was > "
              + integerFormat.format(MAX_AMOUNT);
        }
      }
      //Whether value was valid or not, format it nicely.
      if (change) {
        amountField.setText(moneyFormat.format(amount));
        amountField.selectAll();
      }
      return wasValid;
    }
    //Checks that the rate field is valid. If it is valid,
    //it returns true, otherwise it sets the message field and
    //returns false. If the change argument is true, set the
    //textfield to the parsed number so that it looks good -- no
    //letters, for example.
    public boolean checkRateField(boolean change) {
      boolean wasValid = true;
      double rate = DEFAULT_RATE;
      //Parse the value.
      try {
        rate = percentFormat.parse(rateField.getText()).doubleValue();
      } catch (ParseException pe) {
        message = "Invalid percent format in APR field";
        return false;
      }
      //Value was invalid.
      if (rate < MIN_RATE) {
        wasValid = false;
        message = "Bad value: APR was < " + MIN_RATE;
      }
      //Whether value was valid or not, format it nicely.
      if (change) {
        rateField.setText(percentFormat.format(rate));
        rateField.selectAll();
      }
      return wasValid;
    }
    //Checks that the numPeriods field is valid. If it is valid,
    //it returns true, otherwise it sets the message field and
    //returns false. If the change argument is true, set the
    //textfield to the parsed number so that it looks good -- no
    //letters, for example.
    public boolean checkNumPeriodsField(boolean change) {
      boolean wasValid = true;
      int numPeriods = DEFAULT_PERIOD;
      //Parse the value.
      try {
        numPeriods = decimalFormat.parse(numPeriodsField.getText())
            .intValue();
      } catch (ParseException pe) {
        message = "Invalid decimal format in Years field";
        return false;
      }
      //Value was invalid.
      if (numPeriods < MIN_PERIOD) {
        wasValid = false;
        message = "Bad value: Number of years was < "
            + integerFormat.format(MIN_PERIOD);
      } else if (numPeriods > MAX_PERIOD) {
        wasValid = false;
        message = "Bad value: Number of years was > "
            + integerFormat.format(MAX_PERIOD);
      }
      //Whether value was valid or not, format it nicely.
      if (change) {
        numPeriodsField.setText(decimalFormat.format(numPeriods));
        numPeriodsField.selectAll();
      }
      return wasValid;
    }
    public void actionPerformed(ActionEvent e) {
      JTextField source = (JTextField) e.getSource();
      shouldYieldFocus(source); //ignore return value
      source.selectAll();
    }
  }
  /**
   * Create the GUI and show it. For thread safety, this method should be
   * invoked from the event-dispatching thread.
   */
  private static void createAndShowGUI() {
    //We can"t set this due to bug #4819813.
    //This bug causes the Java look and feel window
    //decorations to be focusable.
    //JFrame.setDefaultLookAndFeelDecorated(true);
    //Create and set up the window.
    JFrame frame = new JFrame("InputVerificationDialogDemo");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    JComponent newContentPane = new InputVerificationDialogDemo();
    newContentPane.setOpaque(true); //content panes must be opaque
    frame.setContentPane(newContentPane);
    //Display the window.
    frame.pack();
    frame.setVisible(true);
  }
  public static void main(String[] args) {
    //Schedule a job for the event-dispatching thread:
    //creating and showing this application"s GUI.
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        createAndShowGUI();
      }
    });
  }
  //Compute the monthly payment based on the loan amount,
  //APR, and length of loan.
  double computePayment(double loanAmt, double rate, int numPeriods) {
    double I, partial1, denominator, answer;
    numPeriods *= 12; //get number of months
    if (rate > 0.01) {
      I = rate / 100.0 / 12.0; //get monthly rate from annual
      partial1 = Math.pow((1 + I), (0.0 - numPeriods));
      denominator = (1 - partial1) / I;
    } else { //rate ~= 0
      denominator = numPeriods;
    }
    answer = (-1 * loanAmt) / denominator;
    return answer;
  }
  //Create and set up number formats. These objects also
  //parse numbers input by user.
  private void setUpFormats() {
    moneyFormat = (NumberFormat) NumberFormat.getNumberInstance();
    percentFormat = NumberFormat.getNumberInstance();
    percentFormat.setMinimumFractionDigits(3);
    decimalFormat = (DecimalFormat) NumberFormat.getNumberInstance();
    decimalFormat.setParseIntegerOnly(true);
    paymentFormat = (DecimalFormat) NumberFormat.getNumberInstance();
    paymentFormat.setMaximumFractionDigits(2);
    paymentFormat.setNegativePrefix("(");
    paymentFormat.setNegativeSuffix(")");
    integerFormat = NumberFormat.getIntegerInstance();
  }
}





JFormattedTextField: an input mask (###) ###-#### for a telephone number

  
import java.awt.Container;
import java.text.ParseException;
import javax.swing.BoxLayout;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.text.MaskFormatter;
public class Main {
  public static void main(String args[]) throws ParseException {
    JFrame f = new JFrame();
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    Container content = f.getContentPane();
    content.setLayout(new BoxLayout(content, BoxLayout.PAGE_AXIS));
    MaskFormatter mf1 = new MaskFormatter("###-###-###");
    mf1.setPlaceholderCharacter("_");
    JFormattedTextField ftf1 = new JFormattedTextField(mf1);
    content.add(ftf1);
    MaskFormatter mf2 = new MaskFormatter("(###) ###-####");
    JFormattedTextField ftf2 = new JFormattedTextField(mf2);
    content.add(ftf2);
    f.setSize(300, 100);
    f.setVisible(true);
  }
}





Make custom Input Text Formatter in Java

  
import java.awt.BorderLayout;
import java.text.ParseException;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.text.DefaultFormatter;
class MyFormatter extends DefaultFormatter {
  public MyFormatter() {
    super();
  }
  public String valueToString(Object arg0) throws ParseException {
    return super.valueToString(arg0);
  }
  public Object stringToValue(String arg0) throws ParseException {
    try {
      int value = Integer.parseInt(arg0);
      if (value >= 1 && value <= 10) {
        return "" + value;
      } else {
        return "Invalid";
      }
    } catch (Exception e) {
      return "Invalid";
    }
  }
}
public class Main extends JFrame {
  public Main() {
    JPanel panel = new JPanel();
    JLabel label = new JLabel("Number :");
    JFormattedTextField tf = new JFormattedTextField(new MyFormatter());
    tf.setColumns(10);
    panel.add(label);
    panel.add(tf);
    getContentPane().add(panel, BorderLayout.SOUTH);
    pack();
  }
  public static void main(String[] args) {
    Main mfe = new Main();
    mfe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    mfe.setVisible(true);
  }
}





Support a date with the custom format: 2009-1-1

  
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.swing.JFormattedTextField;
public class Main {
  public static void main(String[] argv) throws Exception {
    JFormattedTextField tft3 = new JFormattedTextField(new SimpleDateFormat("yyyy-M-d"));
    tft3.setValue(new Date());
  
    Date date = (Date) tft3.getValue();
  }
}





Using an InputVerifier with a formatted textfield

  
/*
Java Swing, 2nd Edition
By Marc Loy, Robert Eckstein, Dave Wood, James Elliott, Brian Cole
ISBN: 0-596-00408-7
Publisher: O"Reilly 
*/
// FtfInputVerifier.java
//An example of using an InputVerifier with a formatted textfield.
//
import javax.swing.BorderFactory;
import javax.swing.InputVerifier;
import javax.swing.JComponent;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class FtfInputVerifier {
  public static void main(String argv[]) {
    java.net.URL u = null;
    try {
      u = new java.net.URL("http://www.ora.ru/");
    } catch (java.net.MalformedURLException ignored) {
    }
    // create two identical JFormattedTextFields
    JFormattedTextField ftf1 = new JFormattedTextField(u);
    JFormattedTextField ftf2 = new JFormattedTextField(u);
    // and set an InputVerifier on one of them
    ftf2.setInputVerifier(new InputVerifier() {
      public boolean verify(JComponent input) {
        if (!(input instanceof JFormattedTextField))
          return true; // give up focus
        return ((JFormattedTextField) input).isEditValid();
      }
    });
    JPanel p = new JPanel(new java.awt.GridLayout(0, 2, 3, 8));
    p.add(new JLabel("plain JFormattedTextField:", JLabel.RIGHT));
    p.add(ftf1);
    p.add(new JLabel("FTF with InputVerifier:", JLabel.RIGHT));
    p.add(ftf2);
    p.add(new JLabel("plain JTextField:", JLabel.RIGHT));
    p.add(new JTextField(u.toString()));
    p.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
    JFrame f = new JFrame("FtfInputVerifier");
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.getContentPane().add(
        new JLabel("Try to delete the colon in each field.",
            JLabel.CENTER), java.awt.BorderLayout.NORTH);
    f.getContentPane().add(p, java.awt.BorderLayout.CENTER);
    f.pack();
    f.setVisible(true);
  }
}