227 votes

Écouteur de changement de valeur pour JTextField

Je veux que la boîte de message apparaisse immédiatement après que l'utilisateur ait modifié la valeur du champ de texte. Actuellement, je dois appuyer sur la touche Entrée pour que la boîte de message s'affiche. Y a-t-il un problème avec mon code ?

textField.addActionListener(new java.awt.event.ActionListener() {
    public void actionPerformed(java.awt.event.ActionEvent e) {

        if (Integer.parseInt(textField.getText())<=0){
            JOptionPane.showMessageDialog(null,
                    "Error: Please enter number bigger than 0", "Error Message",
                    JOptionPane.ERROR_MESSAGE);
        }       
    }
}

Toute aide serait appréciée !

391voto

Codemwnci Points 28817

Ajoutez un écouteur au document sous-jacent, qui est automatiquement créé pour vous.

// Listen for changes in the text
textField.getDocument().addDocumentListener(new DocumentListener() {
  public void changedUpdate(DocumentEvent e) {
    warn();
  }
  public void removeUpdate(DocumentEvent e) {
    warn();
  }
  public void insertUpdate(DocumentEvent e) {
    warn();
  }

  public void warn() {
     if (Integer.parseInt(textField.getText())<=0){
       JOptionPane.showMessageDialog(null,
          "Error: Please enter number bigger than 0", "Error Message",
          JOptionPane.ERROR_MESSAGE);
     }
  }
});

0 votes

bon format pour le casting d'avertissement/type. Le même modèle sera utile pour gérer les montants doubles (chiffres de vente/prix saisis ou affichés).

0 votes

cela fonctionne bien mais j'ai une requête qui, lorsque j'insère du texte dans le champ texte, veut appeler une méthode. je n'ai pas beaucoup d'idée sur la façon dont cela est fait

0 votes

J'avais des problèmes avec une JTable qui ne recevait pas les mises à jour de la zone de texte d'une JComboBox éditable lorsque je cliquais sur une autre cellule de la table, et la fonction insertUpdate ici était la seule façon de la faire fonctionner correctement.

16voto

Sachez que lorsque l'utilisateur modifie le champ, le DocumentListener peut, parfois, recevoir deux événements. Par exemple, si l'utilisateur sélectionne tout le contenu du champ, puis appuie sur une touche, vous recevrez un removeUpdate (tout le contenu est supprimé) et un insertUpdate. Dans votre cas, je ne pense pas que ce soit un problème mais, en général, ça l'est. Malheureusement, il semble qu'il n'y ait aucun moyen de suivre le contenu du textField sans sous-classer JTextField. Voici le code d'une classe qui fournit une propriété "text" :

package net.yapbam.gui.widget;

import javax.swing.JTextField;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;

/** A JTextField with a property that maps its text.
 * <br>I've found no way to track efficiently the modifications of the text of a JTextField ... so I developed this widget.
 * <br>DocumentListeners are intended to do it, unfortunately, when a text is replace in a field, the listener receive two events:<ol>
 * <li>One when the replaced text is removed.</li>
 * <li>One when the replacing text is inserted</li>
 * </ul>
 * The first event is ... simply absolutely misleading, it corresponds to a value that the text never had.
 * <br>Anoter problem with DocumentListener is that you can't modify the text into it (it throws IllegalStateException).
 * <br><br>Another way was to use KeyListeners ... but some key events are throw a long time (probably the key auto-repeat interval)
 * after the key was released. And others events (for example a click on an OK button) may occurs before the listener is informed of the change.
 * <br><br>This widget guarantees that no "ghost" property change is thrown !
 * @author Jean-Marc Astesana
 * <BR>License : GPL v3
 */

public class CoolJTextField extends JTextField {
    private static final long serialVersionUID = 1L;

    public static final String TEXT_PROPERTY = "text";

    public CoolJTextField() {
        this(0);
    }

    public CoolJTextField(int nbColumns) {
        super("", nbColumns);
        this.setDocument(new MyDocument());
    }

    @SuppressWarnings("serial")
    private class MyDocument extends PlainDocument {
        private boolean ignoreEvents = false;

        @Override
        public void replace(int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
            String oldValue = CoolJTextField.this.getText();
            this.ignoreEvents = true;
            super.replace(offset, length, text, attrs);
            this.ignoreEvents = false;
            String newValue = CoolJTextField.this.getText();
            if (!oldValue.equals(newValue)) CoolJTextField.this.firePropertyChange(TEXT_PROPERTY, oldValue, newValue);
        }

        @Override
        public void remove(int offs, int len) throws BadLocationException {
            String oldValue = CoolJTextField.this.getText();
            super.remove(offs, len);
            String newValue = CoolJTextField.this.getText();
            if (!ignoreEvents && !oldValue.equals(newValue)) CoolJTextField.this.firePropertyChange(TEXT_PROPERTY, oldValue, newValue);
        }
    }

4 votes

Swing déjà a un type de textField qui fait correspondre les modifications du document à une propriété - il s'appelle JFormattedTextField :-)

11voto

Astridax Points 71

Je sais que cela concerne un problème très ancien, mais il m'a également causé quelques problèmes. Comme kleopatra répondu dans un commentaire ci-dessus, j'ai résolu le problème avec une JFormattedTextField . Cependant, cette solution demande un peu plus de travail, mais est plus soignée.

Le site JFormattedTextField ne déclenche pas par défaut un changement de propriété après chaque modification de texte dans le champ. Le constructeur par défaut de JFormattedTextField ne crée pas de formateur.

Cependant, pour faire ce que le PO a suggéré, vous devez utiliser un formateur qui invoquera la fonction commitEdit() après chaque modification valide du champ. Le site commitEdit() est ce qui déclenche le changement de propriété d'après ce que je peux voir et sans le formateur, ceci est déclenché par défaut sur un changement de focus ou lorsque la touche entrée est pressée.

Voir http://docs.oracle.com/javase/tutorial/uiswing/components/formattedtextfield.html#value pour plus de détails.

Créer un formateur par défaut ( DefaultFormatter ) à passer à l'objet JFormattedTextField soit par l'intermédiaire de son constructeur ou d'une méthode de paramétrage. Une méthode du formateur par défaut est setCommitsOnValidEdit(boolean commit) qui définit le formateur pour déclencher le commitEdit() à chaque fois que le texte est modifié. Ceci peut ensuite être récupéré en utilisant une méthode PropertyChangeListener et le propertyChange() méthode.

0voto

Giang D HN Points 23

Vous pouvez même utiliser "MouseExited" pour contrôler. exemple :

 private void jtSoMauMouseExited(java.awt.event.MouseEvent evt) {                                    
        // TODO add your handling code here:
        try {
            if (Integer.parseInt(jtSoMau.getText()) > 1) {
                //auto update field
                SoMau = Integer.parseInt(jtSoMau.getText());
                int result = SoMau / 5;

                jtSoBlockQuan.setText(String.valueOf(result));
            }
        } catch (Exception e) {

        }

    }

6 votes

pas vraiment : l'exigence est de faire quelque chose lorsque le texte est modifié - qui n'est pas lié aux mouseEvents ;-)

0voto

nick Points 1

Utilisez un KeyListener (qui se déclenche sur n'importe quelle touche) plutôt qu'un ActionListener (qui se déclenche sur l'entrée).

0 votes

Cela ne fonctionne pas car la valeur du champ n'est pas capturée correctement, field.getText() renvoie la valeur initiale. et l'événement ( arg0.getKeyChar() ) renvoie la touche pressée une vérification des erreurs est nécessaire pour déterminer si vous devez concaténer le texte du champ.

0 votes

@glend, vous pouvez utiliser l'événement keyReleased au lieu de l'événement keyTyped. Cela a fonctionné pour moi et j'ai obtenu la valeur complète.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X