转自andycpp,http://blog.youkuaiyun.com/andycpp/article/details/1698238
JFormattedTextField intField = new JFormattedTextField(NumberFormat.getIntegerInstance());
短短的一行代码就能实现如下功能:当该文本框失去焦点时,检测用户的输入是否符合整数的格式。若不符合整数的格式,则有几种方式来提示用 户。默认的方式是丢弃用户的输入,文本框内显示的内容恢复到用户输入前的状态。比如文本框内原来是“123”,你输入了个“abc”,因为“abc”不是 一个整数,因此当光标离开文本框后,文本框的内容立刻又变回“123”,并且内部的Value对象仍然是整数123。
intField.setFocusLostBehavior(JFormattedTextField.COMMIT);
这样用户的错误输入就不会丢失了,但也没有任何提示性信息来告知用户输入错误。同时请注意,虽然文本框内会保留“abc”,但是内部的Value对象仍然是整数123!!
JFormattedTextField intField = new JFormattedTextField(NumberFormat.getIntegerInstance());
intField.setInputVerifier(new FormattedTextFieldVerifier());
//定义一个InputVerifier类,把这个类添加到JFormattedTextField中
class FormattedTextFieldVerifier extends InputVerifier
{
public boolean verify(JComponent component)
{
JFormattedTextField field = (JFormattedTextField) component;
//若用户的输入符合格式,则返回true,否则返回false
return field.isEditValid();
}
}
大家看到了,上述代码不光为JFormattedTextField 添加了一个整数格式,还为他添加了一个验证器类。验证器类中有一个verify方法,此方法若返回ture,则焦点可以离开,此方法若返回false,则 焦点不能离开。在此方法中,我们调用isEditValid方法来验证格式的正确与否。isEditValid方法是JFormattedTextField提供的,通过此方法可以很方便的验证格式的正确性。
//用自定义的DocumentFilter替换格式类中默认的DocumentFilter
JFormattedTextField intField3 = new JFormattedTextField(
new InternationalFormatter(NumberFormat.getIntegerInstance()) {
protected DocumentFilter getDocumentFilter() {
return filter;
}
private DocumentFilter filter = new IntFilter();
});
//自定义一个DocumentFilter类
class IntFilter extends DocumentFilter {
//重载insertString方法
public void insertString(FilterBypass fb, int offset, String string,
AttributeSet attr) throws BadLocationException {
StringBuilder builder = new StringBuilder(string);
for (int i = builder.length() - 1; i >= 0; i--) {
int cp = builder.codePointAt(i);
if (!Character.isDigit(cp) && cp != '-') {
builder.deleteCharAt(i);
if (Character.isSupplementaryCodePoint(cp)) {
i--;
builder.deleteCharAt(i);
}
}
}
super.insertString(fb, offset, builder.toString(), attr);
}
//重载replace方法
public void replace(FilterBypass fb, int offset, int length, String string,
AttributeSet attr) throws BadLocationException {
if (string != null) {
StringBuilder builder = new StringBuilder(string);
for (int i = builder.length() - 1; i >= 0; i--) {
int cp = builder.codePointAt(i);
if (!Character.isDigit(cp) && cp != '-') {
builder.deleteCharAt(i);
if (Character.isSupplementaryCodePoint(cp)) {
i--;
builder.deleteCharAt(i);
}
}
}
string = builder.toString();
}
super.replace(fb, offset, length, string, attr);
}
}
原理很简单,就是添加一个过滤器。不过要注意,这个过滤器不是直接添加到JFormattedTextField中,而是替换格式类中默认的过滤器。在过滤器中,你要重载2个方法,分别是insertString和replace。在这2个方法中,把你不希望用户输入的字符过滤掉。但是请注意,不要被这2个方法的名字迷惑了,当你将光标定位到文本框中(不选中任何文字),然后敲击一下键盘,系统会调用哪个方法?是insertString吗?不是,是replace!!!目前为止我还不知道insertString方法会在什么时候被调用,至少在我的程序中,它从来没有被调用过。但是SUN的专家告诉我们“您一定要将insertString这个方法重载,它将在某些时候被调用”。听专家的话一定没错,反正我每次都将他重载了。
MaskFormatter formatter = new MaskFormatter("###########");
formatter.setPlaceholderCharacter('0');
JFormattedTextField ssnField = new JFormattedTextField(formatter);
上述代码就能限制输入一个长度为11位的数字,也就是手机号。
class IPAddressFormatter extends DefaultFormatter {
public String valueToString(Object value) throws ParseException {
if (!(value instanceof byte[]))
throw new ParseException("Not a byte[]", 0);
byte[] a = (byte[]) value;
if (a.length != 4)
throw new ParseException("Length != 4", 0);
StringBuilder builder = new StringBuilder();
for (int i = 0; i <</span> 4; i++) {
int b = a[i];
if (b <</span> 0)
b += 256;
builder.append(String.valueOf(b));
if (i <</span> 3)
builder.append('.');
}
return builder.toString();
}
public Object stringToValue(String text) throws ParseException {
StringTokenizer tokenizer = new StringTokenizer(text, ".");
byte[] a = new byte[4];
for (int i = 0; i <</span> 4; i++) {
int b = 0;
if (!tokenizer.hasMoreTokens())
throw new ParseException("Too few bytes", 0);
try {
b = Integer.parseInt(tokenizer.nextToken());
} catch (NumberFormatException e) {
throw new ParseException("Not an integer", 0);
}
if (b <</span> 0 || b >= 256)
throw new ParseException("Byte out of range", 0);
a[i] = (byte) b;
}
if (tokenizer.hasMoreTokens())
throw new ParseException("Too many bytes", 0);
return a;
}
}
第二种实现方法是直接使用DefaultFormatter,然后调用JFormattedTextField 的setValue方法,传递给他的参数必须是一个符合要求的类:该类拥有一个“以一个字符串为参数的构造函数”(会抛出异常,相当于上面的 stringToValue方法),还有一个toString方法(也会抛出异常,相当于上面的valueToString方法)。比如一个URL网 址,JAVA就有相应的类,我们可以直接使用,代码如下:
DefaultFormatter formatter = new DefaultFormatter();
formatter.setOverwriteMode(false);
JFormattedTextField urlField = new JFormattedTextField(formatter);
urlField.setFocusLostBehavior(JFormattedTextField.COMMIT);
urlField.setValue(new URL("http://java.sun.com"));
只要用户的输入不符合网址的格式,都可以利用前面讲过的各种机制来提示用户。