从 JFormattedTextField 中排除零

Exclude zero from JFormattedTextField

我有一个由

创建的JFormattedTextField
JFormattedTextField(NumberFormat.getInstance);  

我想增强它的行为,这样如果用户 输入零并且该字段失去焦点,它的反应就像用户输入了例如"foo"。

使用 InputVerifier 以某种方式破坏了还原行为,并且使用 DecimalFormat 的自定义子类在输入零时没有还原,而是清除了字段。
(我的意思是零,任何解析为 BigDecimal.ZERO 的东西。)

我使用的代码:

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;
}

当时不接受零,但该字段仅在输入字母时恢复。

您可以添加一个 FocusListener 来对内部完成的内容进行类似的检查:

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);
    }
});

关于此方法的注释:

  • A JFormattedTextField 有一个 focusLostBehavior 指示在失去焦点时该怎么做。我假设它总是 COMMIT_OR_REVERT (默认值)。

  • 如果您将 PropertyChangeListener 注册到文本字段,请小心,因为我没有仔细处理触发它的事件。虽然无法解析的输入将 "immediately" 还原(并且不会触发 PropertyChangeEvent 事件),但解析为 0 的值将首先被提交(并触发 PropertyChangeEvent) 然后才恢复(再次触发 PropertyChangeEvent)。

关于其他方法的注释:

  • 虽然我认为这是最直接的方法,但几乎可以肯定还有其他方法可以实现这一点,其中涉及扩展和覆盖某些方法。从文本字段本身到为其选择的格式的层次结构可能有点复杂,可以在某些步骤中进行修改,但应注意不要破坏任何内容。

  • 输入验证也可以工作,但它的行为不同——它保持焦点直到输入被验证,而不是允许它丢失和恢复。最终还是程序员的选择。

将类似于 @user1803551 的代码放入 PropertyChangeListener 中效果更好 - 之前,当表单中有默认按钮时点击 "return" 会出现问题 - 它会接收 "action performed" 而无需用户更改输入值。另外,我们不用额外的变量就可以了。

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());
        }

    });