Câu trả lời thông thường cho điều này là "sử dụng một DocumentListener
". Tuy nhiên, tôi luôn thấy giao diện đó cồng kềnh. Thực sự giao diện được thiết kế quá mức. Nó có ba phương thức, để chèn, xóa và thay thế văn bản, khi nó chỉ cần một phương thức: thay thế. (Một phần chèn có thể được xem như là sự thay thế không có văn bản với một số văn bản và việc xóa có thể được xem như là sự thay thế của một số văn bản không có văn bản.)
Thông thường tất cả những gì bạn muốn là biết khi văn bản trong hộp đã thay đổi , vì vậy một DocumentListener
triển khai điển hình có ba phương thức gọi một phương thức.
Do đó tôi đã thực hiện phương thức tiện ích sau, cho phép bạn sử dụng đơn giản ChangeListener
hơn là a DocumentListener
. (Nó sử dụng cú pháp lambda của Java 8, nhưng bạn có thể điều chỉnh nó cho Java cũ nếu cần.)
/**
* 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);
}
Không giống như thêm người nghe trực tiếp vào tài liệu, điều này xử lý trường hợp (không phổ biến) mà bạn cài đặt một đối tượng tài liệu mới trên một thành phần văn bản. Ngoài ra, nó hoạt động xung quanh vấn đề được đề cập trong câu trả lời của Jean-Marc Astesana , trong đó tài liệu đôi khi phát sinh nhiều sự kiện hơn mức cần thiết.
Dù sao, phương pháp này cho phép bạn thay thế mã gây phiền nhiễu trông như thế này:
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();
}
});
Với:
addChangeListener(someTextBox, e -> doSomething());
Mã được phát hành cho miền công cộng. Chúc vui vẻ!