Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
135 views
in Technique[技术] by (71.8m points)

java - JTextArea setText() & UndoManager

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:

  1. Run the following code
  2. Click the setText() button
  3. Press CTRL+Z to undo (you'll see an empty textarea!)
  4. Press CTRL+Z to undo (you'll see the actual previous text)

I 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);
    }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

By default javax.swing.undo.UndoManager retains each undoable edit, including the one that removes of the original text (your step three). Individual edits are inaccessible, but you can group edits using the approach cited here. Some additional notes on your example:

  • For better cross-platform results, use getMenuShortcutKeyMask() as suggested here.

  • Use a layout; if necessary, invoke setSize() after pack(), as shown here.

  • Swing GUI objects should be constructed and manipulated only on the event dispatch thread.

Code:

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import static javax.swing.JFrame.EXIT_ON_CLOSE;
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;

@SuppressWarnings("serial")
public class JTextComponentSetTextUndoEvent extends JFrame {

    private static final int MASK
        = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
    private JTextArea area = new JTextArea();
    private UndoManager undoManager = new UndoManager();

    public JTextComponentSetTextUndoEvent() {
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        area.setText("Test");
        add(area);
        JButton btnSettext = new JButton("setText()");
        btnSettext.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                area.setText("stackoverflow.com");
            }
        });
        add(btnSettext, BorderLayout.PAGE_END);
        Document doc = area.getDocument();
        doc.addUndoableEditListener(new UndoableEditListener() {
            @Override
            public void undoableEditHappened(UndoableEditEvent e) {
                undoManager.addEdit(e.getEdit());
                System.out.println(e);
            }
        });
        area.getActionMap().put("Undo", new AbstractAction("Undo") {
            @Override
            public void actionPerformed(ActionEvent evt) {
                try {
                    if (undoManager.canUndo()) {
                        undoManager.undo();
                    }
                } catch (CannotUndoException e) {
                    System.out.println(e);
                }
            }
        });
        area.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_Z, MASK), "Undo");
        area.getActionMap().put("Redo", new AbstractAction("Redo") {
            @Override
            public void actionPerformed(ActionEvent evt) {
                try {
                    if (undoManager.canRedo()) {
                        undoManager.redo();
                    }
                } catch (CannotRedoException e) {
                    System.out.println(e);
                }
            }
        });
        area.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_Y,MASK), "Redo");
        pack();
        setSize(320, 240);
        setLocationRelativeTo(null);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new JTextComponentSetTextUndoEvent().setVisible(true);
            }
        });
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...