Ограничение ввода JTextField для целых чисел
Я знаю, что этот вопрос, должно быть, спросил и ответил миллион раз, но я просто не могу найти легкое решение. У меня есть JTextField, который должен принимать только положительные целые числа в качестве входных данных. Мне нужен способ убедиться, что здесь ничего не вводит.
У меня уже есть keyListener, прикрепленный к этому элементу управления. Удалив другой код, который должен обработать этот слушатель, у меня есть следующее:
txtAnswer.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { int key = e.getKeyCode(); /* Restrict input to only integers */ if (key 105) e.setKeyChar(''); }; });
Как вы можете видеть, я пытаюсь использовать KeyCode для проверки того, попадает ли только что нажатый ключ в диапазон целых чисел. Кажется, это работает. Но я хочу просто проигнорировать запись, если она выходит за пределы этого диапазона. Код e.setKeyChar('')
должен был справиться с этим, но он не работает. Код будет компилироваться, но он не имеет видимого эффекта.
- Не удается получить ArrayIndexOutOfBoundsException из будущего И SwingWorker, если stream запущен. Исполнитель
- Java Look and Feel (L & F)
- Java: сохранение формата изображения JPanel
- Java: Swing Library & Thread Safety
- Java Swing Blank JFrame подходит?
Может ли кто-нибудь сказать мне, если я на правильном пути? Что я могу заменить e.setKeyChar('')
чтобы сделать эту работу? Или я полностью иду в неправильном направлении?
Благодарю.
- Как сделать canvas с Swing?
- установить и отключить иконки JToggleButton
- Удалить контейнер верхнего уровня во время выполнения
- Как добавить MouseListener в элемент на Java Swing Canvas
- Использование setValueAt для воссоздания взаимоисключающих флажков
- Как включить базу данных SQLite в исполняемый Jar?
- Как я могу прослушивать нажатия клавиш (внутри Java Swing) для всех компонентов?
- Несколько графиков на нескольких фигурах с использованием jFreeChart
Не используйте KeyListener для этого, поскольку вы пропустите много, включая вставку текста. Также KeyListener – это очень низкоуровневая конструкция и как таковая, следует избегать в приложениях Swing.
Решение было описано много раз на SO: используйте DocumentFilter . На этом сайте есть несколько примеров, некоторые из которых написаны мной.
Например: using-documentfilter-filterbypass
Кроме того, для получения справки по учебному пособию ознакомьтесь с: Реализация DocumentFilter .
редактировать
Например:
import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; import javax.swing.text.Document; import javax.swing.text.DocumentFilter; import javax.swing.text.PlainDocument; public class DocFilter { public static void main(String[] args) { JTextField textField = new JTextField(10); JPanel panel = new JPanel(); panel.add(textField); PlainDocument doc = (PlainDocument) textField.getDocument(); doc.setDocumentFilter(new MyIntFilter()); JOptionPane.showMessageDialog(null, panel); } } class MyIntFilter extends DocumentFilter { @Override public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException { Document doc = fb.getDocument(); StringBuilder sb = new StringBuilder(); sb.append(doc.getText(0, doc.getLength())); sb.insert(offset, string); if (test(sb.toString())) { super.insertString(fb, offset, string, attr); } else { // warn the user and don't allow the insert } } private boolean test(String text) { try { Integer.parseInt(text); return true; } catch (NumberFormatException e) { return false; } } @Override public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException { Document doc = fb.getDocument(); StringBuilder sb = new StringBuilder(); sb.append(doc.getText(0, doc.getLength())); sb.replace(offset, offset + length, text); if (test(sb.toString())) { super.replace(fb, offset, length, text, attrs); } else { // warn the user and don't allow the insert } } @Override public void remove(FilterBypass fb, int offset, int length) throws BadLocationException { Document doc = fb.getDocument(); StringBuilder sb = new StringBuilder(); sb.append(doc.getText(0, doc.getLength())); sb.delete(offset, offset + length); if (test(sb.toString())) { super.remove(fb, offset, length); } else { // warn the user and don't allow the insert } } }
Почему это важно?
- Что делать, если пользователь использует копию и вставку для вставки данных в текстовый компонент? KeyListener может пропустить это?
- Кажется, вы хотите проверить, могут ли данные представлять int. Что делать, если они вводят числовые данные, которые не подходят?
- Что делать, если вы хотите разрешить пользователю позднее вводить двойные данные? В научной нотации?
Вы также можете использовать JFormattedTextField
, который намного проще в использовании. Пример:
public static void main(String[] args) { NumberFormat format = NumberFormat.getInstance(); NumberFormatter formatter = new NumberFormatter(format); formatter.setValueClass(Integer.class); formatter.setMinimum(0); formatter.setMaximum(Integer.MAX_VALUE); formatter.setAllowsInvalid(false); // If you want the value to be committed on each keystroke instead of focus lost formatter.setCommitsOnValidEdit(true); JFormattedTextField field = new JFormattedTextField(formatter); JOptionPane.showMessageDialog(null, field); // getValue() always returns something valid System.out.println(field.getValue()); }
Не могу поверить, что я еще не нашел это простое решение в любом месте при переполнении стека, это, безусловно, самое полезное. Изменение документа или DocumentFilter не работает для JFormattedTextField. Ответ Петра Цзэна очень близок.
NumberFormat longFormat = NumberFormat.getIntegerInstance(); NumberFormatter numberFormatter = new NumberFormatter(longFormat); numberFormatter.setValueClass(Long.class); //optional, ensures you will always get a long value numberFormatter.setAllowsInvalid(false); //this is the key!! numberFormatter.setMinimum(0l); //Optional JFormattedTextField field = new JFormattedTextField(numberFormatter);
Вот один из подходов, который использует keylistener, но использует keyChar (вместо keyCode):
http://edenti.deis.unibo.it/utils/Java-tips/Validating%20numerical%20input%20in%20a%20JTextField.txt
keyText.addKeyListener(new KeyAdapter() { public void keyTyped(KeyEvent e) { char c = e.getKeyChar(); if (!((c >= '0') && (c <= '9') || (c == KeyEvent.VK_BACK_SPACE) || (c == KeyEvent.VK_DELETE))) { getToolkit().beep(); e.consume(); } } });
Другой подход (который лично я считаю почти сложным, как модель JTree от Swing) заключается в использовании форматированных текстовых полей:
http://docs.oracle.com/javase/tutorial/uiswing/components/formattedtextfield.html
Раньше я использовал Key Listener для этого, но с таким подходом мне не удавалось много времени. Лучший подход, как рекомендовано, – использовать DocumentFilter. Ниже приведен метод утилиты, созданный для построения текстовых полей с использованием только ввода номера. Просто будьте осторожны, что он также будет принимать одиночные ‘.’ а также потому, что он может использоваться для ввода в десятичной форме.
public static void installNumberCharacters(AbstractDocument document) { document.setDocumentFilter(new DocumentFilter() { @Override public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException { try { if (string.equals(".") && !fb.getDocument() .getText(0, fb.getDocument().getLength()) .contains(".")) { super.insertString(fb, offset, string, attr); return; } Double.parseDouble(string); super.insertString(fb, offset, string, attr); } catch (Exception e) { Toolkit.getDefaultToolkit().beep(); } } @Override public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException { try { if (text.equals(".") && !fb.getDocument() .getText(0, fb.getDocument().getLength()) .contains(".")) { super.insertString(fb, offset, text, attrs); return; } Double.parseDouble(text); super.replace(fb, offset, length, text, attrs); } catch (Exception e) { Toolkit.getDefaultToolkit().beep(); } } }); }
Когда вы вводите целочисленные числа в JtextField1 после отпускания ключа, он переходит внутрь try, для любого другого персонажа он будет вызывать NumberFormatException. Если вы установите пустую строку в jTextField1 внутри catch, чтобы пользователь не мог вводить другие ключи, кроме положительных чисел, потому что JTextField1 будет очищен для каждой неудачной попытки.
//Fields int x; JTextField jTextField1; //Gui Code Here private void jTextField1KeyReleased(java.awt.event.KeyEvent evt) { try { x = Integer.parseInt(jTextField1.getText()); } catch (NumberFormatException nfe) { jTextField1.setText(""); } }