Channels ▼
RSS

Design

Java: Better Interfaces via JFormattedTextField


Putting It All Together

Creating a JFormattedTextField that does it all requires you to do the following steps:

  1. Create an instance of a formatter for display mode (when the control does not have the focus)
  2. Create an instance formatter for edit mode (when the control does have the focus)
  3. Create an instance DefaultFormatterFactory based on the two formatters
  4. Attach the DefaultFormatterFactory to the JFormattedTextField using the setFormatterFactory method
  5. Create an instance of a InputVerifier
  6. Attach the InputVerifier to the JFormattedTextField using the setInputVerifier method


// create the JFormattedTextField
   JFormattedTextField salaryField = new JFormattedTextField();  
// create the formatters, default, display, edit
   NumberFormatter defaultFormatter = new NumberFormatter(new DecimalFormat("#.##"));
   NumberFormatter displayFormatter = 
                 new NumberFormatter(new DecimalFormat("$ #,###.00"));
   NumberFormatter editFormatter = new NumberFormatter(new DecimalFormat("#.##")); 
// set their value classes
   defaultFormatter.setValueClass(Double.class);
   displayFormatter.setValueClass(Double.class);
   editFormatter.setValueClass(Double.class);   
// create and set the DefaultFormatterFactory
   DefaultFormatterFactory salaryFactory = 
       new DefaultFormatterFactory(defaultFormatter,displayFormatter,editFormatter);
   salaryField.setFormatterFactory(salaryFactory);
// create and attach an InputVerifier
  DoubleVerifier salaryVerifier = new DoubleVerifier(0,1000000);// salaries 0 to 1 mil 
  salaryField.setInputVerifier(salaryVerifier);  // attach the verifier

As you can see, this is quite a bit of code to create a fancy equivalent of a JTextField. Doubtless this is one of the reasons why the JFormattedTextField is not covered in many Java texts or used as frequently by programmers. Fortunately, object-oriented programming can come to your aid. Instead of repeating the sequence of code for every field in every program, just create a few reusable classes for common data types. Adding PropertySupport to the classes makes them easy to integrate into the Netbeans GUI designer palette, allowing you to add them to your program graphically like any other control.

The code project attached to this article (and available for download here) provides examples via the following reusable classes:

  • JFormattedTextFields
    • FormattedCurrencyField
    • FormattedDateField
    • FormattedDoubleField
    • FormattedEmailField
    • FormattedIntegerField
    • FormattedPercentField
    • FormattedPhoneField
    • FormattedSSNField

  • Custom verifiers
    • DateVerifier
    • DoubleVerifier
    • EmailVerifier
    • IntegerVerifier
    • MaskVerifier (used by JFormattedPhoneField and JFormattedSSNField)
    • PercentVerifier

  • Custom formatters
    • EmailFormatter
    • PercentFormatter

Figure 2 shows the use of these classes. I will cover FormattedDoubleField and FormattedDateField as examples:

[Click image to view at full size]
Figure 2: Sample application

FormattedDoubleField extends JFormattedTextField. (FormattedDoubleField.java can be downloaded here.) It has properties for the number of decimal places to display (decimalPlaces), the minimum and maximum valid values (minValue, maxValue). Four constructors are provided, a no-arg constructor that uses the default values, a constructor that accepts the number of decimal places, a constructor that accepts the min and max values, and a constructor that accepts the min value, max value, the current value, and number of decimal places. Accessor and mutator methods are provided to change the maxValue, minValue, and decimalPlaces.

The constructor first checks the min and max values, generating an IllegalArgumentException if min is greater than max. A DoubleVerfier (discussed previously) is then created and attached using the setInputVerifier method. Three NumberFormatters are created. The display and edit formatters are created based on the DecimalFormat class. Display includes the grouping character while the edit does not. These formatters are then used to create a DefaultFormatterFactory, which in turn is attached using the setFormatterFactory method. PropertyChange support is provided with the propertySupport variable and implemented using calls to the firePropertyChange method in the mutator methods. The FormattedDoubleField class can be compiled in NetBeans and added to the GUI palette using the Palette Manager.

Program code that uses the FormattedDoubleField just needs to call the getValue and setValue methods. getValue will return an Object that can be cast to a Double, setValue assumes a Double object will be given. A simple adder using three FormattedDoubleFields -- xField, yField, zField -- would look like:


    Double x = (Double)xField.getValue();
    Double y = (Double)yField.getValue();   
    zField.setValue(new Double(x+y));

There is no need to invoke Double.parseDouble or try/catch NumberFormat exceptions. That is all provided along with range checking of the inputs. Implementing similar code using a JTextField would look like:


try{
  double x = Double.parseDouble(xField.getText());
  if(x < min || x > max) {
    JOptionPane.showMessageDialog(this, "invalid value for x");
    return;
  }
}
catch(NumberFormatException exX){
   JOptionPane.showMessageDialog(this, "invalid value for x");
   return;
}

try{
   double y = Double.parseDouble(yField.getText());
   if(y < min || y > max) {
     JOptionPane.showMessageDialog(this, "invalid value for y");
     return;
   }
}
catch(NumberFormatException exY){
   JOptionPane.showMessageDialog(this, "invalid value for y ");
   return;
}

DecimalFormat formatter = new DecimalFormat("#,###.##");
double z = x+y;
xField.setText(formatter.format(z));

FormattedDateField extends JFormattedTextField. (FormattedDateField.java can be downloaded here.) It provides several constructors, a default one that uses the current date, one that accepts a GregorianCalendar object, one that accepts the month, day, year, hour, minute, second as integers, and one that accepts a Date object. The principle constructor first sets the value of the JFormattedTextField to the specified date and time using a SimpleDateFormat object to convert it to a String in the proper format. It then creates a DateVerifier and attaches it using a call to setInputVerifier. A MaskFormatter is created using "##/##/#### ##:##:## UM" as the format string. Recall that the #'s are masks for digits, the U for an uppercase character, and the slashes, spaces, colon, and M are literals. This creates a formatter that allows the user to only change the certain characters leaving the literals in place for guidance. The valid characters for the MaskFormatter are set to the digits 0 to 9 and the characters A and P. Thus the U placeholder can only be replaced with an A or P. A DefaultFormatterFactory is then created with the MaskFormatter and attached using the setFormatterFactory method. A DateFormatter could have been created using the SimpleDateFormat class and used in place of the MaskFormatter. However, the DateFormatter allows editing of the entire text and does not "lock down" literal characters. Giving less guidance for the user and leaving a greater chance for error.

Since a MaskFormatter is being used, the getValue and setValue methods associated with the JFormattedTextField class will return a String. Separate getDate and setDate methods were added to provide support for Date objects. The getDate method uses a SimpleDateFormat object to parse the text value into a Date object; setDate uses the same SimpleDateFormat object to format a Date into a String. A Timer object was added to allow the field to automatically update itself. A boolean variable "ticking" can be turned on/off to control the Timer.

Program code that accesses a FormattedDateField can call the getDate or getValue to retrieve the contents of the field.


Date date1 = dateField.getDate();
String date2 = (String)dateField.getValue();

Conclusion

This article has demonstrated how to use JFormattedTextFields for numeric data, fixed size string data, and custom data. Using JFormattedTextFields in place of JTextFields requires extra upfront coding for initializing the interface, but saves code when accessing and processing the data. JFormattedTextFields also provide a more fool-proof interface and better guidance to the user. Coding efficiency and reusability is further enhanced if custom classes based on JFormattedTextField are created for generic data types.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video