在一个具体项目中想实现UNDO/REDO的功能, 操作的次数没有限制, 而且数据的类型比较复杂. 如有这方面有经验的高手, 可否谈谈你是如何实现的.
评论
-
# re: 有没有在具体项目中作过UNDO/REDO的高手, 给提点建议.
Posted @ 2005-09-23 10:21
这是个很好的话题,相信很多人都考虑过,而且想过各种复杂的做法。
实际上有个最简单的解决办法。有几点要先注意到的:
1、每个基本操作都是可以分解为添加/删除动作的。
2、每个UNDO/REDO动作是由一组基本的添加/删除动作组成的,这个基本的动作本身也是一个UNDO/REDO动作。
3、如果一个基本的UNDO动作做的工作是添加,对应的REDO动作就是删除。
4、UNDO/REDO动作必须以一个顺序来执行。
5、当前位置处于UNDO历史中时,一个DO动作要删除当前位置后面的所有UNDO动作。
比如在文字编辑器中,输入一段话,构成一个“添加字符串”动作。删除一段话,构成一个“删除字符串”动作。它们在动作历史中,只需要保存发生这个动作时的一些基本环境信息。
另一些复杂的动作,比如选择一段文字,拖到另一个位置,可以分解为一个删除+一个添加动作,并把这2个动作组成一个给用户使用的UNDO/REDO动作。当用户UNDO时,执行后一个添加动作的反动作即删除动作,接着执行前一个删除动作的反动作即添加动作。
设计UNDO/REDO功能,实际上就是把那些高级功能拆为最基本的添加/删除动作。
以上是个人看法。可以找一些开源的编辑器程序来看它们的源码,实际上UNDO/REDO功能大部分时候都是用在编辑器中。。。 回复 更多评论
-
# re: 有没有在具体项目中作过UNDO/REDO的高手, 给提点建议.
Posted @ 2005-09-23 11:07
谢谢!
COMMAND模式似乎也是提供这样的解决方案. 我在以前也考虑过, 但这种方法也是有些不足:
1. 通常COMMAND模式已经应用到接近APPLICATION/GUI层, 在这个层面的DEVELOPER通常还是稍微差些,要求去理解底层的逻辑通常是不容易的.
2. 考虑到COMMAND众多, 在COMMAND中实现UNDO/REDO也是很麻烦的事.
还有一点是, 个人认为UNDO/REDO应该是一种架构层面的问题, 应该从架构角度找到解决问题的方法. 这样一来, 至少在另一个项目中可以复用. 如依赖COMMAND, 没办法做到这一点. 回复 更多评论
-
# re: 有没有在具体项目中作过UNDO/REDO的高手, 给提点建议.
Posted @ 2005-09-23 11:40
那些东西应该全部封装在底层,而且你不该把这么底层的部分暴露给GUI开发人员。
比如你提供了几个底层的函数:addChar(ch), addString(text), insertString(pos, text),moveCursor(pos)它的实现中都向Undo History中插入Action。
GUI开发人员可能要定义一个功能functionA,这个功能中要调用这几个函数,并组成一个Undo动作。他们根本不需要知道你底层如何动作的,只需要简单做这个过程:
document->BeginAction ("插入日期和开发人员名字");
document->addChar(...);
docuemnt->insertString(...);
document->...;
document->EndAction();
注意中间有一项失败时,应该调用回滚。
EndAction()激发一个事件,通知GUI在UNDO列表中加入一项“插入日期和开发人员名字”。
这不是我的方案,实际上我至少看到过3个编辑器源码这么干,好像成了一个定式了。。。呵呵 回复 更多评论
-
# re: 有没有在具体项目中作过UNDO/REDO的高手, 给提点建议.
Posted @ 2005-09-23 12:16
谢谢, 很清楚! 我考虑试试看! 回复 更多评论
-
# re: 有没有在具体项目中作过UNDO/REDO的高手, 给提点建议.
Posted @ 2006-04-21 10:54
我是采用C++实现的,在我得博客里面有比较详细的介绍,可以参考。
我得博客:http://blog.csdn.net/pandaxcl/ 回复 更多评论