扩展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
相关产品推荐
相关产品推荐

