去下载MiniHex的源代码看看,下面是我从里面抄的:)
{**********************************************************}
{                                                          }
{  功能:管理 Undo 和 Redo.                                }
{  说明:采用循环队列记录Undo动作和Redo动作,              }
{        Undo和Redo是两个不同的队列。                      }
{                                                          }
{**********************************************************}unit ActsMgr;interfaceuses
  Windows, Messages, SysUtils, Classes,
  Controls, Forms, Dialogs;type
  TActType = (              //动作类型
              atNone,
              atModify,
              atInsert,
              atDelete
              );  PAct = ^TAct;
  TAct = record             //动作记录
    Enabled: Boolean;       //该动作是否能用
    ActType: TActType;      //动作类型
    Buf: string;            //缓冲区
    Offset: Integer;        //偏移
    Count: Integer;         //字节数
    CurPos: Integer;        //光标位置
    Prev: PAct;             //Prev指针
    Next: PAct;             //Next指针
  end;  TActs = array of TAct;  TActsMgr = class
  private
    FUndoActs: TActs;       //Undo队列
    FUndoHead: PAct;        //队列头指针
    FUndoTail: PAct;        //队列尾指针    FRedoActs: TActs;       //Redo队列
    FRedoHead: PAct;        //队列头指针
    FRedoTail: PAct;        //队列尾指针    FMaxUndo: Integer;      //最大Undo次数    procedure SetMaxUndo(Value: Integer);
    procedure InitAct(var Act: TAct);  public
    constructor Create(AMaxUndo: Integer);
    destructor Destroy; override;    property MaxUndo: Integer read FMaxUndo write SetMaxUndo;    function AddUndoItem: PAct;
    function AddRedoItem: PAct;
    function Undo: PAct;
    function Redo: PAct;    function CanUndo: Boolean;
    function CanRedo: Boolean;  end;implementationconstructor TActsMgr.Create(AMaxUndo: Integer);
begin
  SetMaxUndo(AMaxUndo);
end;destructor TActsMgr.Destroy;
begin
  SetLength(FUndoActs, 0);
  SetLength(FRedoActs, 0);
end;procedure TActsMgr.SetMaxUndo(Value: Integer);
var
  i: Integer;
begin
  FMaxUndo := Value;
  SetLength(FUndoActs, FMaxUndo + 1);
  for i := 0 to FMaxUndo do
  begin
    if i = FMaxUndo then
      FUndoActs[i].Next := @FUndoActs[0]
    else
      FUndoActs[i].Next := @FUndoActs[i+1];
    if i = 0 then
      FUndoActs[i].Prev := @FUndoActs[FMaxUndo]
    else
      FUndoActs[i].Prev := @FUndoActs[i-1];
    FUndoActs[i].Enabled := False;
  end;
  FUndoHead := @FUndoActs[0];
  FUndoTail := @FUndoActs[0];  SetLength(FRedoActs, FMaxUndo + 1);
  for i := 0 to FMaxUndo do
  begin
    if i = FMaxUndo then
      FRedoActs[i].Next := @FRedoActs[0]
    else
      FRedoActs[i].Next := @FRedoActs[i+1];
    if i = 0 then
      FRedoActs[i].Prev := @FRedoActs[FMaxUndo]
    else
      FRedoActs[i].Prev := @FRedoActs[i-1];
    FRedoActs[i].Enabled := False;
  end;
  FRedoHead := @FRedoActs[0];
  FRedoTail := @FRedoActs[0];
end;procedure TActsMgr.InitAct(var Act: TAct);
begin
  with Act do
  begin
    Enabled := True;
    Buf := '';
    Offset := 0;
    Count := 0;
    CurPos := 0;
  end;
end;function TActsMgr.AddUndoItem: PAct;
begin
  InitAct(FUndoHead^);
  Result := FUndoHead;  if FUndoHead^.Next = FUndoTail then
    FUndoTail := FUndoTail^.Next;
  FUndoHead := FUndoHead^.Next;
  FUndoHead^.Enabled := False;
end;function TActsMgr.AddRedoItem: PAct;
begin
  InitAct(FRedoHead^);
  Result := FRedoHead;  if FRedoHead^.Next = FRedoTail then
    FRedoTail := FRedoTail^.Next;
  FRedoHead := FRedoHead^.Next;
  FRedoHead^.Enabled := False;
end;function TActsMgr.Undo: PAct;
begin
  if not CanUndo then
  begin
    Result := nil;
    Exit;
  end;
  FUndoHead := FUndoHead^.Prev;
  FRedoHead := FRedoHead^.Prev;
  Result := FUndoHead;
end;function TActsMgr.Redo: PAct;
begin
  if not CanRedo then
  begin
    Result := nil;
    Exit;
  end;
  Result := FRedoHead;
  FRedoHead := FRedoHead^.Next;
  FUndoHead := FUndoHead^.Next;
end;function TActsMgr.CanUndo: Boolean;
begin
  Result := (FUndoHead <> FUndoTail);
end;function TActsMgr.CanRedo: Boolean;
begin
  Result := FRedoHead^.Enabled;
end;end.