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

如何在JFormattedTextField中动态切换MaskFormatter?

问题描述

我正在用Java开发一个简单的登录应用,使用带有MaskFormatter的JFormattedTextField作为用户输入控件。需求是:

  • 当输入框失去焦点时移除MaskFormatter(因为要显示占位符)
  • 获得焦点时重新添加MaskFormatter,仅在用户操作输入框时应用格式

目前我只知道通过构造方法添加MaskFormatter,尝试用setFormatterFactory方法但不清楚用法,也没找到相关资料,以下是我的代码:

初始化代码

usuario = new JFormattedTextField(new MaskFormatter("########U"));
usuario.addFocusListener(this);
usuario.setBounds(64, 182, 267, 24);
usuario.setBorder(null);
usuario.setText("Introduce tu nombre de usuario");
usuario.setForeground(new Color(204, 204, 204));
usuario.setFont(new Font("Cascadia Code", Font.PLAIN, 11));
contentPane.add(usuario);

focusGained方法

@Override
public void focusGained(FocusEvent e) {
    if (usuario == e.getSource()) {
                    // set MaskFormatter here
        if (usuario.getText().equals("Introduce tu nombre de usuario")) {
            usuario.setText("");
            usuario.setForeground(Color.BLACK);
        }
    }
}

focusLost方法

@Override
public void focusLost(FocusEvent e) {
    if (usuario == e.getSource()) {
                    // remove MaskFormatter here
        if (usuario.getText().equals("")) {
            usuario.setText("Introduce tu nombre de usuario");
            usuario.setForeground(new Color(204, 204, 204));
        }
    }
}
解决方案

要实现焦点切换时动态添加/移除MaskFormatter,核心是用JFormattedTextField.setFormatterFactory()方法切换不同的格式工厂:

  1. 提前定义两个全局FormatterFactory
    在类成员变量中声明两个格式工厂,分别对应带掩码和无格式的场景:

    private FormatterFactory maskFactory;
    private FormatterFactory defaultFactory;
    
  2. 初始化时创建格式工厂并配置输入框
    把原来的构造方法初始化改成先创建无格式输入框,再提前准备好两个工厂:

    // 初始化输入框(先不绑定掩码)
    usuario = new JFormattedTextField();
    usuario.addFocusListener(this);
    usuario.setBounds(64, 182, 267, 24);
    usuario.setBorder(null);
    usuario.setText("Introduce tu nombre de usuario");
    usuario.setForeground(new Color(204, 204, 204));
    usuario.setFont(new Font("Cascadia Code", Font.PLAIN, 11));
    contentPane.add(usuario);
    
    // 创建带掩码的格式工厂
    try {
        MaskFormatter maskFormatter = new MaskFormatter("########U");
        maskFormatter.setAllowsInvalid(true); // 允许临时不符合格式的内容(避免占位符冲突)
        maskFormatter.setPlaceholderCharacter(' ');
        maskFactory = new DefaultFormatterFactory(maskFormatter);
    } catch (ParseException e) {
        e.printStackTrace();
    }
    
    // 创建无格式的格式工厂(用默认Formatter)
    DefaultFormatter defaultFormatter = new DefaultFormatter();
    defaultFormatter.setAllowsInvalid(true); // 允许任意文本(比如占位符)
    defaultFactory = new DefaultFormatterFactory(defaultFormatter);
    
    // 初始状态用无格式工厂,避免占位符被掩码限制
    usuario.setFormatterFactory(defaultFactory);
    
  3. 修改焦点事件方法实现切换
    在焦点获取/失去时切换对应的格式工厂:

    @Override
    public void focusGained(FocusEvent e) {
        if (usuario == e.getSource()) {
            // 切换到带掩码的格式工厂
            usuario.setFormatterFactory(maskFactory);
            // 处理占位符逻辑
            if (usuario.getText().equals("Introduce tu nombre de usuario")) {
                usuario.setText("");
                usuario.setForeground(Color.BLACK);
            }
        }
    }
    
    @Override
    public void focusLost(FocusEvent e) {
        if (usuario == e.getSource()) {
            // 切换到无格式的格式工厂
            usuario.setFormatterFactory(defaultFactory);
            // 处理占位符逻辑
            if (usuario.getText().trim().isEmpty()) {
                usuario.setText("Introduce tu nombre de usuario");
                usuario.setForeground(new Color(204, 204, 204));
            }
        }
    }
    
  4. 关键注意点

    • 必须设置setAllowsInvalid(true),否则当输入框内容不符合掩码规则(比如占位符文本)时,会被强制清空或抛出异常
    • 切换格式工厂时,输入框内容会被重新格式化,所以要确保切换时机和占位符逻辑的顺序正确

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 06:25:10