Вероятно, вы пытаетесь заставить DocumentListener изменить текст того же документа, который он прослушивает.Это не разрешено согласно DocumentListener API , в котором говорится:
Уведомление DocumentEvent основано на модели событий JavaBeans.Там нет никакой гарантии о порядке доставки для слушателей, и все слушатели должны быть уведомлены до внесения дальнейших изменений в Документ.Это означает, что реализации DocumentListener могут не изменять источник события (то есть связанный с ним документ).
Одним из способов решения этой проблемы является размещение вашего метода для изменения текста документа в Runnable и в очередьэто на EDT с SwingUtilities.invokeLater(...)
.
Другое решение, возможно, лучше, это использовать DocumentFilter
.
пример с DocumentListener:
static class MyDocumentListener2 implements DocumentListener {
private boolean updating = false;
public void insertUpdate(DocumentEvent e) {
updateLog(e, "");
}
public void removeUpdate(DocumentEvent e) {
updateLog(e, "");
}
public void changedUpdate(DocumentEvent e) {
}
public void updateLog(DocumentEvent e, String action) {
if (updating) {
return;
}
updating = true;
final Document doc = (Document) e.getDocument();
try {
System.out.println("Action detected " + doc.getProperty("type"));
final String text = doc.getText(0, doc.getLength());
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
doc.insertString(0, "hey", null);
updating = false;
} catch (BadLocationException e) {
e.printStackTrace();
}
}
});
} catch (BadLocationException catchme2) {
catchme2.printStackTrace();
}
}
}
И пример DocumentListener и DocumentFilter, который превращает весь текст вверхний регистр:
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
public class Foo003 {
private static final String ENTER = "enter";
public static void main(String[] args) {
final JTextArea myArea = new JTextArea(10, 20);
final PlainDocument myDocument = (PlainDocument) myArea.getDocument();
DocumentListener myDocumentListener = new DocumentListener() {
private boolean changing = false;
public void removeUpdate(DocumentEvent e) {}
public void changedUpdate(DocumentEvent e) {
toUpperCase(myArea, myDocument);
}
@Override
public void insertUpdate(DocumentEvent e) {
toUpperCase(myArea, myDocument);
}
private void toUpperCase(final JTextArea myArea,
final PlainDocument myDocument) {
if (changing) {
return;
}
try {
changing = true;
final String text = myDocument
.getText(0, myDocument.getLength()).toUpperCase();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
myArea.setText(text);
changing = false;
}
});
} catch (BadLocationException e1) {
e1.printStackTrace();
}
}
};
myDocument.addDocumentListener(myDocumentListener);
JOptionPane.showMessageDialog(null, new JScrollPane(myArea),
"With DocumentListener", JOptionPane.INFORMATION_MESSAGE);
myDocument.removeDocumentListener(myDocumentListener);
myArea.setText("");
myDocument.setDocumentFilter(new DocumentFilter() {
@Override
public void insertString(FilterBypass fb, int offset, String text,
AttributeSet attr) throws BadLocationException {
text = text.toUpperCase();
super.insertString(fb, offset, text, attr);
}
@Override
public void replace(FilterBypass fb, int offset, int length,
String text, AttributeSet attrs) throws BadLocationException {
text = text.toUpperCase();
super.replace(fb, offset, length, text, attrs);
}
});
JOptionPane.showMessageDialog(null, new JScrollPane(myArea),
"With DocumentFilter", JOptionPane.INFORMATION_MESSAGE);
}
}
Ключевое различие между DocumentListeners и DocumentFilters (и кто-то исправит меня, если я ошибаюсь!) заключается в том, что DocumentListeners запускаются после обновления документа, в то время как DocumentFilters запускаются до его обновления.