制作自定义 JTextField (JCurrencyField)
我制作了一个 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();
}
}
你能帮我解决这个问题吗?
I making a JCurrencyField to use it in my program, I almost finished creating it but I've faced an issue.
JCurrencyField is a normal JTextField but it cannot accept any character that is not a number or decimal point .
and I made some specifications for this JCurrencyField:
- The user cannot insert more than one decimal point
.
. - The user cannot insert more than two digits after the decimal point.
The issue I've faced was not being able to insert any digits before the decimal point if there are two digits after the decimal point.
Here is my code:
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;
}
}
}
Test Program:
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();
}
}
could you please help me to solve this issue?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
最好将
JFormattedTextField
与NumberFormat
一起使用java.text.NumberFormat#getCurrencyInstance()
it's better to use
JFormattedTextField
withNumberFormat
java.text.NumberFormat#getCurrencyInstance()
您在 DocumentFilter 中测试了错误的字符串。
您不应该测试文本字符串,而应该测试从 FilterBypass 参数获取的文本和文档构建的字符串,因为这是您想要查看它是否满足条件的字符串。例如,不是这个:
而是这个:
您将需要对 containsOnlyNumbers 方法进行更改以适应这些更改。
编辑 1
这可以使用 toto 的正则表达式轻松完成:
You're testing the wrong string in your DocumentFilter.
You shouldn't be testing the text String but rather the String built from text and Document obtained from the FilterBypass parameter since this is the String that you want to see if it fulfills the criteria. For instance, not this:
But rather this:
You will need to make changes to your containsOnlyNumbers method to account for these changes.
Edit 1
And this can be easily done using toto's regex:
以下 正则表达式 应该有效:
但是它还会匹配空字符串,因此如果不匹配,则必须单独检查。 (我不知道
parseDouble
是否为空字符串返回 0。)编辑:@mkorbel 关于使用
java.swing.text.NumberFormatter< 的评论/code> 和
java.text.NumberFormat
是比我更好的解决方案。您可能会将代码缩小约 100 倍……这就是当您了解库时会发生的情况。The following regex should work:
However it would also match the empty string, so you have to check for that separately, if you don't it. (I don't know if
parseDouble
returns 0 for an empty string.)EDIT: the comment of @mkorbel about using
java.swing.text.NumberFormatter
withjava.text.NumberFormat
is a better solution than mine. You'll probably shrink your code by a factor ~100... that's what happens when you know your libraries.