You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

扩展JFormattedTextField后设置Formatter仍无法限制输入格式的问题

问题

我有一个继承自JFormattedTextField的Renderer类,在其构造函数中配置了Formatter和FormatterFactory以限制输入格式,但仍能输入不符合格式的字符。相关代码如下:

NumberFormat bigDecimalFormat = NumberFormat.getCurrencyInstance();
bigDecimalFormat.setMaximumIntegerDigits(1);
bigDecimalFormat.setMaximumFractionDigits(5);
bigDecimalFormat.setRoundingMode(RoundingMode.HALF_UP);
NumberFormatter numberFormatter = new NumberFormatter(bigDecimalFormat);
numberFormatter.setAllowsInvalid(false);
numberFormatter.setValueClass(BigDecimal.class);
numberFormatter.setMinimum(0.0);
numberFormatter.setMaximum(1.0);
//numberFormatter.setFormat(new DecimalFormat("#.####")); //tried to enable and disable it, but that doesn't help
this.setFormatter(numberFormatter);
this.setFormatterFactory(new DefaultFormatterFactory(numberFormatter));

目前仍可输入类似11.111.111的内容,转换为BigDecimal时会抛出异常。查阅资料发现通常通过构造参数设置Formatter即可生效,但我使用的是setter方法。请问在扩展JFormattedTextField时,如何在构造函数中正确配置以限制输入字符符合指定格式?

解决方法
  • 优先通过构造函数绑定Formatter:JFormattedTextField的构造函数直接传入Formatter的方式,能确保组件初始化阶段就完成格式规则绑定,比后续调用setter更可靠。修改构造函数逻辑:
public class YourRenderer extends JFormattedTextField {
    public YourRenderer() {
        NumberFormat bigDecimalFormat = NumberFormat.getCurrencyInstance();
        bigDecimalFormat.setMaximumIntegerDigits(1);
        bigDecimalFormat.setMaximumFractionDigits(5);
        bigDecimalFormat.setRoundingMode(RoundingMode.HALF_UP);
        NumberFormatter numberFormatter = new NumberFormatter(bigDecimalFormat);
        numberFormatter.setAllowsInvalid(false);
        numberFormatter.setValueClass(BigDecimal.class);
        numberFormatter.setMinimum(BigDecimal.ZERO);
        numberFormatter.setMaximum(BigDecimal.ONE);
        
        // 用父类构造函数传入Formatter,替代setter
        super(numberFormatter);
        // 按需设置自定义FormatterFactory
        this.setFormatterFactory(new DefaultFormatterFactory(numberFormatter));
    }
}
  • 修正数值范围的类型匹配:原代码中setMinimum(0.0)和setMaximum(1.0)传入的是double类型,与setValueClass指定的BigDecimal类型不匹配,会导致范围校验失效。改成传入BigDecimal.ZERO和BigDecimal.ONE,确保校验逻辑正常触发。
  • 拦截无效按键输入:重写processKeyEvent方法,直接拦截不符合规则的按键,从输入源头阻止无效内容:
@Override
protected void processKeyEvent(KeyEvent e) {
    char c = e.getKeyChar();
    // 仅允许数字、单个小数点、退格/删除等控制键
    if (!Character.isDigit(c) 
        && c != KeyEvent.VK_BACK_SPACE 
        && c != KeyEvent.VK_DELETE 
        && !(c == '.' && !getText().contains("."))) {
        e.consume();
        return;
    }
    super.processKeyEvent(e);
}
  • 替换为更可控的DecimalFormat:NumberFormat.getCurrencyInstance()会自动添加货币符号,可能干扰输入逻辑。如果不需要货币符号,直接用DecimalFormat自定义格式更稳妥:
DecimalFormat bigDecimalFormat = new DecimalFormat("#.#####");
bigDecimalFormat.setMaximumIntegerDigits(1);
bigDecimalFormat.setRoundingMode(RoundingMode.HALF_UP);

内容的提问来源于stack exchange,提问作者Eljah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 05:28:21