【问题标题】:Restrict Input of JTextField to Double Numbers?将 JTextField 的输入限制为双数?
【发布时间】:2018-09-27 23:49:07
【问题描述】:

在 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,所以请耐心等待。

【问题讨论】:

  • 1) Java GUI 必须在不同的语言环境中使用不同的 PLAF 在不同的操作系统、屏幕尺寸、屏幕分辨率等上工作。因此,它们不利于像素完美布局。而是使用布局管理器,或combinations of them 以及white space 的布局填充和边框。 2) 对于这项任务,我倾向于使用JSpinnerSpinnerNumberModel
  • 这是一个简单的编辑文本框,需要提供输入数字,如果我倾向于使用微调器,我该如何提供不同长度的数字?表示 34533434445545345345345.3454543534535345345

标签: java regex swing javax.swing.text


【解决方案1】:

如果您知道小数点前后的位数,也可以使用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})?,因为两位小数对于货币来说已经足够了。

【讨论】:

  • 我曾经想过同样的事情,但是如果我们不能通过限制输入大小来完全利用程序,那么输入会有多好。
  • 它已经完成了我的工作,抱歉忘记接受答案
【解决方案2】:

您需要使用DocumentFilter。请阅读 Implementing a DocumentFilter 上的 Swing 教程中的部分,以获取帮助您入门的示例。

您的实现将更加复杂,因为您需要获取 Document 中已有的文本,然后将新文本插入到 String 中的适当位置,然后在 String 上调用 Double.parseDouble(...) 以使确保它是一个有效的双精度值。

如果验证成功,则继续插入,否则会发出哔声。

【讨论】:

  • 没有DocumentFilter 就没有其他解决方法了吗? ,我忽略了它,因为我不太了解它。
  • 你怎么能在不到 10 分钟的时间内理解它?你读过教程吗?您是否下载了演示代码并进行了测试?您是否尝试过我的建议,基本上是 3 行代码? i need to restrict TextField to consume() each invalid character while doing input 使用 DocumentFilter 是正确的解决方案,并且完全符合您的要求
【解决方案3】:

您可以在文本字段中添加按键侦听器并实现 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();
}
}

【讨论】:

  • 对用户不太友好。如果您输入了无效字符,插入符号总是移动到文本的末尾,而不是留在用户尝试插入文本的位置。对程序员也不是很友好,因为即使 Document 没有更改,也会为无效字符生成两个 DocumentEvents(添加/删除)。
  • 是的,它暂时显示无效字符。我认为这不是正确的方法
【解决方案4】:

你可以像这样编写自己的 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) {

    }

}

【讨论】:

    猜你喜欢
    • 2020-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-25
    • 2014-10-14
    • 2012-06-19
    相关资源
    最近更新 更多