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

如何通过修改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;
}

修改说明

  1. 光标位置修复:新增PropertyChangeListener监听文本框的值变化,每次格式化完成(比如输入第一个数字触发前缀添加)后,通过invokeLater确保文本更新完成后将光标移到末尾,解决光标跳转问题。
  2. 代码逻辑修复:修正stringToValue中替换负号的无效操作,因为String是不可变类型,必须将替换结果重新赋值给text变量。
  3. 格式简化:简化DecimalFormat的模式定义,正负格式一致时无需重复编写。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 18:25:39