如何通过修改formato()方法修复JFormattedTextField光标位置异常
问题描述
修改NumberFormatter实现带前缀的货币格式后,输入第一个数字时程序会自动添加前缀,但光标会跳转到数字前方。需要仅修改用于JFormattedTextField构造器的formato()方法来解决光标位置问题。
现有代码
创建JFormattedTextField的代码
textFieldMonto = new javax.swing.JFormattedTextField(formato());
formato()方法代码
private NumberFormatter formato() { DecimalFormat myFormatter = new DecimalFormat("'Gs. '###,##0;'Gs. '###,##0"); NumberFormatter numberFormatter = new NumberFormatter(myFormatter) { // 获得焦点时将光标移到末尾 @Override public void install(JFormattedTextField pField) { super.install(pField); pField.setCaretPosition(pField.getDocument().getLength()); } // 允许空文本,禁止负数 @Override public String valueToString(Object value) throws ParseException { String result = super.valueToString(value); if(super.valueToString(value).startsWith("-")) result = result.replaceFirst("-", ""); // 屏蔽负数 if(value==null) return ""; return result; } // 允许空文本,禁止负数 @Override public Object stringToValue(String text) throws ParseException { if (text.length() == 0 || text.equals("Gs. ")) // 空文本或仅含前缀时返回null return null; text.replaceFirst("-", ""); // 屏蔽负数(原代码存在无效操作) if(!text.startsWith("Gs. ")) // 没有前缀则添加 text = "Gs. " + text; return super.stringToValue(text); } }; numberFormatter.setAllowsInvalid(false); numberFormatter.setMaximum(new BigDecimal("999999999999"));// 最大输入值 numberFormatter.setCommitsOnValidEdit(true);// 每次按键后提交值,而非失去焦点时 return numberFormatter; }
解决方案
修改后的formato()方法
private NumberFormatter formato() { // 简化DecimalFormat模式,正负格式一致无需重复定义 DecimalFormat myFormatter = new DecimalFormat("'Gs. '###,##0"); NumberFormatter numberFormatter = new NumberFormatter(myFormatter) { @Override public void install(JFormattedTextField pField) { super.install(pField); // 获得焦点时将光标移到末尾 pField.setCaretPosition(pField.getDocument().getLength()); // 添加值变化监听器,格式化完成后自动将光标移到末尾 pField.addPropertyChangeListener("value", evt -> { // 使用invokeLater确保在文本更新完成后执行光标调整 javax.swing.SwingUtilities.invokeLater(() -> { int docLength = pField.getDocument().getLength(); if (docLength > 0) { pField.setCaretPosition(docLength); } }); }); } @Override public String valueToString(Object value) throws ParseException { if (value == null) { return ""; } String result = super.valueToString(value); // 移除负号,禁止负数输入 if (result.startsWith("-")) { result = result.replaceFirst("-", ""); } return result; } @Override public Object stringToValue(String text) throws ParseException { if (text.isEmpty() || text.equals("Gs. ")) { return null; } // 修复替换负号的无效操作:String不可变,需重新赋值 text = text.replaceFirst("-", ""); if (!text.startsWith("Gs. ")) { text = "Gs. " + text; } return super.stringToValue(text); } }; numberFormatter.setAllowsInvalid(false); numberFormatter.setMaximum(new BigDecimal("999999999999")); numberFormatter.setCommitsOnValidEdit(true); return numberFormatter; }
修改说明
- 光标位置修复:新增
PropertyChangeListener监听文本框的值变化,每次格式化完成(比如输入第一个数字触发前缀添加)后,通过invokeLater确保文本更新完成后将光标移到末尾,解决光标跳转问题。 - 代码逻辑修复:修正
stringToValue中替换负号的无效操作,因为String是不可变类型,必须将替换结果重新赋值给text变量。 - 格式简化:简化DecimalFormat的模式定义,正负格式一致时无需重复编写。
内容的提问来源于stack exchange,提问作者DcSergio
相关产品推荐
相关产品推荐

