本文目录导读:

在 Java Swing 中,JFormattedTextField 本身并没有像第三方控件那样直接提供一个“格式掩码”的字符串属性( 用于电话号码),要实现掩码效果(即限制输入格式并自动填充),通常有两种主要方法:
- 使用
MaskFormatter(最常用,推荐)。 - 使用自定义的
DocumentFilter(更灵活,但代码量更多)。
以下详细介绍如何使用 MaskFormatter 来实现格式掩码。
使用 MaskFormatter(推荐)
这是实现输入掩码最标准的方式,它允许你定义一个字符串模板,其中特定字符表示允许的输入类型。
常用掩码字符
| 字符 | 含义 |
|---|---|
数字 (0-9) |
|
| 转义字符(用于将特殊字符视为普通文本) | |
U |
大写字母 (A-Z) |
L |
小写字母 (a-z) |
A |
字母或数字 |
字母 (a-z 或 A-Z) |
|
| 任意字符 | |
H |
十六进制数字 (0-9, a-f, A-F) |
代码示例
import javax.swing.*;
import javax.swing.text.MaskFormatter;
import java.text.ParseException;
public class MaskFormatterExample {
public static void main(String[] args) {
JFrame frame = new JFrame("MaskFormatter Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 200);
frame.setLayout(new java.awt.FlowLayout());
// 1. 创建 MaskFormatter
MaskFormatter phoneFormatter = null;
try {
// 定义掩码模式:固定格式 (123) 456-7890
phoneFormatter = new MaskFormatter("(###) ###-####");
phoneFormatter.setPlaceholderCharacter('_'); // 占位符
phoneFormatter.setAllowsInvalid(false); // 不允许无效输入
phoneFormatter.setValidCharacters("0123456789");
} catch (ParseException e) {
e.printStackTrace();
}
// 2. 创建 JFormattedTextField 并关联 MaskFormatter
JFormattedTextField phoneField = new JFormattedTextField(phoneFormatter);
phoneField.setColumns(15);
phoneField.setValue("1234567890"); // 设置默认值(可选)
// 示例2:日期掩码 (MM/DD/YYYY)
MaskFormatter dateFormatter = null;
try {
dateFormatter = new MaskFormatter("##/##/####");
dateFormatter.setPlaceholderCharacter('_');
} catch (ParseException e) {
e.printStackTrace();
}
JFormattedTextField dateField = new JFormattedTextField(dateFormatter);
dateField.setColumns(10);
// 示例3:邮编掩码
MaskFormatter zipFormatter = null;
try {
zipFormatter = new MaskFormatter("#####-####");
zipFormatter.setPlaceholderCharacter('_');
} catch (ParseException e) {
e.printStackTrace();
}
JFormattedTextField zipField = new JFormattedTextField(zipFormatter);
zipField.setColumns(10);
// 添加到窗口
frame.add(new JLabel("Phone:"));
frame.add(phoneField);
frame.add(new JLabel("Date:"));
frame.add(dateField);
frame.add(new JLabel("ZIP:"));
frame.add(zipField);
frame.setVisible(true);
}
}
关键方法
setPlaceholderCharacter(char):设置未输入位置的占位符(如 、` `)。setAllowsInvalid(boolean):true:允许输入不符合掩码的字符(直到提交时才验证)。false:即时阻止无效输入(推荐用于掩码)。
setValidCharacters(String):限制允许的输入字符集(例如只允许数字)。setPlaceholder(String):设置初始占位文本。
自定义 DocumentFilter
MaskFormatter 无法满足复杂需求(例如需要根据输入动态改变掩码,或更复杂的验证逻辑),可以实现自定义 DocumentFilter。
简单示例:只允许数字,并自动添加连字符
import javax.swing.*;
import javax.swing.text.*;
public class CustomMaskFilterExample {
public static void main(String[] args) {
JFrame frame = new JFrame("Custom DocumentFilter");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 200);
frame.setLayout(new java.awt.FlowLayout());
JFormattedTextField textField = new JFormattedTextField();
textField.setColumns(15);
textField.setDocument(new PlainDocument() {
@Override
public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
// 1. 只允许数字
if (str == null || !str.matches("\\d+")) {
// 可以选择忽略,或者提示错误
// super.insertString(offs, str, a); // 这样会允许字符
return; // 拒绝非数字字符
}
// 2. 获取当前文本
String currentText = getText(0, getLength());
// 3. 构建新文本
String newText = new StringBuilder(currentText)
.insert(offs, str)
.toString();
// 4. 清理非数字
newText = newText.replaceAll("[^0-9]", "");
// 5. 限制长度(10 位)
if (newText.length() > 10) {
newText = newText.substring(0, 10);
}
// 6. 套用格式(123-456-7890)
StringBuilder formatted = new StringBuilder();
for (int i = 0; i < newText.length(); i++) {
if (i == 3 || i == 6) {
formatted.append("-");
}
formatted.append(newText.charAt(i));
}
// 7. 直接替换整个文本(避免多次触发)
// 使用 SwingUtilities.invokeLater 避免递归
SwingUtilities.invokeLater(() -> {
try {
remove(0, getLength());
super.insertString(0, formatted.toString(), a);
} catch (BadLocationException e) {
e.printStackTrace();
}
});
}
});
frame.add(new JLabel("Phone (###-###-####):"));
frame.add(textField);
frame.setVisible(true);
}
}
| 特点 | MaskFormatter |
自定义 DocumentFilter |
|---|---|---|
| 易用性 | 非常简单,几行代码即可 | 需要编写较多代码 |
| 功能 | 基础掩码、字符验证、占位符 | 完全可控,可实现复杂逻辑 |
| 灵活性 | 较低,格式固定 | 极高,可以动态变化 |
| 推荐场景 | 常见格式(电话、日期、SSN) | 复杂或动态掩码需求 |
常见问题
MaskFormatter无法输入?- 检查
setAllowsInvalid(false)是否阻止了正常输入。 - 确保使用的掩码字符正确( 只允许数字,
L只允许字母)。
- 检查
- 如何获取
MaskFormatter的最终值?- 使用
textField.getText()获取当前显示的文本(包含占位符)。 - 使用
textField.getValue()获取经过格式化的对象(通常是String),但不包含占位符。
- 使用
- 如何清空
MaskFormatter的输入?- 直接
textField.setValue(null)会使其显示占位符,但可能不美观。 - 推荐:
textField.setText("")或textField.setValue("")。
- 直接
完整示例(直接运行)
将上面的第一个例子编译运行,你将看到三个带有占位符 的格式化文本框,并且只能输入数字和特定格式。