La respuesta habitual a esto es "usar a DocumentListener
". Sin embargo, siempre encuentro esa interfaz engorrosa. A decir verdad, la interfaz está sobredimensionada. Tiene tres métodos, para inserción, eliminación y reemplazo de texto, cuando solo necesita un método: reemplazo. (Una inserción se puede ver como un reemplazo de ningún texto con algún texto, y una eliminación se puede ver como un reemplazo de un texto sin texto).
Por lo general, todo lo que desea saber es cuándo ha cambiado el texto en el cuadro , por lo que una DocumentListener
implementación típica tiene los tres métodos que llaman a un método.
Por lo tanto, hice el siguiente método de utilidad, que le permite usar un método ChangeListener
más simple en lugar de a DocumentListener
. (Utiliza la sintaxis lambda de Java 8, pero puede adaptarla para Java antiguo si es necesario).
/**
* 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);
}
A diferencia de agregar un agente de escucha directamente al documento, esto maneja el caso (poco común) de que instale un nuevo objeto de documento en un componente de texto. Además, resuelve el problema mencionado en la respuesta de Jean-Marc Astesana , donde el documento a veces dispara más eventos de los que necesita.
De todos modos, este método le permite reemplazar el código molesto que se ve así:
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();
}
});
Con:
addChangeListener(someTextBox, e -> doSomething());
Código liberado al dominio público. ¡Que te diviertas!