我的项目的一部分是写文本编辑器,用于键入某些规则,我的应用程序编译并运行它。编写编译器结束并发布测试版。在最终版本中,我们必须在文本编辑器中添加撤消和重做。我使用文件并定期保存文本编辑器。如何设计撤消和重做到我的文本编辑器?文件持久性结构的变化是什么?
答案 0 :(得分:14)
您可以将操作建模为commands,并将其保存在两个堆栈中。一个用于撤销,另一个用于重做。您可以compose命令创建更多高级命令,例如,当您要撤消宏的操作时;或者如果你想在一个动作中对单个单词或短语的单个击键进行分组。
编辑器中的每个操作(或重做操作)都会生成一个新的撤消命令,该命令将进入撤消堆栈(并清除重做堆栈)。每个撤消操作都会生成相应的重做命令,该命令将进入重做堆栈。
如derekerdmann的评论所述,您还可以将undo和redo命令组合成一种命令,知道如何撤消和重做其操作。
答案 1 :(得分:8)
基本上有两种很好的方法可以解决这个问题:
“命令”设计模式
在不可变对象上只使用 OO,其中一切都是由不可变对象组成的不可变对象,这些对象由不可变对象组成(这种情况不太常见,但正确完成时非常优雅)
在天真命令或天真的撤销/重做上使用OO而不是永久对象的优点是你不需要太多考虑它:不需要“撤消”动作的效果而不需要“重播“所有命令。您只需要一个指向大量不可变对象的指针。
因为对象是不可变的,所以所有“状态”都可以非常轻量级,因为你可以在任何状态下缓存/重用大多数对象。
“OO over immutable objects”是一颗纯粹的宝石。可能不会在另外10年之前成为主流; )
P.S:在不可变对象上执行OO也令人惊讶地简化了并发编程。答案 2 :(得分:6)
如果您不想要任何想象,可以添加UndoManager。每次添加或删除文字时,Document
都会触发UndoableEdit
。要撤消和重做每个更改,只需在UndoManager中调用这些方法。
这方面的缺点是每次用户输入内容时UndoManager都会添加一个新的编辑,因此输入“apple”将为您提供5次编辑,一次可撤消。对于我的文本编辑器,我编写了一个包含编辑器的包装器,用于存储除文本更改和偏移之外的编辑时间,以及一个UndoableEditListener
,如果只有短暂的时间段,它会将新编辑连接到以前的编辑他们之间的时间(0.5秒适合我)。
这适用于一般编辑,但在进行大量替换时会导致问题。如果你有一个包含5000个“apple”实例的文档而你想用“orange”替换它,你最终会得到5000个编辑,所有编辑都存储“apple”,“orange”和一个偏移量。为了降低使用的内存量,我将此视为普通编辑的单独案例,而是存储“apple”,“orange”和5000个偏移的数组。我还没有应用这个,但我知道当多个字符串匹配搜索条件时会引起一些麻烦(例如,不区分大小写的搜索,正则表达式搜索)。
答案 3 :(得分:4)
您可以通过两种方式实现:
在我的(图表)编辑器中,有四个级别的状态更改:
答案 4 :(得分:4)
基本思想是将文本编辑器的全部内容保存在数组中,或者是最后一次编辑之间的差异。
在重要位置更新此数组,即每隔几个字符(检查每个按键的内容长度,如果超过20个字符,则设置保存点)。同样在样式的变化(如果是富文本),添加图像(如果它允许这样),粘贴文本等。您还需要一个指针(只是一个int变量)来指向数组中的哪个项目是当前状态的编辑器)
使数组具有设定长度。每次添加保存点时,将其添加到数组的开头,并将所有其他数据点向下移动一个。 (一旦你有这么多的保存点,数组中的最后一项将被遗忘)
当用户按下撤销按钮时,检查编辑器的当前内容是否与最新的保存相同(如果不是,则用户自上次保存点以来进行了更改,因此保存当前编辑器的内容(因此可以重做),使编辑器等于最后一个保存点,并使指针变量= 1(数组中的第二项)。如果它们相同,则不进行任何更改从上一个保存点开始,所以你需要撤消到之前的那个点。为此,增加指针值+ 1,并使编辑器的内容=指针的值。
要重做,只需将指针值减1并加载数组的内容(确保检查是否已到达数组的末尾)。
如果用户在撤消后进行编辑,则将指向的数值单元格移动到单元格0,然后将其余部分向上移动相同的数量(一旦他们进行了不同的编辑,您就不想重做其他内容)。
另一个主要问题 - 如果文本编辑器的内容实际发生了变化,请确保只添加一个保存点(否则你会得到重复的保存点,似乎撤消对用户没有任何作用。
我无法帮助您了解java细节,但我很乐意回答您的任何其他问题,
尼科
答案 5 :(得分:3)
这是the command pattern的工作。
答案 6 :(得分:3)
以下是一个片段,展示了SWT如何支持撤消/重做操作。以实际例子为例(如果您的编辑器基于SWT,则直接使用它):
答案 7 :(得分:2)
阅读一本书Design Patterns: Elements of Reusable Object-Oriented Software。据我记忆,有一个很好的例子。