Y a-t-il un moyen d'accepter uniquement les valeurs numériques dans un champ Jtext?

est-il possible d'accepter uniquement des valeurs numériques dans un JTextField ? Est-il une méthode spéciale pour cela?

41
demandé sur Lukas Rotter 2009-08-21 22:01:06

19 réponses

comme cette question apparaît assez souvent, j'ai mis plus d'efforts dans cette réponse que je le ferais habituellement.

mon vote va au JFormattedTextField . IMO chaque développeur de Swing devrait avoir une version améliorée de cette classe dans sa boîte à outils car il permet de valider presque tout ce que vous pouvez penser par le choix correct de Format . Exemples pour lesquels je l'ai déjà utilisé:

  • chaîne de caractères entrée où le String ne peut pas être vide
  • entrée coordonnée
  • date entrée
  • de l'Éditeur sur un JSpinner
  • échelles de la Carte
  • nombres
  • ...

il permet également une rétroaction visuelle lorsque l'entrée n'est pas valide, ce qui n'est par exemple pas le cas avec le InputVerifier . Il permet toujours à l'utilisateur d'entrer n'importe quoi, mais cette valeur n'est tout simplement pas acceptée quand elle n'est pas valide et que cette valeur ne quitte jamais L'UI. Je pense (mais encore une fois, c'est mon avis) qu'il est préférable de permettre à l'utilisateur de taper une entrée invalide qui vient de supprimer automatiquement avec par exemple un DocumentFilter . Je suspecterais un bug quand un caractère de type a dans un champ de texte n'apparaît pas.

permettez-moi d'illustrer cela avec un certain code (tout à fait un certain code en fait). D'abord la petite application de démonstration. Cette application montre juste un JFormattedTextField pour les nombres. Juste à l'aide de un autre format permet de réutiliser ce composant pour des validations complètement différentes.

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 /q/is-there-any-way-to-accept-only-numeric-values-in-a-jtextfield-61697/"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;
  }
}

qui montre juste un ImprovedFormattedTextField et un JButton qui n'est activé que lorsque l'entrée est valide (AHA, mangez cette solution DocumentFilter ). Il montre aussi un JTextArea dont la valeur est imprimée à chaque fois qu'une nouvelle valeur valide est rencontré. Appuyer sur le bouton indique la valeur.

Le code pour le ImprovedFormattedTextField peut être trouvé ci-dessous, avec le ParseAllFormat dont elle dépend

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 );
            }
          }
        } );
      }
    }
  }
}

Le ParseAllFormat classe:

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 );
  }
}

améliorations possibles:

  • le setBackground n'est pas respecté par tous. Parfois, vous pouvez utiliser le setForeground à la place, mais même cela n'est pas garanti d'être respecté par tous L&Fs. Donc, pour un retour visuel, il pourrait être mieux pour utiliser un point d'exclamation placé à côté du champ. L'inconvénient est que cela pourrait gâcher une mise en page si vous ajoutez/supprimez soudainement une icône
  • la rétroaction indique seulement que l'entrée est valide/invalide. Il n'y a rien qui indique le format attendu. Une solution possible est d'utiliser une extension auto-créée de Format qui comprend une description/exemple d'entrée valide, et mettre que comme infobulle sur le JFormattedTextField .
53
répondu Robin 2012-11-16 20:44:03

cette question a été citée comme une "réplique exacte" d'une autre question qui a été fermée depuis. Les réponses à cette question étaient si pauvres que j'ai été inspiré pour aider tous ceux qui pourraient le trouver plus tard, en liant à une bien meilleure réponse pour ce cas d'utilisation.

il s'agit d'une réponse à la question fermée et peut se résumer comme suit..

utilisez un JSpinner à la place.

9
répondu Andrew Thompson 2017-05-23 12:10:11
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 );
        }
    }
}
8
répondu Rin 2012-06-07 08:04:33

bien qu'il y ait le mal pur JFormattedTextField il n'y a pas une façon triviale de le faire en utilisant seulement la bibliothèque Swing. La meilleure façon de mettre en œuvre ce genre de fonctionnalité est avec un DocumentFilter .

un code que j'ai préparé plus tôt. un peu de description.

7
répondu Tom Hawtin - tackline 2009-08-21 18:29:11

une approche simple consiste à remplacer la sous-classe JTextField par createDefaultModel() en retournant la sous-classe customised PlainDocument. Exemple - un champ Text pour entiers seulement:

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);
    }
}

Processus d'entrée dans insertString() de toute façon.

4
répondu Alexiy 2014-01-07 18:52:24

une solution rapide:

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);
    }
  }
};

le problème avec la solution CI-DESSUS est que l'utilisateur ne peut pas utiliser les touches Delete, left Arrow, right Arrow, ou Backspace dans le champ de texte, donc je suggère d'utiliser cette solution:

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.
    }
  }
};
3
répondu BJ Peter DeLaCruz 2012-07-23 09:40:37

également, envisager d'utiliser un InputVerifier .

2
répondu trashgod 2011-05-24 14:15:52

considérant le nombre de vues que cette question obtient, Je n'ai trouvé aucune de la solution ci-dessus adapté à mon problème. J'ai décidé de faire une coutume PlainDocument pour répondre à mes besoins. Cette solution produit également un bip sonore lorsque le nombre maximum de caractères utilisés est atteint, ou lorsque le texte inséré n'est pas un entier.

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);
    }               
}

implantée comme suit:

    JTextField textfield = new JTextField();
    textfield.setDocument(new FixedSizeNumberDocument(textfield,5));
2
répondu Terraego 2012-11-15 23:05:44
if (JTextField.getText().equals("") || !(Pattern.matches("^[0-9]+$", JTextField.getText()))) {
     JOptionPane.showMessageDialog(null, " JTextField Invalide !!!!! ");
   }
  • si JTextField.getText ().= ("") = = - >si JTextField est vide
  • if (!(Modèle.les allumettes("^[0-9]+$", JTextField.getText ()))) = = > si TextField contient d'autres caractères que ceux
  • JOptionPane.showMessageDialog(null, " component swing jtextfield Invalid !!!!! "); = = - >ainsi ce message apparaîtra
1
répondu Rbj93 2016-05-14 16:55:09

essayez ceci dans l'événement clé pressé pour le JTextField correspondant.

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

    // TODO add your handling code here:
    char enter = evt.getKeyChar();
    if(!(Character.isDigit(enter))){
        evt.consume();
    }
}
1
répondu Erangad 2016-09-09 17:51:30

utilisez formatter pour formater le champ de texte.

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);
1
répondu XurajB 2016-09-17 01:55:17

une solution très simple est d'utiliser un écouteur d'action.

TextFieldActionPerformed(java.awt.event.ActionEvent evt) {
    String textFieldValue = TextField.getText();
    try {
        Integer.parseInteger(textFieldValue);
    } catch(Exception e){
        JOptionPane.showMessageDialog(null, "Please insert Valid Number Only");
        TextField.setText(textFieldValue.substring(0,textFieldValue.length()-1));
    }
}

vous pouvez L'utiliser pour Double aussi bien:

Double.parseDouble(TextField.getText());
1
répondu Christo Naudé 2018-09-27 18:54:57
0
répondu Zed 2009-08-21 18:06:09

inscrire ce code dans clé dactylographiée

char c=evt.getKeyChar();
if(!(Character.isDigit(c) || (c==KeyEvent.VK_BACK_SPACE || c==KeyEvent.VK_DELETE)))
{
    getToolkit().beep();
    evt.consume();
}
0
répondu Navz 2015-06-23 11:26:47
DataTF.addKeyListener(new KeyAdapter() {
            @Override
            public void keyTyped(KeyEvent eve) {
                String AllowedData="0123456789.";
                char enter = eve.getKeyChar();
                if (!AllowedData.contains(String.valueOf(enter))) {
                    eve.consume();
                }
            }       
        });  
0
répondu Ali Mostafa 2018-05-06 14:21:24

numberField = new JFormattedTextField (NumberFormat.getInstance ());

tutoriel de champ de texte formaté

-1
répondu Stefan Kendall 2009-08-21 18:04:10

vous souhaitez jeter un oeil à JFormattedTextField

les champs de texte formatés fournissent une façon pour les développeurs de spécifier l'ensemble valide de caractères qui peuvent être dactylographiés dans un champ de texte

ceci est une sous-classe de JTextField, donc vous pouvez l'utiliser comme ceci:

JTextField textField = new JFormattedTextField(NumberFormat.getInstance());
-1
répondu OscarRyz 2009-08-21 18:12:25

je pense que c'est la meilleure solution:

JTextField textField = new JFormattedTextField(new MaskFormatter("###")); //
-1
répondu Michal 2009-10-22 02:12:27

vous pouvez créer un beau champ de texte en java qui accepte ou ne permet que des valeurs numériques.. Vous pouvez même définir la précision pour les valeurs flottantes... vérifier le code en zybocodes

-2
répondu Chris 2012-09-08 16:07:20