如何防止撤消 Document.Replace 后光标移动

发布于 2024-10-28 20:53:08 字数 414 浏览 1 评论 0原文

如果您在 Java 中有一个文本组件并且执行替换,则光标将不会移动,如果您使用标准撤消管理器撤消和重做该替换,则光标将移动到该插入或删除的开头或结尾。

我该如何防止这种行为?

我能够使用 Java TextComponentDemo 触发此操作,我在其中添加了一个简单的替换操作来执行此操作:

doc.replace(doc.getText(0, doc.getLength()).indexOf("mouse"), 5, "cat", null);

如果我随后使用演示的撤消和重做,则光标将移动。

If you have a text component in Java and you do a replace the cursor will not move, if you undo and redo that replace using a standard undo manager the cursor will move to the beginning or end of that insertion or deletion.

How would I prevent this behavior?

I was able to trigger this with the Java TextComponentDemo, where I added a simple replace action that did this:

doc.replace(doc.getText(0, doc.getLength()).indexOf("mouse"), 5, "cat", null);

If I then use the demo's undo's and redo's the cursor will move.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

水波映月 2024-11-04 20:53:08

Java Swing 并不是唯一在标准撤消管理器中具有此行为的 API。有时,XUL(Firefox 和 Thunderbird 的基础)对 3rd 方扩展中的文本区域执行相同的操作。本质上,即使在这种情况下原始文本和替换文本相似,文本区域也必须将文档视为全新文档,就像您执行了全选操作一样>粘贴以覆盖旧文本。一般来说,将相同的光标位置恢复到新文档中是没有用的,如果文档较短,甚至可能不可能。

我认为解决这个问题最简单的方法是创建您自己的自定义操作来替换文本。聆听它们并执行操作,而不是执行默认操作。您的自定义操作应该是一个复合操作,它手动扫描文档,替换现有文档中的子字符串 - 通过执行多次文档更改来扫描并替换到最后。当您覆盖撤消方法时,只需浏览您所做的修改列表,以相反的顺序撤消每一项。只要复合动作中的每个动作正确设置文本和光标位置,并且其撤消方法正常工作,整个复合动作也将正确撤消。

本指南有望更清楚地解释这个概念。该示例在用户键入时将操作合并到组中。您只需要执行相同的操作,但要进行程序编辑。

Java Swing isn't the only API that has this behaviour in the standard undo manager. Sometimes XUL (which is the base for Firefox and Thunderbird) does the same thing with text areas in 3rd-party extensions. Essentially, even though the original text and the replacement text are similar in this case, the text area has to treat the document as an entirely new one, just like if you had done a select all and paste to overwrite the old text. In general, restoring the same cursor position to the new document would be useless, and if the document is shorter, it might not even be possible.

I think the easiest way around this would be to create your own custom actions for replacing text. Listen for them and perform the actions instead of performing the default action. Your custom action should be a compound action which scans the document manually, replacing substrings in the existing document - scan and replace all the way to the end by performing a number of document changes. When you override the undo method, just go through the list of modifications you made, undoing each one in reverse order. As long as each action in the compound action sets the text and the cursor position correctly, and its undo method works properly, the whole compound action will also undo properly.

This guide should hopefully explain this concept a little more clearly. The example merges actions into groups while the user types. You just need to do the same, but with procedural edits instead.

毁梦 2024-11-04 20:53:08

查看插入符号更新类 中的策略DefaultCaret

以下更新政策是
允许:

  • NEVER_UPDATE:插入符号保持在相同的绝对位置
    文件,无论任何文件
    更新,除非文档长度
    变得小于当前插入符号
    由于移除而导致的位置。在这种情况下
    插入符号位置调整到末尾
    该文件的。插入符号不尝试
    通过滚动保持自身可见
    使用此视图时的关联视图
    政策。
  • ALWAYS_UPDATE:插入符号始终跟踪文档更改。对于常规
    改变它会增加它的位置,如果
    插入发生在其之前或之时
    当前位置,并减少
    如果删除发生在之前的位置
    它当前的位置。用于撤消/重做
    更新它总是移动到
    发生更新的位置。这
    插入符号也试图保持自己
    通过调用 adjustmentVisibility 可见
    方法。
  • UPDATE_WHEN_ON_EDT:如果文档更新,则行为类似于 ALWAYS_UPDATE
    在事件调度上执行
    线程和 NEVER_UPDATE if
    更新在其他线程上执行。

您可以在撤消或重做操作之前将更新策略设置为 NEVER_UPDATE,然后将其设置回该操作之后的状态。

public void actionPerformed(ActionEvent e) {
    int updatePolicy = caret.getUpdatePolicy();
    caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE);
    undoManager.undo();
    caret.setUpdatePolicy(updatePolicy);
}

Check out the caret update policy in the class DefaultCaret.

The following update policies are
allowed:

  • NEVER_UPDATE: the caret stays at the same absolute position in the
    document regardless of any document
    updates, except when document length
    becomes less than the current caret
    position due to removal. In that case
    caret position is adjusted to the end
    of the document. The caret doesn't try
    to keep itself visible by scrolling
    the associated view when using this
    policy.
  • ALWAYS_UPDATE: the caret always tracks document changes. For regular
    changes it increases its position if
    an insertion occurs before or at its
    current position, and decreases
    position if a removal occurs before
    its current position. For undo/redo
    updates it is always moved to the
    position where update occurred. The
    caret also tries to keep itself
    visible by calling adjustVisibility
    method.
  • UPDATE_WHEN_ON_EDT: acts like ALWAYS_UPDATE if the document updates
    are performed on the Event Dispatching
    Thread and like NEVER_UPDATE if
    updates are performed on other thread.

You can set the update policy to NEVER_UPDATE before an undo or redo action, then set it back to what it was after the action.

public void actionPerformed(ActionEvent e) {
    int updatePolicy = caret.getUpdatePolicy();
    caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE);
    undoManager.undo();
    caret.setUpdatePolicy(updatePolicy);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文