隐藏Swing的撤消管理器中的某些操作

时间:2009-01-06 17:42:10

标签: java swing undo

我正在尝试编写一个支持某种着色的JTextPane:当用户输入文本时,我正在运行一些代码,根据某种算法为文本着色。这很有效。

问题是着色操作是使用撤消管理器(带有EventType.CHANGE的DefaultDocumentEvent)注册的。因此,当用户单击撤消时,着色消失。仅在第二个撤消请求时,文本本身才会回滚。

(请注意,着色算法有点慢,因此我无法在插入文本时对其进行着色。)

如果我试图阻止CHANGE事件到达撤消管理器,我会在几次撤消请求后得到异常:这是因为文档内容不符合可撤销编辑对象所期望的内容。

有什么想法吗?

4 个答案:

答案 0 :(得分:1)

您是如何阻止CHANGE事件到达撤消管理器的?

在CHANGE排队后,您是否可以立即向UndoManager发送lastEdit()。die()调用?

答案 1 :(得分:1)

我只能假设你是如何进行文字着色的。如果您在StyledDocuments更改字符属性方法中执行此操作,则可以获取撤消侦听器并暂时从文档中取消注册该操作,然后一旦颜色更改已完成,则可以重新注册侦听器。

对于你想要做的事情应该没问题。

希望有所帮助

答案 2 :(得分:1)

在将isSignificant()方法返回false之前,您可以拦截CHANGE编辑并将每个编辑包装在另一个UndoableEdit中,然后再将其添加到UndoManager。然后每个撤消命令将撤消最近的INSERT或REMOVE编辑,以及自那时以来发生的每个CHANGE编辑。

最终,我认为你会发现JTextPane / StyledDocument / etc提供的样式机制。这种事情太有限了。它很慢,它使用太多内存,并且它基于用于跟踪文档词法结构的相同元素树。对于用户应用样式的应用程序(如文字处理器)而言,这是可以的(我猜),但对于必须在用户输入时不断更新样式的语法高亮显示器,这是可以的。

有几个基于Swing JTextComponentViewDocument类的自定义实现的语法高亮编辑器的示例。像JEdit这样的一些实际上重新实现了整个javax.swing.text包,但我认为你不需要走那么远。

答案 3 :(得分:0)

我刚刚遇到过这个问题。这是我的解决方案:

private class UndoManagerFix extends UndoManager {

    private static final long serialVersionUID = 5335352180435980549L;

    @Override
    public synchronized void undo() throws CannotUndoException {
        do {
            UndoableEdit edit = editToBeUndone();
            if (edit instanceof AbstractDocument.DefaultDocumentEvent) {
                AbstractDocument.DefaultDocumentEvent event = (AbstractDocument.DefaultDocumentEvent) edit;
                if (event.getType() == EventType.CHANGE) {
                    super.undo();
                    continue;
                }
            }
            break;
        } while (true);

        super.undo();
    }

    @Override
    public synchronized void redo() throws CannotRedoException {
        super.redo();
        int caretPosition = getCaretPosition();

        do {
            UndoableEdit edit = editToBeRedone();
            if (edit instanceof AbstractDocument.DefaultDocumentEvent) {
                AbstractDocument.DefaultDocumentEvent event = (AbstractDocument.DefaultDocumentEvent) edit;
                if (event.getType() == EventType.CHANGE) {
                    super.redo();
                    continue;
                }
            }
            break;
        } while (true);

        setCaretPosition(caretPosition);
    }

}

它是我自定义JTextPane中的内部类,所以我可以在重做时修复插入位置。