本贴转自http://www.drgraph.com/viewthread.php?tid=105&extra=page%3D1
1. 总体目标
Undo/Redo功能是一常用编辑功能,便于用户进行更多的尝试编辑工作。
图形组态功能中,针对Undo/Redo功能尚未进行系统设计。为提高软件易用性与通用性,应加入该项功能设计。
可参照微软Word模式,实现Undo/Redo下拉式选择效果。
2. 设计与实现
首先,针对每个图形文件均可进行65535级Undo/Redo操作。因此,Undo/Redo的各种模型数据在各图形文件实例中都应有独立实例。
2.1 框架实现
先考虑调用需求
用户可单步Undo/Redo,亦可多步,因此,设计调用接口
在实现时,先实现单步。
1) 添加编辑菜单项Undo/Redo,编辑多语言资源文件,中文为“撤销/重做”,英文为“Undo/Redo”
2) 添加工具条按钮,完成相应图标
3) 定义常量CBW_UNDO=-1, CBW_REDO=1;
4) Undo的Tag为CBW_UNDO,Redo的Tag为CBW_REDO
5) 单击事件处理
6) Undo/Redo函数先不处理
2.2 操作类设计
作为一个操作类,需记录操作的类型及其相关数据,以便进行撤销操作时有据可查。从直观需求而言,需记录以下信息
1) 操作所发起的窗口对象
2) 操作的类型
3) 被操作对象名称列表
4) 操作本身信息
而对外的接口主要是需自动记录用户的操作,响应用户的手动撤销/重做指令,即
自动记录用户的操作,即需创建相应的操作类实例,设计其构造函数为
操作的设计重点在于对于不同类型的操作,应记录哪些信息。
故此首先处理操作的类型,设计一个枚举类CbwExecuteType
用枚举类的好处在于扩充,以后有什么新的操作类型,可直接加入一个枚举量,然后对其进行相应处理即可。
首先来处理最先碰到的创建操作,该操作对应的枚举量为cetCreate。
第一件事,当然是自动记录创建操作,该操作的入口有以下几个:
1) 鼠标左键按下时:添加元件或放置图元
2) 鼠标左键弹起时:结束对象构造
3) 多点图元构造完毕
4) 粘贴操作
假定我们在以上入口处构造出创建操作类对象,即
还需将该对象加入到窗口的操作列表中去
这样,需在窗口类中设计一个数据成员,可设计为vector<TCbwExecuteItem *>类型,也可设计为TList类型,当然,从长远的角度考虑,可将TCbwExecuteItem类型设计为树形,这样,每一个操作均可包含多个子操作,并负责其各子操作的生命周期管理。
到目前,TCbwExecuteItem类的大致内容为
而在窗口类中,加入成员
而开始记录操作时,设计一个共用函数
同样,结束记录操作时,设计一个公用函数
在此基础上,可直接完成窗口的Undo/Redo操作函数,即将工作交由TCbwExecuteItem类完成
void __fastcall TCbwGraphBaseForm::Undo(int stepCount)
{
if(FExecuteIndex >= 0)
{
TCbwExecuteItem * item = FExecuteItem->ItemAt(FExecuteIndex);
if(item)
item->Undo();
}
--FExecuteIndex;
if(FExecuteIndex < 0)
{
FExecuteIndex = -1;
FFileModifiedFlag = false;
}
if(--stepCount)
Undo(stepCount);
}
void __fastcall TCbwGraphBaseForm::Redo(int stepCount)
{
TCbwExecuteItem * item = FExecuteItem->ItemAt(FExecuteIndex);
if(item)
{
++FExecuteIndex;
item->Redo();
}
if(--stepCount)
Redo(stepCount);
}
剩下的事就是TCbwExecuteItem的了,先还是啥也不做
针对各操作类型的核心设计工作,现在才开始。