自己动手设计代码编辑器——(三)撤销与重做
来源:互联网 发布:怎么在淘宝买假学生证 编辑:程序博客网 时间:2024/05/16 09:31
谈到代码编辑器,基本功能的“撤销与重做”是必不可少的。
刚好最近看了设计模式的“命令模式”,做这个倒是正好
简单来说,就是把所以可以撤销的方法封装成类
这里有个简单的测试例子,演示了用“命令模式”实现的“撤销”功能
这里是两个基本接口
// 命令接口,所有能被编辑器接受命令都从这里继承public interface ICommand{void Execute();}
// 可撤销的命令借口,所有可撤销的命令都从这里继承public interface IUndoCommand : ICommand{void Undo();}
接下来是具体的命令
// 插入一个字符到编辑器的命令public class InsertCharacterCommand : IUndoCommand{private CodeManager codeManager;private int index;private char ch;public InsertCharacterCommand(CodeManager setCodeManager, int setIndex, char setCh){this.codeManager = setCodeManager;this.index = setIndex;this.ch = setCh;}public void Execute(){codeManager.InserCharacter(index, ch);}public void Undo(){codeManager.RemoveCharacter(index);}}
这里用到了CodeManager,这个马上说,其他的就很简单了,实现了借口的两个函数Execute和Undo
而且这两个实际上函数都是调用的CodeManager的函数,所以挺简单了
// 管理文本的类,所有对文档的操作都在这里实现public class CodeManager{private Stack<IUndoCommand> undoCommands; // 保存执行后,可以撤销的命令private Stack<IUndoCommand> redoCommands; // 保存撤销后,可以重做的命令private StringBuilder text; // 保存代码的地方public string Text{get{return text.ToString();}}public CodeManager(){undoCommands = new Stack<IUndoCommand>();redoCommands = new Stack<IUndoCommand>();text = new StringBuilder();}// 执行命令,并且添加命令到堆栈中public void Execute(ICommand cmd){cmd.Execute();redoCommands.Clear(); // 当输入一个新的命令后,要清除可重做的命令。因为重做命令应该只是在撤销命令执行后,才能使用的。具体可以看看其它编辑器,然后自己试试if( cmd is IUndoCommand ){undoCommands.Push(cmd as IUndoCommand);}else{undoCommands.Clear();}}// 撤销public void Undo(){if ( undoCommands.Count == 0 ){MessageBox.Show("不能撤销了");return;}IUndoCommand cmd = undoCommands.Pop();cmd.Undo();redoCommands.Push(cmd);}// 重做public void Redo(){if ( redoCommands.Count == 0 ){MessageBox.Show("不能重做了");return;}IUndoCommand cmd = redoCommands.Pop();cmd.Execute();undoCommands.Push(cmd);}// 具体的对文本的操作函数public void InserCharacter(int index, char ch){text.Insert(index, ch);}public void RemoveCharacter(int index){text.Remove(index, 1);}public char GetCharacter(int index){return text[index];}}
这个类比较简单,代码都很容易看懂
// 编辑器public class Coder{public CodeManager codeManager;public Coder(){codeManager = new CodeManager();}// 插入字符函数,实例化具体的命令,并且让CodeManager去执行public void InsertCharacter(int index, char ch){InsertCharacterCommand cmd = new InsertCharacterCommand(codeManager, index, ch);codeManager.Execute(cmd);}public void AppendCharacter(char ch){InsertCharacter(codeManager.Text.Length, ch);}public void Undo(){codeManager.Undo();}public void Redo(){codeManager.Redo();}}
Coder类就是具体和用户打交道的类
Coder类也很简单,都是调用CodeManager的函数
到这里位置,撤销与重做功能就完成了
新建一个窗口,拖一个Label控件,在窗口中输入如下代码,可以看看效果
void MainFormKeyDown(object sender, KeyEventArgs e){switch ( e.KeyCode ){case Keys.D0:case Keys.D1:case Keys.D2:case Keys.D3:case Keys.D4:case Keys.D5:case Keys.D6:case Keys.D7:case Keys.D8:case Keys.D9:coder.AppendCharacter(e.KeyCode.ToString()[1]);break;case Keys.Z:coder.Undo();break;case Keys.Y:coder.Redo();break;default:break;}label1.Text = coder.codeManager.Text; // 这里显然不该这样,正确的做法是在Coder里实现一个函数,来间接的获取Text,但测试下就无所谓了}
这个函数里,用0-9的数字键来模拟输入字符,用Z键模拟“撤销”,用Y键模拟“重做”
好了,执行试试,输入,撤销,重做。
怎么样,很简单对吧(当然,这里的命令都是很简单的命令,如果涉及到命令组合,要难很多)
本来到这里就结束的,但可能有人会问,怎么实现其它功能。那这里我就在实现一个删除字符的命令,刚好就与输入命令相反
很简单,只要继承IUndoCommand命令就行
// 删除字符命令public class RemoveCharacterCommand : IUndoCommand{private CodeManager codeManager;private int index;private char ch;public RemoveCharacterCommand(CodeManager setCodeManager, int setIndex){this.codeManager = setCodeManager;this.index = setIndex;this.ch = ' ';}public void Execute(){this.ch = codeManager.GetCharacter(index);codeManager.RemoveCharacter(index);}public void Undo(){codeManager.InserCharacter(index, ch);}}
然后再Coder中加入函数
public void RemoveCharacter(int index){RemoveCharacterCommand cmd = new RemoveCharacterCommand(codeManager, index);codeManager.Execute(cmd);}public void SubtractCharacter(){RemoveCharacter(codeManager.Text.Length - 1);}
然后再switch(e.KeyCode)的分支中,加入一句
case Keys.Back:
coder.SubtractCharacter();
break;
就行了,试试效果吧
- 自己动手设计代码编辑器——(三)撤销与重做
- 自己动手设计代码编辑器——(二)导入源代码
- 自己动手设计代码编辑器——(五)分析源代码
- [Vim]撤销与重做
- 自己动手设计代码编辑器——(四)代码智能提示(自动完成功能)
- 自己动手设计代码编辑器——(一)源代代码分析
- 自己动手设计代码编辑器——(六)自己写XML管理类
- vi中的撤销与重做
- 双向同步时撤销重做设计思路
- c语言夜未眠2——实现撤销和重做
- 涂鸦撤销与重做的功能实现
- CDR X8撤销、重做与重复操作方法介绍
- [dhtmlxGantt(甘特图)开发手册]第四篇——撤销/重做、提示消息、加载任务
- 撤销重做(Undo/Redo)
- vim-撤销/重做/重复
- 撤销功能的实现——备忘录模式(三)
- 撤销功能的实现——备忘录模式(三)
- 撤销功能的实现——备忘录模式(三)
- 关于vecteor::erase(iterator++),导致崩溃的问题
- set命令
- Android去掉状态栏和标题栏的两种方式
- [winxp]远程桌面设置
- Cocos2d-x之 地图物体层CCTMXObjectGroup
- 自己动手设计代码编辑器——(三)撤销与重做
- 数据链路层
- Codeforces Round #190 (Div. 2)
- 今天的生活是对那些在曾经的日子里认真、努力的人的奖励, 是对漫不经心、懦弱、胆小的人的惩罚。
- Flex之AdvancedDataGrid用法
- Instant Contiki 安装笔记——SDCC和CC2530
- codeforces B. Ciel and Duel
- 字符串如何转数字
- c/c++ 算法之汉诺塔(河内之塔(Towers of Hanoi))