Вопрос по swing, numbers, java, jtextfield – Ограничение ввода JTextField целыми числами [дубликаты]

38

This question already has an answer here:

Is there any way to accept only numeric values in a JTextField? 19 answers

Я знаю, что на этот вопрос нужно было ответить и ответить миллион раз, но я просто не могу найти легкого решения. У меня есть JTextField, который предназначен для приема только положительных целых чисел в качестве входных данных. Мне нужен способ удостовериться, что больше ничего не получает здесь.

У меня уже есть keyListener, прикрепленный к этому элементу управления. Удаляя другой код, который должен обработать этот слушатель, у меня есть это:

       txtAnswer.addKeyListener(new KeyAdapter() {
        @Override
        public void keyPressed(KeyEvent e) {

            int key = e.getKeyCode();

            /* Restrict input to only integers */
            if (key < 96 && key > 105) e.setKeyChar('');
        };
    });

Как вы можете видеть, я пытаюсь использовать KeyCode, чтобы проверить, попадает ли только что нажатая клавиша в диапазон целых чисел. Это похоже на работу. Но я хочу просто игнорировать запись, если она выходит за пределы этого диапазона. Кодe.setKeyChar('') должен был справиться с этим, но он не работает. Код скомпилируется, но он не имеет видимого эффекта.

Кто-нибудь может сказать мне, если я на правильном пути? Что я могу заменитьe.setKeyChar('') чтобы сделать эту работу? Или я совершенно не в том направлении?

Благодарю.

@ Рэнди: Пожалуйста, посмотрите на этоexample также nIcE cOw

Ваш Ответ

6   ответов
5

Раньше я использовал 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();
                }
            }
        });
    }
3

Когда вы вводите целые числа в JtextField1 после отпускания ключа, он идет внутрь try, для любого другого символа он генерирует исключение NumberFormatException. Если вы установите пустую строку в jTextField1 внутри перехвата, чтобы пользователь не мог вводить любые другие ключи, кроме положительных чисел, потому что 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("");
    }
}   
12

Вот один из подходов, который использует 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

61

Не используйте KeyListener для этого, так как вы многое пропустите, включая вставку текста. Кроме того, KeyListener - это очень низкоуровневая конструкция, поэтому ее следует избегать в приложениях Swing.

Решение было описано много раз на SO:DocumentFilter, На этом сайте есть несколько примеров, некоторые из которых написаны мной.

Например:используя-documentfilter-filterbypass

Также для учебной помощи, пожалуйста, посмотрите на:Реализация DocumentFilter.

Edit

Например:

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
      }

   }
}

Почему это важно?

  • What if the user uses copy and paste to insert data into the text component? A KeyListener can miss this?
  • You appear to be desiring to check that the data can represent an int. What if they enter numeric data that doesn't fit?
  • What if you want to allow the user to later enter double data? In scientific notation?
+1 Тоже посмотримInputVerifier.
@Randy: изменить метод теста (текст строки). Пусть это вернет, еслиtext.trim().isEmpty() правда.
Спасибо вам за образец. Это очень полезно. Ваш пример, кажется, ограничивает ввод максимум 10 цифрами. Подскажите, пожалуйста, как увеличить это?
Я столкнулся с проблемой, что вы не можете стереть последнюю цифру, если у вас есть та же проблема, вы можете использовать этот кусок кода в функции удаления.if(sb.toString().length() == 0) { super.replace(fb, offset, length, "0", null); } else { if (test(sb.toString())) { super.remove(fb, offset, length); } else { // warn the user and don't allow the insert } }                 В моем примере я заменяю его"0", но вы можете заменить его на""
Это довольно круто. Я давно смотрю на это и тестирую в упрощенном приложении. Я более или менее понимаю, что он делает и почему (более или менее!). Это создает для меня одну проблему. На моем JTextBox после того, как пользователь нажал клавишу ввода, я вызываю несколько методов, для выполнения которых я все еще использую KeyListener. Это похоже на работу. Но ОЧЕНЬ последнее, что мне нужно сделать с этим текстовым полем, это очистить его, чтобы можно было вводить новый текст. Я делал это с txtAnswer.setText (& quot; & quot;); но теперь кажется, что этот фильтр документов блокирует это действие. Кто-нибудь может подсказать? Поблагодарить Alex
38

Вы также можете использовать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());
}
field.setColumns (..) // для числа ширины больше 1000 не может быть проанализировано в целое число. (обычный способ)
При этом пользователь может вставлять буквы в поле.
Этот метод работает хорошо, за исключением одного: после ввода числа первая цифра не может быть удалена клавишей Backspace.
@cesAR: я исправил это, кодировав свою собственную реализацию, вы можете обратиться к ответу Hovercraft Full Of Eels, я также добавил комментарий в конце, чтобы решить эту проблему. Проблема возникает из-за того, что она не учитывает"" в качестве действительного Interger / Double ..
20

Я не могу поверить, что пока не нашел это простое решение где-либо при переполнении стека, оно, безусловно, самое полезное. Изменение Document или 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);
@LeeCambl Эту проблему можно решить, сделав подклассNumberFormatter который переопределяетstringToValue(String text) возвращатьnull для пустой строки.
Поле также никогда не может быть пустым после того, как вы начали что-то набирать в нем (то есть, если я наберу 1234 и решу «на самом деле, мне не нужно число в этом поле», останется хотя бы один символ).

Похожие вопросы