我制作了一个JCurrencyField以便在程序中使用它,我几乎完成了创建它,但是遇到了一个问题。
JCurrencyField是一个普通的JTextField,但它不能接受不是数字或小数点.
的任何字符,并且我为此JCurrencyField做了一些规定:
用户不能插入多个小数点.
。
用户不能在小数点后插入两位以上的数字。
我遇到的问题是,如果小数点后有两位数字,则无法在小数点前插入任何数字。
这是我的代码:
import javax.swing.*;
import javax.swing.text.*;
public class JCurrencyField extends JTextField
{
public JCurrencyField()
{
((AbstractDocument)getDocument()).setDocumentFilter(new NumberOnlyFilter());
}
private class NumberOnlyFilter extends DocumentFilter
{
public void insertString(DocumentFilter.FilterBypass fb, int offset,
String text, AttributeSet attr) throws BadLocationException
{
if(!containsOnlyNumbers(text)) return;
fb.insertString(offset, text, attr);
}
public void replace(DocumentFilter.FilterBypass fb, int offset, int length,
String text, AttributeSet attr) throws BadLocationException
{
if(!containsOnlyNumbers(text)) return;
fb.replace(offset, length, text, attr);
}
/**
* This method checks if a String contains only numbers
*/
public boolean containsOnlyNumbers(String str)
{
//It can't contain only numbers if it's null or empty...
if (str == null || str.length() == 0) return false;
int counter = 0;
for(int i = 0; i < getText().length(); i++)
{
if(counter > 1) return false;
if(getText().charAt(i) == '.')
{
counter++;
}
}
int fp_counter = 0;
int fp_index = -1;
for(int i = 0; i < str.length(); i++)
{
if(counter >= 1) break;
if(str.charAt(i) == '.')
{
fp_counter++;
fp_index = i;
}
}
if(fp_counter > 1) return false;
if(str.length() > fp_index + 3) return false;
if(counter >= 1)
{
for(int i = 0; i < getText().length(); i++)
{
if(getText().charAt(i) == '.') counter++;
}
}
for (int j = 0; j < str.length(); j++)
{
if(counter >= 1 && (str.charAt(j) == '.')) return false;
}
int index = 0;
boolean fp_Flag = false;
int sp_count = 0;
for(int k = 0; k < getText().length(); k++)
{
if(getText().charAt(k) == '.')
{
index = k;
fp_Flag = true;
}
if(fp_Flag) sp_count++;
if(sp_count > 2) return false;
}
//if(fp_Flag && str.length() > 2) return false;
if(fp_Flag && index + 1 < getText().length() && str.length() > 1) return false;
//if(index + 2 < getText().length() && fp_Flag) return false;
for (int l = 0; l < str.length(); l++)
{
//If we find a non-digit character we return false.
if(str.charAt(l) == '.') continue;
if(!Character.isDigit(str.charAt(l)))
return false;
}
return true;
}
}
}
测试程序:
import java.awt.*;
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;
public class Test extends JFrame
{
private JCurrencyField txt = new JCurrencyField();
public Test()
{
super("Test...");
setDefaultCloseOperation(EXIT_ON_CLOSE);
try{ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());}
catch(Exception e){ System.out.println("Unable to load Windows look and feel");}
setPreferredSize(new Dimension(300, 100));
((JPanel) getContentPane()).setBorder(new EmptyBorder(13, 13, 13, 13) );
setLayout(new FlowLayout());
txt.setPreferredSize(new Dimension(100,30));
add(txt);
pack();
setLocationRelativeTo(null);
setVisible(true);
setResizable(false);
}
public static void main(String[] args)
{
new Test();
}
}
您能帮我解决这个问题吗?
最佳答案
您正在测试DocumentFilter中的错误字符串。
您不应该测试文本String,而应该测试根据从FilterBypass参数获得的文本和Document构建的String,因为这是您要查看其是否满足条件的String。例如,不是这样的:
public void insertString(DocumentFilter.FilterBypass fb, int offset,
String text, AttributeSet attr) throws BadLocationException
{
if(!containsOnlyNumbers(text)) return;
fb.insertString(offset, text, attr);
}
public void replace(DocumentFilter.FilterBypass fb, int offset, int length,
String text, AttributeSet attr) throws BadLocationException
{
if(!containsOnlyNumbers(text)) return;
fb.replace(offset, length, text, attr);
}
而是这样:
private class NumberOnlyFilter extends DocumentFilter {
public void insertString(DocumentFilter.FilterBypass fb, int offset,
String text, AttributeSet attr) throws BadLocationException {
StringBuilder sb = new StringBuilder();
sb.append(fb.getDocument().getText(0, fb.getDocument().getLength()));
sb.insert(offset, text);
if (!containsOnlyNumbers(sb.toString()))
return;
fb.insertString(offset, text, attr);
}
public void replace(DocumentFilter.FilterBypass fb, int offset,
int length, String text, AttributeSet attr)
throws BadLocationException {
StringBuilder sb = new StringBuilder();
sb.append(fb.getDocument().getText(0, fb.getDocument().getLength()));
sb.replace(offset, offset + length, text);
if (!containsOnlyNumbers(sb.toString()))
return;
fb.replace(offset, length, text, attr);
}
您将需要对containsOnlyNumbers方法进行更改以解决这些更改。
编辑1
这可以使用toto的正则表达式轻松完成:
private boolean containsOnlyNumbers(String text) {
Pattern pattern = Pattern.compile("\\d*(\\.\\d{0,2})?");
Matcher matcher = pattern.matcher(text);
boolean isMatch = matcher.matches();
return isMatch;
}