zoukankan      html  css  js  c++  java
  • 文字录入无限制Undo,Redo的实现

    这里只针对Edit的内容做一个简单的undo,redo功能;

    原理就是,将新增字符和相关信息添加到undo列表,在undo动作时,取记录信息,并在edit中删除新增的字符,然后将此动作添加到redo列表,以便恢复。

    本程序只对文本框文字的顺序增加做了处理,对于任意位置的删除,复制粘贴等没有进行处理,大家可以根据实际情况完善,增加辅助信息来完成对撤销和恢复的操作。

    明白了原理,对于其他的操作都是这个道理,比如你画图什么的,保留每个图形的相关信息,然后撤销恢复重画,说的简单,做起来还是需要我们动脑子的^_^

    为方便查看,将所有代码写到了一个单元。

    Delphi代码

    [delphi] view plaincopy
     
    1. unit Unit1;  
    2. interface  
    3. uses  
    4.   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,  
    5.   Dialogs, StdCtrls;  
    6. type  
    7.   TUndoInfo = record  
    8.     sText : String;    //每次增加的新字符串,不是整个edit的字符串  
    9.     iLastLen : Integer;//上一次edit内容的长度  
    10.   end;  
    11.   PUndoInfo = ^TUndoInfo;  
    12.   TForm1 = class(TForm)  
    13.     Edit1: TEdit;  
    14.     btn_undo: TButton;  
    15.     btn_redo: TButton;  
    16.     procedure FormCreate(Sender: TObject);  
    17.     procedure Edit1Change(Sender: TObject);  
    18.     procedure btn_undoClick(Sender: TObject);  
    19.     procedure btn_redoClick(Sender: TObject);  
    20.   private  
    21.     { Private declarations }  
    22.     FUnDoList : TList;      //undo列表  
    23.     FReDoList : TList;      //redo列表  
    24.     //添加到undo列表,s:新字符串,lastlen:上一次整个长度  
    25.     procedure AddUnDoAction(s:String;lastlen:Integer);  
    26.     //添加到redo列表  
    27.     procedure AddReDoAction(p:PUndoInfo);  
    28.   public  
    29.     { Public declarations }  
    30.   end;  
    31. var  
    32.   Form1: TForm1;  
    33. implementation  
    34. {$R *.dfm}  
    35. { TForm1 }  
    36. procedure TForm1.AddUnDoAction(s: String;lastlen:Integer);  
    37. var  
    38.   p:PUndoInfo;  
    39. begin  
    40.   New(p);  
    41.   p.sText := s;  
    42.   p.iLastLen := lastlen + Length(s);  
    43.   FUnDoList.Add(p);  
    44. end;  
    45. procedure TForm1.FormCreate(Sender: TObject);  
    46. begin  
    47.   FUnDoList := TList.Create;  
    48.   FReDoList := TList.Create;  
    49.   //添加初始值  
    50.   AddUnDoAction(Edit1.Text,0);  
    51. end;  
    52. 这里只简单的在OnChange事件中来添加 undo内容,实际应用中比这要复杂的多,这里只在 
    53. 这里说明一下简单应用 
    54. }  
    55. procedure TForm1.Edit1Change(Sender: TObject);  
    56. var  
    57.   lastlen:Integer;  
    58.   s:String;  
    59. begin  
    60.   //先取得上一次的最后长度  
    61.   lastlen := PUndoInfo(FUnDoList.Items[FUnDoList.Count - 1]).iLastLen;  
    62.   //本次新录入的字符串  
    63.   s := Copy(Edit1.Text,lastlen+1,Length(Edit1.Text)-lastlen);  
    64.   //添加到undo列表  
    65.   AddUnDoAction(s,lastlen);  
    66. end;  
    67. procedure TForm1.btn_undoClick(Sender: TObject);  
    68. var  
    69.   s,ts:string;  
    70.   lastlen:Integer;  
    71. begin  
    72.   //先取消OnChange事件,否则当修改edit的内容时,会重复触发OnChange事件,导致错误  
    73.   Edit1.OnChange := nil;  
    74.   //因为最后一个是原始值,所以这里判断是否大于1  
    75.   if FUnDoList.Count > then  
    76.   begin  
    77.     s := Edit1.Text;  
    78.     //取上次的值  
    79.     ts := PUndoInfo(FUnDoList.Items[FUnDoList.Count - 1]).sText;  
    80.     lastlen := PUndoInfo(FUnDoList.Items[FUnDoList.Count - 1]).iLastLen;  
    81.     //重新赋给edit内容  
    82.     Delete(s,lastlen,Length(ts));  
    83.     Edit1.Text := s;  
    84.     //添加到redo  
    85.     AddReDoAction(FUnDoList.Items[FUnDoList.Count - 1]);  
    86.     //将该项移出undo列表  
    87.     FUnDoList.Delete(FUnDoList.Count - 1);  
    88.   end;  
    89.   //回复OnChange事件  
    90.   Edit1.OnChange := Self.Edit1Change;  
    91. end;  
    92. procedure TForm1.AddReDoAction(p:PUndoInfo);  
    93. begin  
    94.   FReDoList.Add(p);  
    95. end;  
    96. //重复动作,原理同撤销动作  
    97. procedure TForm1.btn_redoClick(Sender: TObject);  
    98. var  
    99.   s,ts:string;  
    100.   lastlen:Integer;  
    101. begin  
    102.   Edit1.OnChange := nil;  
    103.   if FReDoList.Count > then  
    104.   begin  
    105.     ts := PUndoInfo(FReDoList.Items[FReDoList.Count - 1]).sText;  
    106.     lastlen := PUndoInfo(FReDoList.Items[FReDoList.Count - 1]).iLastLen;  
    107.     Edit1.Text := Edit1.Text + ts;  
    108.     FUnDoList.Add(PUndoInfo(FReDoList.Items[FReDoList.Count - 1]));  
    109.     FReDoList.Delete(FReDoList.Count - 1);  
    110.   end;  
    111.   Edit1.OnChange := Self.Edit1Change;  
    112. end;  
    113. end.  

    C#代码

    [c-sharp] view plaincopy
     
    1. using System;  
    2. using System.Collections.Generic;  
    3. using System.ComponentModel;  
    4. using System.Data;  
    5. using System.Drawing;  
    6. using System.Text;  
    7. using System.Windows.Forms;  
    8. namespace Test_CSharp_Win  
    9. {  
    10.     public partial class Form2 : Form  
    11.     {  
    12.         List<UnDoInfo> undoList;  
    13.         List<UnDoInfo> redoList;  
    14.         public Form2()  
    15.         {  
    16.             InitializeComponent();  
    17.             undoList = new List<UnDoInfo>();  
    18.             redoList = new List<UnDoInfo>();  
    19.             //添加初始值  
    20.             AddUnDoAction(textBox1.Text, 0);  
    21.         }  
    22.         /// <summary>  
    23.         /// //添加到undo列表  
    24.         /// </summary>  
    25.         /// <param name="s">新字符串</param>  
    26.         /// <param name="lastlen">上一次整个长度</param>  
    27.         private void AddUnDoAction(string s, int lastlen)  
    28.         {  
    29.             UnDoInfo info = new UnDoInfo();  
    30.             info.sText = s;  
    31.             info.iLastLen = lastlen + s.Length;  
    32.             undoList.Add(info);  
    33.         }  
    34.         /// <summary>  
    35.         /// 添加到redo列表  
    36.         /// </summary>  
    37.         /// <param name="info"></param>  
    38.         private void AddReDoAction(UnDoInfo info)  
    39.         {  
    40.             redoList.Add(info);  
    41.         }  
    42.         private void textBox1_TextChanged(object sender, EventArgs e)  
    43.         {  
    44.             string s = string.Empty;  
    45.             int lastlen = 0;  
    46.             //先取得上一次的最后长度  
    47.             lastlen = undoList[undoList.Count - 1].iLastLen;  
    48.             //本次新录入的字符串  
    49.             s = textBox1.Text.Substring(lastlen, textBox1.Text.Length - lastlen);  
    50.             //添加到undo列表  
    51.             AddUnDoAction(s, lastlen);  
    52.         }  
    53.         private void btn_undo_Click(object sender, EventArgs e)  
    54.         {  
    55.             string s = string.Empty;  
    56.             string ts = string.Empty;  
    57.             int lastlen = 0;  
    58.             //先取消TextChanged事件,否则当修改edit的内容时,会重复触发TextChanged事件,导致错误  
    59.             textBox1.TextChanged -= this.textBox1_TextChanged;  
    60.             //因为最后一个是原始值,所以这里判断是否大于1  
    61.             if (undoList.Count > 1)  
    62.             {  
    63.                 s = textBox1.Text;  
    64.                 ts = undoList[undoList.Count - 1].sText;  
    65.                 lastlen = undoList[undoList.Count - 1].iLastLen;  
    66.                 s = s.Remove(lastlen-1, ts.Length);  
    67.                 textBox1.Text = s;  
    68.                 //添加到redo  
    69.                 AddReDoAction(undoList[undoList.Count - 1]);  
    70.                 //将该项移出undo列表  
    71.                 undoList.RemoveAt(undoList.Count - 1);  
    72.             }  
    73.             //恢复TextChanged事件  
    74.             textBox1.TextChanged += this.textBox1_TextChanged;  
    75.         }  
    76.         /// <summary>  
    77.         /// 重复动作,原理同撤销动作  
    78.         /// </summary>  
    79.         /// <param name="sender"></param>  
    80.         /// <param name="e"></param>  
    81.         private void btn_redo_Click(object sender, EventArgs e)  
    82.         {  
    83.             string ts = string.Empty;  
    84.             int lastlen = 0;  
    85.             textBox1.TextChanged -= this.textBox1_TextChanged;  
    86.             if (redoList.Count > 0)  
    87.             {  
    88.                 ts = redoList[redoList.Count - 1].sText;  
    89.                 lastlen = redoList[redoList.Count - 1].iLastLen;  
    90.                 textBox1.Text = textBox1.Text + ts;  
    91.                 undoList.Add(redoList[redoList.Count - 1]);  
    92.                 redoList.RemoveAt(redoList.Count - 1);  
    93.             }  
    94.             textBox1.TextChanged += this.textBox1_TextChanged;  
    95.         }  
    96.     }  
    97.     struct UnDoInfo  
    98.     {  
    99.         //每次增加的新字符串,不是整个edit的字符串  
    100.         public string sText;  
    101.         //上一次edit内容的长度  
    102.         public int iLastLen;  
    103.     }  
    104. }  

    VC代码

    [cpp] view plaincopy
     
    1. 头文件{DataDefined.h}  
    2. struct UnDoInfo  
    3. {  
    4.     CString sText;  
    5.     int iLastLen;  
    6. };  
    7. CArray<UnDoInfo*,UnDoInfo*&> undoList;  
    8. CArray<UnDoInfo*,UnDoInfo*&> redoList;  
    9. void AddUnDoAction(CString s,int lastlen);  
    10. void AddReDoAction(UnDoInfo* info);  
    11. 主cpp文件,其中要为CEdit指定内容变化响应事件{ON_EN_CHANGE(IDC_EDIT1, &CTest_c_MFCDlg::OnEnChangeEdit1)}  
    12. #include "DataDefined.h"  
    13. BOOL CTest_c_MFCDlg::OnInitDialog()  
    14. {  
    15.     CDialog::OnInitDialog();  
    16.     //这里省略自动生成代码  
    17.     // TODO: 这里添加初始的信息  
    18.     CEdit* edit = (CEdit*)GetDlgItem(IDC_EDIT1);  
    19.     CString s;  
    20.     edit->GetWindowTextW(s);  
    21.     AddUnDoAction(s,0);  
    22.     return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE  
    23. }  
    24. bool canchange = true; //这个控制是否触发CEdit的内容变化事件  
    25. //添加到undo列表,s:新字符串,lastlen:上一次整个长度  
    26. void AddUnDoAction(CString s,int lastlen)  
    27. {  
    28.     UnDoInfo* info = new UnDoInfo;  
    29.     info->iLastLen = lastlen + s.GetLength();  
    30.     info->sText = s;  
    31.     undoList.Add(info);  
    32. }  
    33. //添加到redo列表  
    34. void AddReDoAction(UnDoInfo* info)  
    35. {  
    36.     redoList.Add(info);  
    37. }  
    38. //undo按钮点击事件  
    39. void CTest_c_MFCDlg::OnBnClickedundo()  
    40. {  
    41.     // TODO: 在此添加控件通知处理程序代码  
    42.     canchange = false;  
    43.     CString s,ts;  
    44.     int lastlen;  
    45.     CEdit* edit = (CEdit*)GetDlgItem(IDC_EDIT1);  
    46.     if (undoList.GetCount() > 1)  
    47.     {  
    48.         edit->GetWindowTextW(s);  
    49.         ts = undoList.GetAt(undoList.GetCount()-1)->sText;  
    50.         lastlen = undoList.GetAt(undoList.GetCount() - 1)->iLastLen;  
    51.         if (lastlen > 0)  
    52.             s.Delete(lastlen-1,ts.GetLength());  
    53.         else  
    54.             s = "";  
    55.         edit->SetWindowTextW(s);  
    56.         AddReDoAction(undoList.GetAt(undoList.GetCount() - 1));  
    57.         undoList.RemoveAt(undoList.GetCount() - 1);  
    58.     }  
    59.     canchange = true;  
    60. }  
    61. //redo按钮点击事件  
    62. void CTest_c_MFCDlg::OnBnClickedredo()  
    63. {  
    64.     // TODO: 在此添加控件通知处理程序代码  
    65.     canchange = false;  
    66.     CString s,ts;  
    67.     int lastlen;  
    68.     CEdit* edit = (CEdit*)GetDlgItem(IDC_EDIT1);  
    69.     if (redoList.GetCount() > 0)  
    70.     {  
    71.         edit->GetWindowTextW(s);  
    72.         ts = redoList.GetAt(redoList.GetCount() - 1)->sText;  
    73.         lastlen = redoList.GetAt(redoList.GetCount() - 1)->iLastLen;  
    74.         edit->SetWindowTextW(s + ts);  
    75.         undoList.Add(redoList.GetAt(redoList.GetCount() - 1));  
    76.         redoList.RemoveAt(redoList.GetCount() - 1);  
    77.     }  
    78.     canchange = true;  
    79. }  
    80. //CEdit的change处理代码  
    81. void CTest_c_MFCDlg::OnEnChangeEdit1()  
    82. {  
    83.     // TODO:  如果该控件是 RICHEDIT 控件,则它将不会  
    84.     // 发送该通知,除非重写 CDialog::OnInitDialog()  
    85.     // 函数并调用 CRichEditCtrl().SetEventMask(),  
    86.     // 同时将 ENM_CHANGE 标志“或”运算到掩码中。  
    87.     // TODO:  在此添加控件通知处理程序代码  
    88.     if (!canchange) return;  
    89.     CString s;  
    90.     int lastlen;  
    91.     lastlen = ((UnDoInfo*)undoList.GetAt(undoList.GetCount()-1))->iLastLen;  
    92.     CEdit* edit = (CEdit*)GetDlgItem(IDC_EDIT1);      
    93.     edit->GetWindowTextW(s);  
    94.     s = s.Mid(lastlen,s.GetLength()-lastlen);  
    95.     AddUnDoAction(s,lastlen);  
    96. }  

     参考:

    http://blog.csdn.net/bdmh/article/details/6426564

  • 相关阅读:
    mac 端口转发方案
    Js 函数
    for 循环语句 与 while 循环
    Javascript 基础2
    Javascript 基础 1
    设计模式学习(一)-概述
    java基础知识-对象和类
    java基础知识-(数组)
    Java面试-框架篇(SSM-SpringMVC)
    Java面试-框架篇(SSM-Mybatis)
  • 原文地址:https://www.cnblogs.com/findumars/p/3980113.html
Copyright © 2011-2022 走看看