Reputation: 1758
This is my code:
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.Document;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Frame extends JFrame {
private JTextField txt1 = new JTextField(10);
private JTextField txt2 = new JTextField(10);
private JButton btn = new JButton("Set Text");
public Frame() {
super("Latihan");
setLayout(new FlowLayout());
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
txt1.setText("TEST"); txt2.setText("TEST2");
}
});
txt1.getDocument().addDocumentListener(new TheDocumentListener("txt1"));
txt2.getDocument().addDocumentListener(new TheDocumentListener("txt2"));
add(txt1);
add(txt2);
add(btn);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setVisible(true);
}
public static void main (String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new Frame();
}
});
}
}
class TheDocumentListener implements DocumentListener {
private String source;
public TheDocumentListener(String source) {
this.source = source;
}
@Override
public void insertUpdate(DocumentEvent e) {
System.out.println("insertUpdate from " + source);
}
@Override
public void removeUpdate(DocumentEvent e) {
System.out.println("removeUpdate from " + source);
}
@Override
public void changedUpdate(DocumentEvent e) {
System.out.println("changedUpdate from " + source);
}
}
When I click on the JButton for the first time, only insertUpdate()
will be called:
insertUpdate from txt1
insertUpdate from txt2
But if I click the button again, removeUpdate()
will be called before insertUpdate()
:
removeUpdate from txt1
insertUpdate from txt1
removeUpdate from txt2
insertUpdate from txt2
Is this expected behaviour or something wrong in my code?
Can I make insertUpdate
the only method that was being called when performing JTextField.setText
? I want to make sure removeUpdate
is being called only when user delete text in the text field. How to do that?
Upvotes: 7
Views: 6906
Reputation: 21233
This is the expected behavior of string replacement. What setText()
actually does is remove the whole string and set a new one. Here is the implementation of JTextField.setText()
:
public void setText(String t) {
try {
Document doc = getDocument();
if (doc instanceof AbstractDocument) {
((AbstractDocument)doc).replace(0, doc.getLength(), t,null);
}
else {
doc.remove(0, doc.getLength());
doc.insertString(0, t, null);
}
} catch (BadLocationException e) {
UIManager.getLookAndFeel().provideErrorFeedback(JTextComponent.this);
}
}
As you can see, AbstractDocument.replace()
is executed for AbstractDocument
docs. Otherwise, remove()
and insert()
are executed.
From AbstractDocument.replace() documentation:
Deletes the region of text from offset to offset + length, and replaces it with text. It is up to the implementation as to how this is implemented, some implementations may treat this as two distinct operations: a remove followed by an insert, others may treat the replace as one atomic operation.
So it depends on the document implementation. PlainDocument
for example inherits basic implementation of AbstractDocument
. A PlainDocument
is the default document for text fields.
You can always create you own document implementation if needed, or maybe installing a document filter. See Using Text Components tutorial for details. Not sure though, what is the reason behind this behavior change you're trying to achieve.
Upvotes: 5