I'm using an UndoManager
to capture changes in my JTextArea
.
The method setText()
however deletes everything and then pastes the text. When I undo I firstly see an empty area and then it would show which text it had before.
How to reproduce:
setText()
buttonI want to skip 3).
import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.text.Document;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;
import java.awt.event.ActionEvent;
import javax.swing.JButton;
import java.awt.event.ActionListener;
@SuppressWarnings("serial")
public class JTextComponentSetTextUndoEvent extends JFrame
{
JTextArea area = new JTextArea();
public JTextComponentSetTextUndoEvent()
{
setSize(300, 300);
setDefaultCloseOperation(EXIT_ON_CLOSE);
getContentPane().setLayout(null);
area.setText("Test");
area.setBounds(0, 96, 146, 165);
getContentPane().add(area);
JButton btnSettext = new JButton("setText()");
btnSettext.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent arg0)
{
area.setText("stackoverflow.com");
}
});
btnSettext.setBounds(0, 28, 200, 50);
getContentPane().add(btnSettext);
final UndoManager undoManager = new UndoManager();
Document doc = area.getDocument();
doc.addUndoableEditListener(new UndoableEditListener()
{
public void undoableEditHappened(UndoableEditEvent evt)
{
undoManager.addEdit(evt.getEdit());
}
});
area.getActionMap().put("Undo", new AbstractAction("Undo")
{
public void actionPerformed(ActionEvent evt)
{
try
{
if (undoManager.canUndo())
{
undoManager.undo();
}
} catch (CannotUndoException e)
{
}
}
});
area.getInputMap().put(KeyStroke.getKeyStroke("control Z"), "Undo");
area.getActionMap().put("Redo", new AbstractAction("Redo")
{
public void actionPerformed(ActionEvent evt)
{
try
{
if (undoManager.canRedo())
{
undoManager.redo();
}
} catch (CannotRedoException e)
{
}
}
});
area.getInputMap().put(KeyStroke.getKeyStroke("control Y"), "Redo");
}
public static void main(String[] args)
{
new JTextComponentSetTextUndoEvent().setVisible(true);
}
}
You can try something like this:
//Works fine for me on Windows 7 x64 using JDK 1.7.0_60:
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
import javax.swing.undo.*;
public final class UndoManagerTest {
private final JTextField textField0 = new JTextField("default");
private final JTextField textField1 = new JTextField();
private final UndoManager undoManager0 = new UndoManager();
private final UndoManager undoManager1 = new UndoManager();
public JComponent makeUI() {
textField1.setDocument(new CustomUndoPlainDocument());
textField1.setText("aaaaaaaaaaaaaaaaaaaaa");
textField0.getDocument().addUndoableEditListener(undoManager0);
textField1.getDocument().addUndoableEditListener(undoManager1);
JPanel p = new JPanel();
p.add(new JButton(new AbstractAction("undo") {
@Override public void actionPerformed(ActionEvent e) {
if (undoManager0.canUndo()) {
undoManager0.undo();
}
if (undoManager1.canUndo()) {
undoManager1.undo();
}
}
}));
p.add(new JButton(new AbstractAction("redo") {
@Override public void actionPerformed(ActionEvent e) {
if (undoManager0.canRedo()) {
undoManager0.redo();
}
if (undoManager1.canRedo()) {
undoManager1.redo();
}
}
}));
p.add(new JButton(new AbstractAction("setText(new Date())") {
@Override public void actionPerformed(ActionEvent e) {
String str = new Date().toString();
textField0.setText(str);
textField1.setText(str);
}
}));
Box box = Box.createVerticalBox();
box.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
box.add(makePanel("Default", textField0));
box.add(Box.createVerticalStrut(5));
box.add(makePanel("replace ignoring undo", textField1));
JPanel pp = new JPanel(new BorderLayout());
pp.add(box, BorderLayout.NORTH);
pp.add(p, BorderLayout.SOUTH);
return pp;
}
private static JPanel makePanel(String title, JComponent c) {
JPanel p = new JPanel(new BorderLayout());
p.setBorder(BorderFactory.createTitledBorder(title));
p.add(c);
return p;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new UndoManagerTest().makeUI());
f.setSize(320, 240);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
class CustomUndoPlainDocument extends PlainDocument {
private CompoundEdit compoundEdit;
@Override protected void fireUndoableEditUpdate(UndoableEditEvent e) {
if (compoundEdit == null) {
super.fireUndoableEditUpdate(e);
} else {
compoundEdit.addEdit(e.getEdit());
}
}
@Override public void replace(
int offset, int length,
String text, AttributeSet attrs) throws BadLocationException {
if (length == 0) {
System.out.println("insert");
super.replace(offset, length, text, attrs);
} else {
System.out.println("replace");
compoundEdit = new CompoundEdit();
super.fireUndoableEditUpdate(new UndoableEditEvent(this, compoundEdit));
super.replace(offset, length, text, attrs);
compoundEdit.end();
compoundEdit = null;
}
}
}