JavaFX用TextFormatter实现动态掩码货币TextField 适配小数格式化需求
支持小数的JavaFX货币输入框TextFormatter实现
原有实现仅处理整数部分的千位分隔,未区分整数/小数段,且正则不支持逗号作为小数分隔符,修改后可满足你需要的输入254648,32自动转换为254.648,32的需求。
核心修改点
- 调整正则匹配规则,允许最多1个逗号作为小数分隔符,限制小数位最多2位
- 拆分输入内容为整数段、小数段两部分,千位分隔符仅作用于整数段
- 长度校验改为仅统计数字位数,避免分隔符占用长度配额
完整实现代码
public class MoneyTextFieldOperator implements UnaryOperator<TextFormatter.Change> { // 千位分隔符 final char thousandSeparator = '.'; // 小数分隔符 final char decimalSeparator = ','; final Pattern p; // 最大数字长度(不含分隔符) int maxDigitLength; public MoneyTextFieldOperator(int maxDigitLength) { this.maxDigitLength = maxDigitLength; // 正则允许数字、千位分隔符、小数分隔符 this.p = Pattern.compile("[0-9.,]*"); } @Override public TextFormatter.Change apply(final TextFormatter.Change c) { if (!c.isContentChange()) { return c; } final String newText = c.getControlNewText(); if (newText.isEmpty()) { return c; } // 拦截非法字符 if (!this.p.matcher(newText).matches()) { return null; } // 统计纯数字长度,判断是否超过限制 long digitCount = newText.chars().filter(Character::isDigit).count(); if (digitCount > maxDigitLength) { return null; } // 拆分整数和小数部分 String integerPart; String decimalPart = ""; if (newText.contains(String.valueOf(decimalSeparator))) { int separatorIndex = newText.indexOf(decimalSeparator); integerPart = newText.substring(0, separatorIndex); // 小数部分最多保留2位 decimalPart = newText.substring(separatorIndex + 1) .replaceAll("[^0-9]", "") .substring(0, Math.min(2, newText.substring(separatorIndex + 1).length())); } else { integerPart = newText; } // 过滤整数部分的非数字字符,准备格式化 String pureInteger = integerPart.replaceAll("[^0-9]", ""); StringBuilder formattedInteger = new StringBuilder(); // 从右往左每3位加千位分隔符 for (int i = pureInteger.length() - 1, count = 0; i >= 0; i--, count++) { if (count != 0 && count % 3 == 0) { formattedInteger.append(thousandSeparator); } formattedInteger.append(pureInteger.charAt(i)); } formattedInteger.reverse(); // 拼接最终结果 String finalText = formattedInteger.toString(); if (!decimalPart.isEmpty()) { finalText += decimalSeparator + decimalPart; } // 设置变更内容 c.setRange(0, c.getControlText().length()); c.setText(finalText); c.setCaretPosition(finalText.length()); c.setAnchor(finalText.length()); return c; } }
调用方式
和原有调用逻辑完全一致:
montantTextField.setTextFormatter(new TextFormatter(new MoneyTextFieldOperator(10)));
效果说明
- 整数部分自动按每3位用
.作为千位分隔符格式化 - 输入逗号后自动识别为小数分隔符,小数部分最多保留2位
- 非法字符(除数字、逗号、点之外的字符)会被自动拦截
- 长度限制仅统计数字位数,不会被分隔符占用配额
内容的提问来源于stack exchange,提问作者Youssef Idraiss
相关产品推荐
相关产品推荐

