Java Tips Weblog

  • Blog Stats

    • 2,572,323 hits
  • Categories

  • Archives

Formatted Text Field Tips

Posted by Rob Camick on February 21, 2010

A JFormattedTextField provides the ability for text to be formatted depending on the formatter specified. This formatting causes the formatted text field to behave differently than other text components in some cases. It also makes it a little more difficult to customize the behaviour in other situations.

The behaviour difference of the formatted text field happens because formatting of the text can be done when the text field receives focus or loses focus. As a result of this formatting the caret is always positioned at the start of the text field, whether you tab to the text field or use the mouse to click on the text field. With other text components the caret position is retained when you tab from field to field and the caret position is reset depending on the charcter you click on when using the mouse.

The solution presented here will allow you to retain the caret position when using the mouse on a formatted text field. The default behaviour actually does occur when using the mouse. That is, the caret is positioned on the character that is clicked. The problem is that when the formatter takes control, the caret position is reset to 0. So the simple solution is to use a MouseListener to track the initial caret position and then use the SwingUtilities.invokeLater() method to reset the caret back to its original position. The CaretPositionListener is used as a MouseListener to provide this functionality. Simple usage of the CaretPositionListener class could be:

formattedTextField.addMouseListener( new CaretPositionListener() );

This works in most cases, however the formatted text field has another feature that can cause problems. The formatting can be different depending on whether the text field has focus or not. In the image below the last 3 text fields were all created using the code from below:

Integer value = Integer.valueOf( 1234567890 );
JFormattedTextField ftf = new JFormattedTextField( value );

The fourth text field has focus and notice how the “thousands” formatting characters have been removed. This causes problems when positioning the caret as the mouse click occured while the formatting characters where displayed.

The CaretPositionListener can also handle this situation. The caret position is recalculated based on the number of formatting characters that have been removed. I do not know of any way to query the formatter to determine if this “dynamic” formatting based on focus will happen or not, so you must invoke the setDynamicFormatting() method. So the code to use a formatted text field in this situation would be:

Integer value = Integer.valueOf( 1234567890 );
JFormattedTextField ftf = new JFormattedTextField( value );
CaretPositionListener cpl = new CaretPositionListener( ftf );
cpl.setDynamicFormatting( true );

Play with the WebStart demo below. First tab to each text field to note the behaviour. Then use the mouse to click on a specific character and note the behaviour. Hopefully the CaretPositionListener class will provide the behaviour you desire.

Another feature that is commonly used in a JTextField is to select all the text when the component gains focus. This is generally done by adding a FocusListener to the text field and by invoking the selectAll() method in the focusGained() method. Again, this is a problem with a JFormattedTextField because the selection will be removed when the caret is reset to the start of the text field. The solution is again to make sure you wrap the selectAll() method in a SwingUtilities.invokeLater(). So your FocusListener might look like:

FocusListener fl = new FocusAdapter()
{
    public void focusGained(final FocusEvent e)      
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                JTextField tf = (JTextField)e.getSource();
                tf.selectAll();
            }
        });
    }
};
textField.addFocusListener( fl );

Hopefully these simple tips will get you pointed in the right direction.

Get The Code

CaretPositionListener.java
CaretPositionListenerDemo.java

5 Responses to “Formatted Text Field Tips”

  1. Very nice. Thanks a lot!

  2. Wouter De Geest said

    Nice solution!
    One small problem is that you should probably differ between pressing and selecting mode. As now when the user wants to select text, the selection will be removed after the caret has been set.

    Adding these two lines in the beginning of the mousePressed should solve this:

    public void mousePressed(final MouseEvent me) {
        if (me.getClickCount() >= 2) {
            return;
        }
        ...
    }
    
  3. terryconsult said

    Hello Rob,
    I have a JFormattedTextField whose formatFactory is set. I face problem like – on inputting data when the thousands comma comes due to format the caret moves 1 digit inner resulting in wrong input. I added your CaretPositionListener to my formatTextfield and also set its dynamicFormatting to true. Yet no success. This is my code :

    DecimalFormat numberFormat = (DecimalFormat) DecimalFormat.getNumberInstance();
    numberFormat.setMaximumFractionDigits(2);
    numberFormat.setMinimumFractionDigits(2);
    numberFormat.setRoundingMode(RoundingMode.HALF_UP);

    formatter = new InternationalFormatter(numberFormat);
    formatter.setAllowsInvalid(false);
    formatter.setMinimum(0.00);
    formatter.setMaximum(999999.99);

    this.buyPriceTxt.setFormatterFactory(new AbstractFormatterFactory() {
    @Override
    public AbstractFormatter getFormatter(JFormattedTextField tf) {
    return formatter;
    }
    });

    CaretPositionListener cpl = new CaretPositionListener(this.buyPriceTxt);
    cpl.setDynamicFormatting(true);

    It also has a DocumentListener (code is too long so didn’t add here), I tried without adding DocumentListener, yet no good results. Can you point me where am I going wrong ? Or what should I do to achieve the goal.

    Thanks.

Leave a comment