Ограничить ввод JTextField двойными числами?

В Java я пытаюсь сделать простой конвертер валют, но для этого мне нужно текстовое поле, которое может ограничить ввод только цифрами и, что более важно, двойными числами. Я пытался с помощью JFormatedTextField но он только форматирует ввод после того, как вы сделали свой ввод и нажали в другом месте, но мне нужно ограничить TextField для потребления () каждого недопустимого символа при выполнении ввода.

Возможные попытки:

С помощью 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, так что будьте терпеливы.

4 ответа

Решение

Если вы знаете, сколько мест до и после запятой вы хотите, вы также можете использовать 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})? потому что два знака после запятой достаточно для валюты.

Вам нужно будет использовать DocumentFilter, Прочитайте раздел руководства Swing по реализации DocumentFilter для примера, с чего можно начать.

Ваша реализация будет более сложной, потому что вам нужно будет взять текст, уже содержащийся в документе, а затем вставить новый текст в соответствующее место в строке и затем вызвать Double.parse Double (...) в строке, чтобы убедиться, что он действительное двойное значение.

Если проверка прошла успешно, вы продолжите вставку, в противном случае вы можете подать звуковой сигнал.

Вы можете добавить прослушиватель клавиш в текстовое поле и реализовать метод 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();
}
}

Вы можете написать свой собственный 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) {

    }

}
Другие вопросы по тегам