【问题标题】:Hide certain actions from Swing's undo manager对 Swing 的撤消管理器隐藏某些操作
【发布时间】:2010-09-29 20:52:36
【问题描述】:

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

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

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

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

有什么想法吗?

【问题讨论】:

    标签: java swing undo


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

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

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

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

      【讨论】:

      • 扩展 DefaultStyledDocument 让我很头疼。当我对样式进行更改时,我可以通过禁用撤消管理器来处理撤消/重做颜色问题。但是存在明显的问题,因为当撤消/重做完成时,样式化的文档并没有真正得到 insertString 调用 - 它似乎直接对文档的模型做一些事情,当它在属性之间完成时可能会破坏模型。如果它可以在按下撤消/重做时调用 DefaultStyledDocument 上的这些方法,那就容易多了。
      【解决方案3】:

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

      应该适合你在那里尝试做的事情。

      希望对你有帮助

      【讨论】:

      • 不要这样做!!!尝试以这种方式执行此操作时遇到了一个非常糟糕的 java 内部异常。完整的 Swing 线程在我身上崩溃了,每次重绘都抛出了这个异常:线程“AWT-EventQueue-0”中的异常 java.lang.IllegalArgumentException: offset out of bounds at sun.util.locale.provider.RuleBasedBreakIterator.checkOffset(RuleBasedBreakIterator.java :759) ...
      【解决方案4】:

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

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

      【讨论】:

        猜你喜欢
        • 2015-03-04
        • 2023-03-23
        • 1970-01-01
        • 2016-09-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多