Java/Swing JFC/Formatted TextField
Версия от 18:01, 31 мая 2010; (обсуждение)
Содержание
- 1 A BigDecimal object custom formatter
- 2 Accepting Formatted Input
- 3 A decimal number with one digit following the decimal point;
- 4 A formatter for regular expressions to be used with JFormattedTextField
- 5 A quick demonstration of JFormattedTextField
- 6 Creating a Text Field to Display and Edit a Date
- 7 Creating a Text Field to Display and Edit a Number
- 8 Creating a Text Field to Display and Edit a Phone Number
- 9 Creating a Text Field to Display and Edit a social security number
- 10 Different configurations of JFormattedTextField: Date
- 11 different configurations of JFormattedTextField: Number
- 12 Dynamically change the format
- 13 Field with different formats with focus and without
- 14 Format and validate input field in Java Swing
- 15 Formatted TextField Demo
- 16 Formatted TextField Example
- 17 Formatter Factory Demo
- 18 Input: any number of hyphen-delimeted numbers. Output: int array
- 19 Input Verification Demo
- 20 Input Verification Dialog Demo
- 21 JFormattedTextField: an input mask (###) ###-#### for a telephone number
- 22 Make custom Input Text Formatter in Java
- 23 Support a date with the custom format: 2009-1-1
- 24 Using an InputVerifier with a formatted textfield
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);
}
}