代码之家  ›  专栏  ›  技术社区  ›  Itay Maman

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

  •  5
  • Itay Maman  · 技术社区  · 16 年前

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

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

    (请注意,着色算法有点慢,所以我无法在插入文本时为其着色)。

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

    有什么想法吗?

    4 回复  |  直到 16 年前
        1
  •  1
  •   Alan Moore Chris Ballance    16 年前

    您可以拦截CHANGE编辑,并将每个编辑包裹在另一个UndoableEdit中 isSignificant() 方法返回 false ,然后将其添加到UndoManager。然后,每个“撤消”命令都将撤消最近的INSERT或REMOVE编辑,以及此后发生的每个CHANGE编辑。

    最终,我认为你会发现JTextPane/StyledDocument/等提供的样式机制对于这类事情来说太有限了。它很慢,占用了太多的内存,而且它基于用于跟踪文档词汇结构的相同元素树。(我想)对于用户应用样式的应用程序来说是可以的,比如文字处理器,但对于必须随着用户键入而不断更新样式的语法高亮显示程序来说则不然。

    有几个基于Swing自定义实现的语法突出显示编辑器的示例 JTextComponent , View Document 班级。有些,比如JEdit,实际上重新实现了整个 javax.swing.text 包裹,但我认为你不需要走那么远。

        2
  •  1
  •   Richard Campbell    16 年前

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

    在CHANGE排队后,您不能立即向UndoManager发送lastEdit().die()调用吗?

        3
  •  1
  •   Stephen Stephen    16 年前

    我只能假设你是如何进行文本着色的。如果你是在StyledDocuments change character属性方法中进行的,你可以获取撤销监听器,并将其从文档中临时注销以进行该操作,然后一旦颜色更改完成,你就可以重新注册监听器。

    对于你想在那里做的事情应该没问题。

    希望能有所帮助

        4
  •  0
  •   Vitor    11 年前

    我刚刚经历了这个问题。以下是我的解决方案:

    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中的一个内部类,因此我可以在重做时修复插入符号的位置。

    推荐文章