如何在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()方法切换不同的格式工厂:
提前定义两个全局
FormatterFactory
在类成员变量中声明两个格式工厂,分别对应带掩码和无格式的场景:private FormatterFactory maskFactory; private FormatterFactory defaultFactory;初始化时创建格式工厂并配置输入框
把原来的构造方法初始化改成先创建无格式输入框,再提前准备好两个工厂:// 初始化输入框(先不绑定掩码) 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);修改焦点事件方法实现切换
在焦点获取/失去时切换对应的格式工厂:@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)); } } }关键注意点
- 必须设置
setAllowsInvalid(true),否则当输入框内容不符合掩码规则(比如占位符文本)时,会被强制清空或抛出异常 - 切换格式工厂时,输入框内容会被重新格式化,所以要确保切换时机和占位符逻辑的顺序正确
- 必须设置
内容的提问来源于stack exchange,提问作者tumorito
相关产品推荐
相关产品推荐

