Value Change Listener to JTextField Value Change Listener to JTextField java java

Value Change Listener to JTextField


Add a listener to the underlying Document, which is automatically created for you.

// Listen for changes in the texttextField.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);     }  }});


The usual answer to this is "use a DocumentListener". However, I always find that interface cumbersome. Truthfully the interface is over-engineered. It has three methods, for insertion, removal, and replacement of text, when it only needs one method: replacement. (An insertion can be viewed as a replacement of no text with some text, and a removal can be viewed as a replacement of some text with no text.)

Usually all you want is to know is when the text in the box has changed, so a typical DocumentListener implementation has the three methods calling one method.

Therefore I made the following utility method, which lets you use a simpler ChangeListener rather than a DocumentListener. (It uses Java 8's lambda syntax, but you can adapt it for old Java if needed.)

/** * Installs a listener to receive notification when the text of any * {@code JTextComponent} is changed. Internally, it installs a * {@link DocumentListener} on the text component's {@link Document}, * and a {@link PropertyChangeListener} on the text component to detect * if the {@code Document} itself is replaced. *  * @param text any text component, such as a {@link JTextField} *        or {@link JTextArea} * @param changeListener a listener to receieve {@link ChangeEvent}s *        when the text is changed; the source object for the events *        will be the text component * @throws NullPointerException if either parameter is null */public static void addChangeListener(JTextComponent text, ChangeListener changeListener) {    Objects.requireNonNull(text);    Objects.requireNonNull(changeListener);    DocumentListener dl = new DocumentListener() {        private int lastChange = 0, lastNotifiedChange = 0;        @Override        public void insertUpdate(DocumentEvent e) {            changedUpdate(e);        }        @Override        public void removeUpdate(DocumentEvent e) {            changedUpdate(e);        }        @Override        public void changedUpdate(DocumentEvent e) {            lastChange++;            SwingUtilities.invokeLater(() -> {                if (lastNotifiedChange != lastChange) {                    lastNotifiedChange = lastChange;                    changeListener.stateChanged(new ChangeEvent(text));                }            });        }    };    text.addPropertyChangeListener("document", (PropertyChangeEvent e) -> {        Document d1 = (Document)e.getOldValue();        Document d2 = (Document)e.getNewValue();        if (d1 != null) d1.removeDocumentListener(dl);        if (d2 != null) d2.addDocumentListener(dl);        dl.changedUpdate(null);    });    Document d = text.getDocument();    if (d != null) d.addDocumentListener(dl);}

Unlike with adding a listener directly to the document, this handles the (uncommon) case that you install a new document object on a text component. Additionally, it works around the problem mentioned in Jean-Marc Astesana's answer, where the document sometimes fires more events than it needs to.

Anyway, this method lets you replace annoying code which looks like this:

someTextBox.getDocument().addDocumentListener(new DocumentListener() {    @Override    public void insertUpdate(DocumentEvent e) {        doSomething();    }    @Override    public void removeUpdate(DocumentEvent e) {        doSomething();    }    @Override    public void changedUpdate(DocumentEvent e) {        doSomething();    }});

With:

addChangeListener(someTextBox, e -> doSomething());

Code released to public domain. Have fun!


Just create an interface that extends DocumentListener and implements all DocumentListener methods:

@FunctionalInterfacepublic interface SimpleDocumentListener extends DocumentListener {    void update(DocumentEvent e);    @Override    default void insertUpdate(DocumentEvent e) {        update(e);    }    @Override    default void removeUpdate(DocumentEvent e) {        update(e);    }    @Override    default void changedUpdate(DocumentEvent e) {        update(e);    }}

and then:

jTextField.getDocument().addDocumentListener(new SimpleDocumentListener() {    @Override    public void update(DocumentEvent e) {        // Your code here    }});

or you can even use lambda expression:

jTextField.getDocument().addDocumentListener((SimpleDocumentListener) e -> {    // Your code here});