【问题标题】:Undo the effect of method setText() of JEditorPane in one step not in three一步不三步撤消JEditorPane的setText()方法的效果
【发布时间】:2014-11-17 22:57:36
【问题描述】:

我正在尝试撤消 JEditorPane 中的 setText() 方法效果。这是我的代码:

public final class UndoManagerTestForJEditorPane {

private final JEditorPane editor = new JEditorPane();
private final UndoManager undoManager = new UndoManager();

public JComponent makeUI() {
    editor.setContentType("text/html");
    HTMLDocument document = (HTMLDocument) editor.getDocument();
    document.addUndoableEditListener(undoManager);
    editor.setText("Hello");

    JPanel p = new JPanel();
    p.add(new JButton(new AbstractAction("undo") {
        @Override
        public void actionPerformed(ActionEvent e) {
            if (undoManager.canUndo()) {
                undoManager.undo();
            }
        }
    }));
    p.add(new JButton(new AbstractAction("redo") {
        @Override
        public void actionPerformed(ActionEvent e) {
            if (undoManager.canRedo()) {
                undoManager.redo();
            }
        }
    }));
    p.add(new JButton(new AbstractAction("setText(new Date())") {
        @Override
        public void actionPerformed(ActionEvent e) {
            String str = new Date().toString();
            editor.setText(str);
        }
    }));

    Box box = Box.createVerticalBox();
    box.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
    box.add(makePanel("Default", editor));

    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 UndoManagerTestForJEditorPane().makeUI());
    f.setSize(320, 240);
    f.setLocationRelativeTo(null);
    f.setVisible(true);
}
}

默认行为通过四个步骤完成:

1) 什么都没做,光标甚至没有移动..

2) 光标下降到插入的单词下将近 10 行..

3) 文字消失了..

4) 旧文本终于出现了..

那么,除了这些步骤,我们是否可以只使用一个撤消步骤(如 JTextField JTextArea setText() & UndoManager 的此链接中的一个撤消步骤,但使用 JEditorPane 呢?

在JEditorPane上调用setText()时,JEditorPane的replace方法没有被执行的问题...

请帮忙?

谢谢

【问题讨论】:

  • 感谢您的回答,但我已经在使用这种方法,问题就出在使用例如:JEditorPane ed = new JEditorPane(); ed.setText("一些文字");当我撤消时,行为如第一篇文章中所述。有什么帮助吗?
  • 那么你最好提供一个runnable example 来证明你的问题。这将导致更少的混乱和更好的响应
  • 我添加了代码作为演示,非常感谢:)

标签: java swing


【解决方案1】:

您可以使用扩展AbstractUndoableEdit 的单独类来完成此操作(如果您只需要使用来自一个类的信息进行编辑,则可以嵌套以直接访问必要的 GUI 元素)。您可以保存在一次 undo 操作后要加载的确切旧状态,以及在 redo 操作后要重新加载的确切新状态。然后,您可以在redoundo 方法中直接设置正确的值,方法是在State 类中覆盖它们。这可能如下所示:

public final class UndoManagerTestForJEditorPane {

private final JEditorPane editor = new JEditorPane();
private final UndoManager undoManager = new UndoManager();

public JComponent makeUI() {
    editor.setContentType("text/html");
    HTMLDocument document = (HTMLDocument) editor.getDocument();
    //document.addUndoableEditListener(undoManager);  -> Not used anymore
    editor.setText("Hello");

    JPanel p = new JPanel();
    p.add(new JButton(new AbstractAction("undo") {
        @Override
        public void actionPerformed(ActionEvent e) {
            if (undoManager.canUndo()) {
                undoManager.undo();
            }
        }
    }));

    // New class to hold the state and load the correct string
    class State extends AbstractUndoableEdit
    {
        String oldText;
        String newText;

        State(String oldText, String newText)
        {
            this.oldText = oldText;
            this.newText = newText;
        }

        @Override
        public void undo() throws CannotUndoException {
            editor.setText(oldText);
        }

        @Override
        public boolean canUndo() {
            return true;
        }

        @Override
        public void redo() throws CannotRedoException {
            editor.setText(newText);
        }

        @Override
        public boolean canRedo() {
            return true;
        }


    }
    p.add(new JButton(new AbstractAction("redo") {
        @Override
        public void actionPerformed(ActionEvent e) {
            if (undoManager.canRedo()) {
                undoManager.redo();
            }
        }
    }));
    p.add(new JButton(new AbstractAction("setText(new Date())") {
        @Override
        public void actionPerformed(ActionEvent e) {
            String str = new Date().toString();
            // Add a new edit by saving the old string (by calling getText) and the new string 'str'
            undoManager.addEdit(new State(editor.getText(), str));
            editor.setText(str);
        }
    }));



    Box box = Box.createVerticalBox();
    box.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
    box.add(makePanel("Default", editor));

    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 UndoManagerTestForJEditorPane().makeUI());
    f.setSize(320, 240);
    f.setLocationRelativeTo(null);
    f.setVisible(true);
}
}

【讨论】:

  • 非常感谢您的回答,它工作正常,但它禁用了我在单击 setText 之前制作的版本的侦听器。那么我应该怎么做才能跟踪以前的版本呢?再次感谢您
  • 没问题,现在对你有用吗?很高兴能帮到你
  • 是的,非常感谢,JEditorPane 出现了新问题,我在这里发帖,再次感谢stackoverflow.com/questions/27005483/…
  • 太好了,不客气。您应该为您的新问题提供一些代码。否则我们无能为力。
  • 你好,你能看看我的新帖子吗?非常感谢
猜你喜欢
  • 2019-06-25
  • 2019-09-22
  • 1970-01-01
  • 1970-01-01
  • 2012-10-02
  • 2013-09-06
  • 1970-01-01
  • 2014-08-26
  • 2012-11-18
相关资源
最近更新 更多