java - JTextArea setText() & UndoManager

标签 java swing jtextarea undo-redo

我正在使用 UndoManager 来捕获我的 JTextArea 中的更改。

setText() 方法会删除所有内容,然后粘贴文本。当我撤消时,我首先看到一个空白区域,然后它会显示它之前的文本。

如何重现:

  1. 运行以下代码
  2. 点击setText()按钮
  3. CTRL+Z 撤消(您会看到一个空的文本区域!)
  4. CTRL+Z 撤消(您将看到实际的先前文本)

我想跳过 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);
    }
}

最佳答案

默认情况下,javax.swing.undo.UndoManager 会保留每个可撤消的编辑,包括删除原始文本的编辑(您的第三步)。无法访问单个编辑,但您可以使用引用的方法分组编辑 here .关于您的示例的一些附加说明:

  • 为了获得更好的跨平台结果,请按照建议使用 getMenuShortcutKeyMask() here .

  • 使用 layout ;如有必要,调用 setSize() after pack(),如图所示 here .

  • Swing GUI 对象应该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);
            }
        });
    }
}

关于java - JTextArea setText() & UndoManager,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24433089/

相关文章:

java - 如何将MySQL表中的数据导入到Java JTable中?

java - 遗传算法旅行商概率不断循环

java - Swing BoxLayout

java - 设置 View 可见性 GONE 保留其他 View

java - 在单行中分配和执行 if/else 条件

java - 拖动未修饰的 JFrame 并调整其大小

java - JAVA中大写ActionEvent函数

java - 在 .properties 文件中加密值之前是否需要 ENC 函数?

java - LWJGL - 加载字体后一切都消失了

java - JTextArea行数限制