本文目录导读:

在 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("")。
- 直接
完整示例(直接运行)
将上面的第一个例子编译运行,你将看到三个带有占位符 的格式化文本框,并且只能输入数字和特定格式。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播