简体   繁体   中英

Exclude zero from JFormattedTextField

I have an JFormattedTextField created by

JFormattedTextField(NumberFormat.getInstance);  

I would like to augment its behaviour, so that if the user enters a zero and the field loses focus, it reacts exactly as if the user had entered eg "foo".

Using an InputVerifier somehow wrecked the reverting behaviour, and using a custom subclass of DecimalFormat did not revert when zero was entered, but instead cleared the field.
(By zero I mean, anything that parses to BigDecimal.ZERO .)

The code I used:

new DecimalFormat(){
{
    setParseBigDecimal(true);
}
public Number parse(String txt, ParsePosition pos){
     BigDecimal num = (BigDecimal) super.parse(txt, pos);
     if(num == null || num.compareTo(BigDecimal.ZERO) == 0)
          return null;
     else return num;
}

Zero was not accepted then, but the field only reverted on letters entered.

You can add a FocusListener to do a similar check to what is done internally:

JFormattedTextField ftf = new JFormattedTextField(NumberFormat.getInstance());
ftf.addFocusListener(new FocusAdapter() {

    @Override
    public void focusLost(FocusEvent e) {

        Object lastValid = ftf.getValue();
        try {
            ftf.commitEdit();
        } catch (ParseException e1) {
            ftf.setValue(lastValid);
        }
        Object newValue = ftf.getValue();
        if (newValue instanceof Long)
            if ((Long) newValue == 0l)
                ftf.setValue(lastValid);
    }
});

Notes on this approach:

  • A JFormattedTextField has a focusLostBehavior which instructs what to do on focus lost. I assumed it will always be COMMIT_OR_REVERT (the default).

  • Be careful if you registered a PropertyChangeListener to the text field, as I did not handle firing its events carefully. While inputs which can't be parsed will "immediately" be reverted (and not fire a PropertyChangeEvent event), a value which is parsed to 0 will first be committed (and fire a PropertyChangeEvent ) and only then reverted (firing a PropertyChangeEvent again).

Notes on other approaches:

  • While I think this is the most direct approach, there are almost certainly other ways to accomplish this which involve extending and overriding some methods. The hierarchy from the text field itself to the format chosen for it can be a bit complicated and modification can be done in some of the steps, though care should be taken to not break anything.

  • Input verification can also work, but it behaves differently - it holds the focus until the input is verified, instead of allowing its loss and reverting. It is ultimately the programmer's choice.

Putting something similar to the code by @user1803551 into a PropertyChangeListener worked even better - before, there was an issue with hitting "return" when there was a default button in the form - it would receive "action performed" without the user having to change the input value. Plus, we get by without an additional variable.

DecimalFormat format = new DecimalFormat();
format.setParseBigDecimal(true);
JFormattedTextField ftf = new JFormattedTextField(format):
ftf.addPropertyChangeListener(new PropertyChangeListener() {

    public void propertyChange(PropertyChangeEvent evt) {
        if (evt.getPropertyName().equals("value"))
            if ( ((BigDecimal) evt.getNewValue()).compareTo(BigDecimal.ZERO) ==0 )
                ftf.setValue(evt.getOldValue());
        }

    });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM