2016-09-07 9 views
2

私はTStackを使用して、私のプログラムで簡単なアンドゥ/リドゥ機能を実装しようとしています。この背後にある考えは、アクションが実行されると、プログラムの現在の状態が保存される、すなわちスタックにプッシュされるということである。ユーザーがアンドゥをクリックすると、プログラムの最後の状態がリロードされます。つまり、スタックからポップされます。Delphi - TStack容量混乱

この考え方の欠点は、スタックが永続的に成長することができないということです。容量値に達した後、新しいアイテムが上にプッシュされると、最も古いアイテム(スタックの一番下にあるもの)を削除する必要があります。

DelphiのTStackオブジェクトには、この「クリーンアップ」を自動的に実行すると想定されるCapacityプロパティが含まれていますが、スタックをオーバーロードすると(たとえば、capcity 10のアイテムを11アイテム押します) 。

このケースでは、TStackをより効果的に使用する方法についてアドバイスをいただけますか?私は、代替構造は配列構造を使用することを理解していますが、私はスタックを使うのが容易であることが好きです。

よろしく実際に

+0

おそらく、キューと、キューに最後に追加されたアイテムがあるインジケータを使用する方が簡単です。そうすれば、あなたにはやり直しオプションが与えられます。 –

+0

スタックは機能しません。それを放棄。それは間違ったデータ構造です。おそらく、デキュールを探しています。または、固定長の配列を使用して自分で作成してください。配列がいっぱいになると、循環索引を使用します。 –

+0

申し訳ありませんが、あなたが知っているように、 'Capacity'プロパティは自動的に増加しました。彼はすべての 'TOrderedList'派生コレクションオブジェクトで同じです。成長しないように強制する設定もありません。 'OnNotify'イベントを使って自分の限界に達したかどうかを確認し、もしそうなら、必要に応じて内容を変更することができます。 –

答えて

3

TStackは、ダイナミックアレイによって供給されます。
この事実を悪用して、スタックからアイテムを削除することができましたが、今はスタックと戦っていました。

私は循環型リストを使用することをお勧めします。

シンプルなデザインがこのように機能する場合があります。

type 
    TCircularList<T> = class(TObject); 
    private 
    FStorage: TList<T>; 
    FCapacity: cardinal; //duplication for performance reasons 
    FCurrentIndex: cardinal; 
    protected 
    function GetItem(index: cardinal): T; 
    procedure SetItem(index: cardinal; const Value: T); 
    public 
    constructor Create(Size: cardinal = 10); 
    destructor Destroy; override; 
    procedure Add(const Item: T); 
    property Items[index: cardinal]: T read GetItem write SetItem; default; 
    end; 

constructor TCircularList<T>.Create(Size: cardinal = 10); 
begin 
    inherited Create; 
    Assert(Size >= 2); 
    FStorage:= TList<T>.Create; 
    FCapacity:= Size; 
    FStorage.Capacity:= Size; 
end; 

destructor TCircularList<T>.Destroy; 
begin 
    FStorage.Free; 
    inherited; 
end; 

procedure TCircularList<T>.Add(const Item: T); 
begin 
    FCurrentIndex:= (FCurrentIndex + 1) mod FCapacity; 
    FStorage[FCurrentIndex]:= Item; 
end; 

function TCircularList<T>.GetItem(index: cardinal): T; 
var 
    cIndex: cardinal; 
begin 
    cIndex:= Index mod FCapacity; 
    Result:= FStorage[index]; 
end; 

procedure TCircularList<T>.SetItem(index: cardinal; const Value: T); 
var 
    cIndex: cardinal; 
begin 
    cIndex:= index mod FCapacity; 
    FStorage[index]:= Value; 
end; 

明らかに、あなたは最後のdeleteメソッドのようないくつかのより多くの方法が必要と思いますが、私はあなた次第、あなたはここから外挿することができるはずというのまま。

ユーザビリティは、私はUXの観点から、私はUNDO/REDO機能のアイデアは吸うと思うと言わざるを得ない
を発言します。
スナップショットのリストがないと、ディスクに多数のバックアップファイルを保存した場合と同じように、前後に進むことができます。
元に戻す機能を使用するには、最後のxステップを行ったことを正確に記憶しておく必要があります。
私はまた、制限がなければならない理由も理解していません。なぜなら、メモリ/ディスクスペースの許可と同じくらい元に戻す/スナップショットを許可しないのはなぜですか?