将 JTextField 的输入限制为双数?
Restrict Input of JTextField to Double Numbers?
在 java 中,我正在尝试制作简单的货币转换器,但为此我需要一个文本字段,它可以将输入限制为仅限数字,更重要的是双数。我尝试使用 JFormatedTextField
但 它仅在您完成输入并单击其他地方后格式化输入 但我需要将 TextField 限制为 consume() 输入时每个无效字符。
可能的尝试:
使用JFormatedTextField
:
JFormatedTextField textField = new JFormatedTextField(new DoubleFormat());
textField.setBounds(190, 49, 146, 33);
frame.getContentPane().add(textField);
textField.setColumns(10);
使用KeyTyped Event
:
char c = arg0.getKeyChar();
if(!(Character.isDigit(c) || c == KeyEvent.VK_BACK_SPACE || c== KeyEvent.VK_DELETE)){
arg0.consume();
}
将 KeyTyped Event
与正则表达式结合使用:
if(!((textField.getText().toString+arg0.getKeyChar()).matches("[0-9]*(.[0-9]*)?"))){
arg0.consume();
}
第二次和第三次尝试很接近,但是第二次尝试在点值上失败,第三次尝试总是读取 textField 上的第一个字符,不管它是什么,所以有什么建议吗?我不太喜欢 JAVA GUI,所以请耐心等待。
您需要使用 DocumentFilter
。阅读 Swing 教程中关于 Implementing a DocumentFilter 的部分以获取入门示例。
您的实施将更加复杂,因为您需要获取文档中已有的文本,然后将新文本插入字符串中的适当位置,然后调用 Double.parseDouble(...) String 以确保它是一个有效的双精度值。
如果验证成功,则继续插入,否则会发出蜂鸣声。
您可以向文本字段添加按键侦听器并实施 keyReleased() 方法来确定在用户每次击键后文本字段中的值是否为双精度值。
public class CurrencyJTF extends JFrame {
JButton jButton = new JButton("Unfocus");
final JFormattedTextField textField = new JFormattedTextField(new DecimalFormat());
double lastDouble = 0.0;
public CurrencyJTF() throws HeadlessException {
textField.setColumns(20);
textField.setText(lastDouble + "");
this.setLayout(new FlowLayout());
this.add(textField);
this.add(jButton);
textField.addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent e) {
handleKeyReleased();
}
});
}
private void handleKeyReleased() {
String text = textField.getText();
if (text.isEmpty()) return;
try {
lastDouble = Double.parseDouble(text);
} catch (NumberFormatException ex) {
textField.setText(lastDouble + ""); // or set to other values you want
}
}
public static void main(String[] args) {
JFrame frame = new CurrencyJTF();
frame.setVisible(true);
frame.pack();
}
}
如果你知道你想要小数点前后多少位,你也可以使用MaskFormatter
。例如:
JFormattedTextField field = new JFormattedTextField(getMaskFormatter("######.##"));
(...)
private MaskFormatter getMaskFormatter(String format) {
MaskFormatter mask = null;
try {
mask = new MaskFormatter(format);
mask.setPlaceholderCharacter('0');
}catch (ParseException ex) {
ex.printStackTrace();
}
return mask;
}
但是它会变成 JTextField
的样子,所以它总是可见 000000.00
。
编辑
另一种方式,不太优雅,但在我看来可行。试试 DecumentListener
,也许它会满足您的需求:
field = new JFormattedTextField();
field.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
Runnable format = new Runnable() {
@Override
public void run() {
String text = field.getText();
if(!text.matches("\d*(\.\d{0,2})?")){
field.setText(text.substring(0,text.length()-1));
}
}
};
SwingUtilities.invokeLater(format);
}
@Override
public void removeUpdate(DocumentEvent e) {
}
@Override
public void changedUpdate(DocumentEvent e) {
}
});
我使用了正则表达式:\d*(\.\d{0,2})?
因为两位小数对于货币来说已经足够了。
您可以像这样编写自己的 KeyListener:
public class DoubleNumbersKeyListener implements KeyListener {
final HashSet<Character> valid_keys = new HashSet<>();
final ArrayList<Character> sequence = new ArrayList<>();
public DoubleNumbersKeyListener() {
valid_keys.add('.');
valid_keys.add('0');
valid_keys.add('1');
valid_keys.add('2');
valid_keys.add('3');
valid_keys.add('4');
valid_keys.add('5');
valid_keys.add('6');
valid_keys.add('7');
valid_keys.add('8');
valid_keys.add('9');
valid_keys.add((char) KeyEvent.VK_BACK_SPACE);
valid_keys.add((char) KeyEvent.VK_DELETE);
}
@Override
public void keyTyped(KeyEvent event) {
char c = event.getKeyChar();
if (!valid_keys.contains(c)) {
event.consume();
} else {
if (c == KeyEvent.VK_DELETE || c == KeyEvent.VK_BACK_SPACE) {
if (!sequence.isEmpty()) {
char last = sequence.remove(sequence.size() - 1);
if (last == '.') {
valid_keys.add(last);
}
}
} else {
sequence.add(c);
if (c == '.') {
valid_keys.remove(c);
}
}
}
}
@Override
public void keyPressed(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {
}
}
在 java 中,我正在尝试制作简单的货币转换器,但为此我需要一个文本字段,它可以将输入限制为仅限数字,更重要的是双数。我尝试使用 JFormatedTextField
但 它仅在您完成输入并单击其他地方后格式化输入 但我需要将 TextField 限制为 consume() 输入时每个无效字符。
可能的尝试:
使用JFormatedTextField
:
JFormatedTextField textField = new JFormatedTextField(new DoubleFormat());
textField.setBounds(190, 49, 146, 33);
frame.getContentPane().add(textField);
textField.setColumns(10);
使用KeyTyped Event
:
char c = arg0.getKeyChar();
if(!(Character.isDigit(c) || c == KeyEvent.VK_BACK_SPACE || c== KeyEvent.VK_DELETE)){
arg0.consume();
}
将 KeyTyped Event
与正则表达式结合使用:
if(!((textField.getText().toString+arg0.getKeyChar()).matches("[0-9]*(.[0-9]*)?"))){
arg0.consume();
}
第二次和第三次尝试很接近,但是第二次尝试在点值上失败,第三次尝试总是读取 textField 上的第一个字符,不管它是什么,所以有什么建议吗?我不太喜欢 JAVA GUI,所以请耐心等待。
您需要使用 DocumentFilter
。阅读 Swing 教程中关于 Implementing a DocumentFilter 的部分以获取入门示例。
您的实施将更加复杂,因为您需要获取文档中已有的文本,然后将新文本插入字符串中的适当位置,然后调用 Double.parseDouble(...) String 以确保它是一个有效的双精度值。
如果验证成功,则继续插入,否则会发出蜂鸣声。
您可以向文本字段添加按键侦听器并实施 keyReleased() 方法来确定在用户每次击键后文本字段中的值是否为双精度值。
public class CurrencyJTF extends JFrame {
JButton jButton = new JButton("Unfocus");
final JFormattedTextField textField = new JFormattedTextField(new DecimalFormat());
double lastDouble = 0.0;
public CurrencyJTF() throws HeadlessException {
textField.setColumns(20);
textField.setText(lastDouble + "");
this.setLayout(new FlowLayout());
this.add(textField);
this.add(jButton);
textField.addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent e) {
handleKeyReleased();
}
});
}
private void handleKeyReleased() {
String text = textField.getText();
if (text.isEmpty()) return;
try {
lastDouble = Double.parseDouble(text);
} catch (NumberFormatException ex) {
textField.setText(lastDouble + ""); // or set to other values you want
}
}
public static void main(String[] args) {
JFrame frame = new CurrencyJTF();
frame.setVisible(true);
frame.pack();
}
}
如果你知道你想要小数点前后多少位,你也可以使用MaskFormatter
。例如:
JFormattedTextField field = new JFormattedTextField(getMaskFormatter("######.##"));
(...)
private MaskFormatter getMaskFormatter(String format) {
MaskFormatter mask = null;
try {
mask = new MaskFormatter(format);
mask.setPlaceholderCharacter('0');
}catch (ParseException ex) {
ex.printStackTrace();
}
return mask;
}
但是它会变成 JTextField
的样子,所以它总是可见 000000.00
。
编辑
另一种方式,不太优雅,但在我看来可行。试试 DecumentListener
,也许它会满足您的需求:
field = new JFormattedTextField();
field.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
Runnable format = new Runnable() {
@Override
public void run() {
String text = field.getText();
if(!text.matches("\d*(\.\d{0,2})?")){
field.setText(text.substring(0,text.length()-1));
}
}
};
SwingUtilities.invokeLater(format);
}
@Override
public void removeUpdate(DocumentEvent e) {
}
@Override
public void changedUpdate(DocumentEvent e) {
}
});
我使用了正则表达式:\d*(\.\d{0,2})?
因为两位小数对于货币来说已经足够了。
您可以像这样编写自己的 KeyListener:
public class DoubleNumbersKeyListener implements KeyListener {
final HashSet<Character> valid_keys = new HashSet<>();
final ArrayList<Character> sequence = new ArrayList<>();
public DoubleNumbersKeyListener() {
valid_keys.add('.');
valid_keys.add('0');
valid_keys.add('1');
valid_keys.add('2');
valid_keys.add('3');
valid_keys.add('4');
valid_keys.add('5');
valid_keys.add('6');
valid_keys.add('7');
valid_keys.add('8');
valid_keys.add('9');
valid_keys.add((char) KeyEvent.VK_BACK_SPACE);
valid_keys.add((char) KeyEvent.VK_DELETE);
}
@Override
public void keyTyped(KeyEvent event) {
char c = event.getKeyChar();
if (!valid_keys.contains(c)) {
event.consume();
} else {
if (c == KeyEvent.VK_DELETE || c == KeyEvent.VK_BACK_SPACE) {
if (!sequence.isEmpty()) {
char last = sequence.remove(sequence.size() - 1);
if (last == '.') {
valid_keys.add(last);
}
}
} else {
sequence.add(c);
if (c == '.') {
valid_keys.remove(c);
}
}
}
}
@Override
public void keyPressed(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {
}
}