Подтвердить что ты не робот

Есть ли способ принять только числовые значения в JTextField?

Есть ли способ принять только числовые значения в JTextField? Есть ли специальный метод для этого?

4b9b3361

Ответ 1

Поскольку этот вопрос повторяется довольно часто, я прилагаю к этому больше усилий, чем обычно.

Мое голосование идет на JFormattedTextField. ИМО каждый разработчик Swing должен иметь улучшенную версию этого класса в своем наборе инструментов, поскольку он позволяет проверять почти все, что вы можете себе представить, правильным выбором Format. Примеры, для которых я уже использовал его:

  • Строковый ввод, где String может быть пустым
  • Ввод координат
  • Ввод даты
  • Редактор на JSpinner
  • Масштабы карты
  • Числа
  • ...

Он также позволяет визуальную обратную связь, когда вход недействителен, например, не в случае с InputVerifier. Он по-прежнему позволяет пользователю вводить что-либо, но это значение просто не принимается, когда оно недействительно, и это значение никогда не покидает пользовательский интерфейс. Я думаю (но опять же, это мое мнение), что лучше разрешить пользователю вводить недопустимый ввод, который просто удаляет это автоматически, например. a DocumentFilter. Я бы заподозрил ошибку, когда тип символа в текстовом поле не отображается.

Позвольте мне проиллюстрировать это с помощью некоторого кода (на самом деле, кода). Сначала небольшое демо-приложение. Это приложение просто показывает JFormattedTextField для чисел. Просто использование другого формата позволяет повторно использовать этот компонент для совершенно разных проверок.

enter image description here

import be.pcl.swing.ImprovedFormattedTextField;

import javax.swing.*;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.NumberFormat;

/**
 * See http://stackoverflow.com/q/1313390/1076463
 */
public class FormattedTextFieldDemo {
  public static void main( String[] args ) {
    EventQueue.invokeLater(new Runnable() {
      @Override
      public void run() {
        JFrame testFrame = new JFrame( "FormattedTextFieldDemo" );

        NumberFormat integerNumberInstance = NumberFormat.getIntegerInstance();
        ImprovedFormattedTextField integerFormattedTextField = new ImprovedFormattedTextField( integerNumberInstance, 100 );
        integerFormattedTextField.setColumns( 20 );

        testFrame.add( createButtonPanel( integerFormattedTextField ), BorderLayout.NORTH );

        final JTextArea textArea = new JTextArea(50, 50);
        PropertyChangeListener updateTextAreaListener = new PropertyChangeListener() {
          @Override
          public void propertyChange( PropertyChangeEvent evt ) {
            textArea.append( "New value: " + evt.getNewValue() + "\n" );
          }
        };
        integerFormattedTextField.addPropertyChangeListener( "value", updateTextAreaListener );

        testFrame.add( new JScrollPane( textArea ), BorderLayout.CENTER );

        testFrame.setDefaultCloseOperation( WindowConstants.DISPOSE_ON_CLOSE );
        testFrame.pack();
        testFrame.setVisible( true );
      }
    } );

  }

  private static JPanel createButtonPanel( final JFormattedTextField aTextField ){
    JPanel panel = new JPanel( new BorderLayout(  ) );
    panel.add( aTextField, BorderLayout.WEST );

    Action action = new AbstractAction() {
      {
        aTextField.addPropertyChangeListener( "editValid", new PropertyChangeListener() {
          @Override
          public void propertyChange( PropertyChangeEvent evt ) {
            setEnabled( ( ( Boolean ) evt.getNewValue() ) );
          }
        } );
        putValue( Action.NAME, "Show current value" );
      }
      @Override
      public void actionPerformed( ActionEvent e ) {
        JOptionPane.showMessageDialog( null, "The current value is [" + aTextField.getValue() + "] of class [" + aTextField.getValue().getClass() + "]" );
      }
    };
    panel.add( new JButton( action ), BorderLayout.EAST );
    return panel;
  }
}

который показывает только ImprovedFormattedTextField и a JButton, который активируется только тогда, когда вход действителен (ага, есть это решение DocumentFilter). Он также показывает JTextArea, в котором значение печатается каждый раз, когда встречается новое допустимое значение. Нажатие кнопки показывает значение.

Код для ImprovedFormattedTextField можно найти ниже, вместе с ParseAllFormat, от которого он зависит

package be.pcl.swing;

import javax.swing.JFormattedTextField;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.Color;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.KeyEvent;
import java.text.Format;
import java.text.ParseException;

/**
 * <p>Extension of {@code JFormattedTextField} which solves some of the usability issues</p>
 */
public class ImprovedFormattedTextField extends JFormattedTextField {

  private static final Color ERROR_BACKGROUND_COLOR = new Color( 255, 215, 215 );
  private static final Color ERROR_FOREGROUND_COLOR = null;

  private Color fBackground, fForeground;

  /**
   * Create a new {@code ImprovedFormattedTextField} instance which will use {@code aFormat} for the
   * validation of the user input.
   *
   * @param aFormat The format. May not be {@code null}
   */
  public ImprovedFormattedTextField( Format aFormat ) {
    //use a ParseAllFormat as we do not want to accept user input which is partially valid
    super( new ParseAllFormat( aFormat ) );
    setFocusLostBehavior( JFormattedTextField.COMMIT_OR_REVERT );
    updateBackgroundOnEachUpdate();
    //improve the caret behavior
    //see also http://tips4java.wordpress.com/2010/02/21/formatted-text-field-tips/
    addFocusListener( new MousePositionCorrectorListener() );
  }

  /**
   * Create a new {@code ImprovedFormattedTextField} instance which will use {@code aFormat} for the
   * validation of the user input. The field will be initialized with {@code aValue}.
   *
   * @param aFormat The format. May not be {@code null}
   * @param aValue  The initial value
   */
  public ImprovedFormattedTextField( Format aFormat, Object aValue ) {
    this( aFormat );
    setValue( aValue );
  }

  private void updateBackgroundOnEachUpdate() {
    getDocument().addDocumentListener( new DocumentListener() {
      @Override
      public void insertUpdate( DocumentEvent e ) {
        updateBackground();
      }

      @Override
      public void removeUpdate( DocumentEvent e ) {
        updateBackground();
      }

      @Override
      public void changedUpdate( DocumentEvent e ) {
        updateBackground();
      }
    } );
  }

  /**
   * Update the background color depending on the valid state of the current input. This provides
   * visual feedback to the user
   */
  private void updateBackground() {
    boolean valid = validContent();
    if ( ERROR_BACKGROUND_COLOR != null ) {
      setBackground( valid ? fBackground : ERROR_BACKGROUND_COLOR );
    }
    if ( ERROR_FOREGROUND_COLOR != null ) {
      setForeground( valid ? fForeground : ERROR_FOREGROUND_COLOR );
    }
  }

  @Override
  public void updateUI() {
    super.updateUI();
    fBackground = getBackground();
    fForeground = getForeground();
  }

  private boolean validContent() {
    AbstractFormatter formatter = getFormatter();
    if ( formatter != null ) {
      try {
        formatter.stringToValue( getText() );
        return true;
      } catch ( ParseException e ) {
        return false;
      }
    }
    return true;
  }

  @Override
  public void setValue( Object value ) {
    boolean validValue = true;
    //before setting the value, parse it by using the format
    try {
      AbstractFormatter formatter = getFormatter();
      if ( formatter != null ) {
        formatter.valueToString( value );
      }
    } catch ( ParseException e ) {
      validValue = false;
      updateBackground();
    }
    //only set the value when valid
    if ( validValue ) {
      int old_caret_position = getCaretPosition();
      super.setValue( value );
      setCaretPosition( Math.min( old_caret_position, getText().length() ) );
    }
  }

  @Override
  protected boolean processKeyBinding( KeyStroke ks, KeyEvent e, int condition, boolean pressed ) {
    //do not let the formatted text field consume the enters. This allows to trigger an OK button by
    //pressing enter from within the formatted text field
    if ( validContent() ) {
      return super.processKeyBinding( ks, e,
                                      condition, pressed ) && ks != KeyStroke.getKeyStroke( KeyEvent.VK_ENTER, 0 );
    }
    else {
      return super.processKeyBinding( ks, e,
                                      condition, pressed );
    }
  }

  private static class MousePositionCorrectorListener extends FocusAdapter {
    @Override
    public void focusGained( FocusEvent e ) {
      /* After a formatted text field gains focus, it replaces its text with its
       * current value, formatted appropriately of course. It does this after
       * any focus listeners are notified. We want to make sure that the caret
       * is placed in the correct position rather than the dumb default that is
        * before the 1st character ! */
      final JTextField field = ( JTextField ) e.getSource();
      final int dot = field.getCaret().getDot();
      final int mark = field.getCaret().getMark();
      if ( field.isEnabled() && field.isEditable() ) {
        SwingUtilities.invokeLater( new Runnable() {
          @Override
          public void run() {
            // Only set the caret if the textfield hasn't got a selection on it
            if ( dot == mark ) {
              field.getCaret().setDot( dot );
            }
          }
        } );
      }
    }
  }
}

Класс ParseAllFormat:

package be.pcl.swing;

import java.text.AttributedCharacterIterator;
import java.text.FieldPosition;
import java.text.Format;
import java.text.ParseException;
import java.text.ParsePosition;

/**
 * <p>Decorator for a {@link Format Format} which only accepts values which can be completely parsed
 * by the delegate format. If the value can only be partially parsed, the decorator will refuse to
 * parse the value.</p>
 */
public class ParseAllFormat extends Format {
  private final Format fDelegate;

  /**
   * Decorate <code>aDelegate</code> to make sure if parser everything or nothing
   *
   * @param aDelegate The delegate format
   */
  public ParseAllFormat( Format aDelegate ) {
    fDelegate = aDelegate;
  }

  @Override
  public StringBuffer format( Object obj, StringBuffer toAppendTo, FieldPosition pos ) {
    return fDelegate.format( obj, toAppendTo, pos );
  }

  @Override
  public AttributedCharacterIterator formatToCharacterIterator( Object obj ) {
    return fDelegate.formatToCharacterIterator( obj );
  }

  @Override
  public Object parseObject( String source, ParsePosition pos ) {
    int initialIndex = pos.getIndex();
    Object result = fDelegate.parseObject( source, pos );
    if ( result != null && pos.getIndex() < source.length() ) {
      int errorIndex = pos.getIndex();
      pos.setIndex( initialIndex );
      pos.setErrorIndex( errorIndex );
      return null;
    }
    return result;
  }

  @Override
  public Object parseObject( String source ) throws ParseException {
    //no need to delegate the call, super will call the parseObject( source, pos ) method
    return super.parseObject( source );
  }
}

Возможные улучшения:

  • setBackground не соблюдается всеми Look-and-Feels. Иногда вы можете использовать setForeground, но даже это не гарантируется всеми L & Fs. Поэтому для визуальной обратной связи может быть лучше использовать восклицательный знак, расположенный рядом с полем. Недостатком является то, что это может испортить макет, если вы вдруг добавите/удалите значок
  • обратная связь указывает только на то, что вход действителен/недействителен. Нет ничего, что указывало бы на ожидаемый формат. Возможное решение - использовать самоподготовленное расширение Format, которое включает описание/пример допустимого ввода и поместить его в качестве подсказки в JFormattedTextField.

Ответ 2

Этот вопрос был назван "точной копией" другого вопроса, который с тех пор был закрыт. Ответы на этот вопрос были настолько бедными, что я был вдохновлен помочь кому-либо, кто мог бы найти его позже, путем ссылки на гораздо лучший ответ для этого случая использования.

Это ответ на закрытый вопрос и может быть суммирован как..

Вместо этого используйте JSpinner.

Ответ 3

import javax.swing.*;
import javax.swing.text.*;

public class JNumberTextField extends JTextField
{
    private static final char DOT = '.';
    private static final char NEGATIVE = '-';
    private static final String BLANK = "";
    private static final int DEF_PRECISION = 2;

    public static final int NUMERIC = 2;
    public static final int DECIMAL = 3;

    public static final String FM_NUMERIC = "0123456789";
    public static final String FM_DECIMAL = FM_NUMERIC + DOT;

    private int maxLength = 0;
    private int format = NUMERIC;
    private String negativeChars = BLANK;
    private String allowedChars = null;
    private boolean allowNegative = false;
    private int precision = 0;

    protected PlainDocument numberFieldFilter;

    public JNumberTextField()
    {
        this( 10, NUMERIC );
    }

    public JNumberTextField( int maxLen )
    {
        this( maxLen, NUMERIC );
    }

    public JNumberTextField( int maxLen, int format )
    {
        setAllowNegative( true );
        setMaxLength( maxLen );
        setFormat( format );

        numberFieldFilter = new JNumberFieldFilter();
        super.setDocument( numberFieldFilter );
    }

    public void setMaxLength( int maxLen )
    {
        if (maxLen > 0)
            maxLength = maxLen;
        else
            maxLength = 0;
    }

    public int getMaxLength()
    {
        return maxLength;
    }

    public void setPrecision( int precision )
    {
        if ( format == NUMERIC )
            return;

        if ( precision >= 0 )
            this.precision = precision;
        else
            this.precision = DEF_PRECISION;
    }

    public int getPrecision()
    {
        return precision;
    }

    public Number getNumber()
    {
        Number number = null;

        if ( format == NUMERIC )
            number = new Integer(getText());
        else
            number = new Double(getText());

        return number;
    }

    public void setNumber( Number value )
    {
        setText(String.valueOf(value));
    }

    public int getInt()
    {
        return Integer.parseInt( getText() );
    }

    public void setInt( int value )
    {
        setText( String.valueOf( value ) );
    }

    public float getFloat()
    {
        return ( new Float( getText() ) ).floatValue();
    }

    public void setFloat(float value)
    {
        setText( String.valueOf( value ) );
    }

    public double getDouble()
    {
        return ( new Double( getText() ) ).doubleValue();
    }

    public void setDouble(double value)
    {
        setText( String.valueOf(value) );
    }

    public int getFormat()
    {
        return format;
    }

    public void setFormat(int format)
    {
        switch ( format )
        {
        case NUMERIC:
        default:
            this.format = NUMERIC;
            this.precision = 0;
            this.allowedChars = FM_NUMERIC;
            break;

        case DECIMAL:
            this.format = DECIMAL;
            this.precision = DEF_PRECISION;
            this.allowedChars = FM_DECIMAL;
            break;
        }
    }

    public void setAllowNegative( boolean value )
    {
        allowNegative = value;

        if ( value )
            negativeChars = "" + NEGATIVE;
        else
            negativeChars = BLANK;
    }

    public boolean isAllowNegative()
    {
        return allowNegative;
    }

    public void setDocument( Document document )
    {
    }

    class JNumberFieldFilter extends PlainDocument
    {
        public JNumberFieldFilter()
        {
            super();
        }

        public void insertString(int offset, String str, AttributeSet attr) throws BadLocationException
        {
            String text = getText(0,offset) + str + getText(offset,(getLength() - offset));

            if ( str == null || text == null )
                return;

            for ( int i=0; i<str.length(); i++ )
            {
                if ( ( allowedChars + negativeChars ).indexOf( str.charAt(i) ) == -1)
                    return;
            }

            int precisionLength = 0, dotLength = 0, minusLength = 0;
            int textLength = text.length();

            try
            {
                if ( format == NUMERIC )
                {
                    if ( ! ( ( text.equals( negativeChars ) ) && ( text.length() == 1) ) )
                        new Long(text);
                }
                else if ( format == DECIMAL )
                {
                    if ( ! ( ( text.equals( negativeChars ) ) && ( text.length() == 1) ) )
                        new Double(text);

                    int dotIndex = text.indexOf(DOT);
                    if( dotIndex != -1 )
                    {
                        dotLength = 1;
                        precisionLength = textLength - dotIndex - dotLength;

                        if( precisionLength > precision )
                            return;
                    }
                }
            }
            catch(Exception ex)
            {
                return;
            }

            if ( text.startsWith( "" + NEGATIVE ) )
            {
                if ( !allowNegative )
                    return;
                else
                    minusLength = 1;
            }

            if ( maxLength < ( textLength - dotLength - precisionLength - minusLength ) )
                return;

            super.insertString( offset, str, attr );
        }
    }
}

Ответ 5

Быстрое решение:

JTextField textField = new JTextField() {
  public void processKeyEvent(KeyEvent ev) {
    char c = ev.getKeyChar();
    if (c >= 48 && c <= 57) { // c = '0' ... c = '9'
      super.processKeyEvent(ev);
    }
  }
};

Проблема с вышеупомянутым решением заключается в том, что пользователь не может использовать клавиши "Удалить", "Стрелка влево", "Стрелка вправо" или "Назад" в текстовом поле, поэтому я предлагаю использовать это решение:

this.portTextField = new JTextField() {
  public void processKeyEvent(KeyEvent ev) {
    char c = ev.getKeyChar();
    try {
      // Ignore all non-printable characters. Just check the printable ones.
      if (c > 31 && c < 127) {
        Integer.parseInt(c + "");
      }
      super.processKeyEvent(ev);
    }
    catch (NumberFormatException nfe) {
      // Do nothing. Character inputted is not a number, so ignore it.
    }
  }
};

Ответ 6

Простой подход заключается в подклассе JTextField и переопределении createDefaultModel() путем возврата настраиваемого подкласса PlainDocument. Пример - текстовое поле для целых чисел:

public class NumberField extends JTextField {


@Override
protected Document createDefaultModel() {
    return new Numberdocument();
}

class Numberdocument extends PlainDocument
{
    String numbers="1234567890-";
    @Override
    public void insertString(int offs, String str, AttributeSet a)
            throws BadLocationException {
        if(!numbers.contains(str));
        else    super.insertString(offs, str, a);
    }
}

Вход в процесс в insertString() любым способом.

Ответ 7

Также рассмотрите возможность использования InputVerifier.

Ответ 8

Рассматривая количество просмотров, которые этот вопрос получает, я не нашел ни одного из вышеперечисленных решений, подходящих для моей проблемы. Я решил создать собственный PlainDocument в соответствии с моими потребностями. Это решение также подает звуковой сигнал при достижении максимального количества символов, или вставленный текст не является целым числом.

private class FixedSizeNumberDocument extends PlainDocument
{
    private JTextComponent owner;
    private int fixedSize;

    public FixedSizeNumberDocument(JTextComponent owner, int fixedSize)
    {
        this.owner = owner;
        this.fixedSize = fixedSize;
    }

    @Override
    public void insertString(int offs, String str, AttributeSet a)
            throws BadLocationException
    {
        if (getLength() + str.length() > fixedSize) {
            str = str.substring(0, fixedSize - getLength());
            this.owner.getToolkit().beep();
        }

        try {
            Integer.parseInt(str);
        } catch (NumberFormatException e) {
            // inserted text is not a number
            this.owner.getToolkit().beep();
            return;
        }

        super.insertString(offs, str, a);
    }               
}

встраивается следующим образом:

    JTextField textfield = new JTextField();
    textfield.setDocument(new FixedSizeNumberDocument(textfield,5));

Ответ 9

Очень простое решение - использовать прослушиватель действий.

TextFieldActionPerformed(java.awt.event.ActionEvent evt) {

  try{

    Integer.parseInteger(TextField.getText());

  }
  catch(Exception e){

    JOptionPane.showMessageDialog(null, "Please insert Valid Number Only");

    TextField.setText(TextField.getText().substring(0,TextField.getText().length()-1));
  }

}

Вы также можете использовать его для Double:

Double.parseDouble(TextField.getText());

Ответ 11

напишите этот код в введенный ключ

char c=evt.getKeyChar();
if(!(Character.isDigit(c) || (c==KeyEvent.VK_BACK_SPACE || c==KeyEvent.VK_DELETE)))
{
    getToolkit().beep();
    evt.consume();
}

Ответ 12

if (JTextField.getText().equals("") || !(Pattern.matches("^[0-9]+$", JTextField.getText()))) {
     JOptionPane.showMessageDialog(null, " JTextField Invalide !!!!! ");
   }
  • если JTextField.getText(). equals ("") == → если JTextField пуст
  • if (! (Pattern.matches( "^ [0-9] + $", JTextField.getText()))) == → if TextField содержит другие символы, кроме тех, что
  • JOptionPane.showMessageDialog(null, "JTextField Invalide!!!!!" ); == → , поэтому это сообщение будет выглядеть

Ответ 13

Попробуйте это в событии с нажатой клавишей для связанного JTextField.

private void JTextField(java.awt.event.KeyEvent evt) {

    // TODO add your handling code here:
    char enter = evt.getKeyChar();
    if(!(Character.isDigit(enter))){
        evt.consume();
    }
}

Ответ 14

Используйте formatter для форматирования текстового поля.

NumberFormat format = NumberFormat.getInstance();
format.setGroupingUsed(false);
NumberFormatter formatter = new NumberFormatter(format);
formatter.setValueClass(Integer.class);
formatter.setMaximum(65535);
formatter.setAllowsInvalid(false);
formatter.setCommitsOnValidEdit(true);
myTextField = new JFormattedTextField(formatter);

Ответ 16

Вы хотели бы взглянуть на JFormattedTextField

Форматированные текстовые поля предоставляют разработчикам возможность указать допустимый набор символов, которые могут быть введены в текстовое поле

Это подкласс JTextField, поэтому вы можете использовать его следующим образом:

JTextField textField = new JFormattedTextField(NumberFormat.getInstance());

Ответ 17

Я думаю, что это лучшее решение:

JTextField textField = new JFormattedTextField(new MaskFormatter("###")); //

Ответ 18

Вы можете создать красивое текстовое поле в java, которое принимает или разрешает только числовые значения. Вы даже можете установить точность для значений float... проверьте code в zybocodes

Ответ 19

textfield.addKeyListener(new KeyAdapter()
{
      public void keyTyped(KeyEvent ke)
{


    char c = ke.getKeyChar();
    if((!(Character.isDigit(c))) && // Only digits
    (c ! '\b') ) // For backspace
    {
         ke.consume();
    }
 }

public void keyReleased(KeyEvent e){}
public void keyPressed(KeyEvent e){}
});