![]() |
Undo Redo: Bilder
Also ich hab ein Programm geschrieben, dass mit einem Canvas auf ein Bild schreibt.
Jetzt wollte ich bei jedem schreiben das Bild davor in einem dynamischen Array speichern. Sobald das Ende erreicht ist, soll der Button abgestellt werden. Leider komme ich da etwas durcheinander. Mein Code bisher:
Delphi-Quellcode:
Wenn das Fenster geschlossen wird:
//Auf das Bild schreiben
procedure TForm1.BT_WriteClick(Sender: TObject); var i,z,x,y: integer; begin SetLength(Bitmap2, High(Bitmap2) + 1); Bitmap2[High(Bitmap2)] := TPicture.Create; Bitmap2[High(Bitmap2)].Bitmap.Assign(Image1.Picture); inc(Bitmap2X); ... ... end; //Undo, Redo procedure TForm1.BT_UndoClick(Sender: TObject); begin if Bitmap2X > Low(Bitmap2) then begin Image1.Picture.Bitmap.Assign(Bitmap2[Bitmap2X-1]); Bitmap2X := Bitmap2X - 1; end else BT_Undo.Enabled := false; end; procedure TForm1.BT_RedoClick(Sender: TObject); begin if Bitmap2X < High(Bitmap2) then begin Image1.Picture.Bitmap.Assign(Bitmap2[Bitmap2X]); Bitmap2X := Bitmap2X + 1; end else BT_Redo.Enabled := false; end;
Delphi-Quellcode:
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var i: integer; begin for i := Low(Bitmap2) to High(Bitmap2) do Bitmap2[i].Free; end; |
AW: Undo Redo: Bilder
Hallo und Willkommen in der DP :dp:,
an Deiner Stelle würde ich nicht TPictures in einem Array, sondern gleich TBitmaps in einer TObjectList ablegen. Dazu noch ein privates Feld für den aktuellen Index innerhalb der Objektliste, dann kannst Du vorwärts oder rückwärts in der Liste navigieren. [edit] Zitat:
|
AW: Undo Redo: Bilder
Ich glaube, der Quellcode würde dann nur unnötig länger als zuvor. Oder?
PS: Kann sein... |
AW: Undo Redo: Bilder
Wohl eher verkürzen: Bitmap erzeugen und mit Add der Liste hinzufügen. Bei Programmende dann einfach die Liste freigeben, die kümmert sich per Default um die Freigabe der enthaltenen Objekte.
|
AW: Undo Redo: Bilder
Zitat:
Für eine saubere Undo/Redo-Implementierung brauchst du zwei Stacks: einen für die Undo- und einen für die Redo-Operation. Ich habe da mal vor ein paar Jahren etwas geschrieben, das du ja mal als Anregung anschauen kannst: ![]() |
AW: Undo Redo: Bilder
Okay ich wollte es jetzt mit TObjectList probieren, jedoch stoße ich schon auf ein Problem.
Dieser Begriff wäre undeklariert. Über eine Unit, die ich unter den uses benutzen muss hab ich nichts gefunden. Ps: Hab die Unit. Pss: Okay, habe jetzt eine Version mit ObjectList und das mit dem Array. Ich habe bei beiden immernoch die selben Probleme wie vorher. Ich weiß nicht wie ich im Index rumschieben soll. Kann mir das jemand bei meinenm Beispil oben zeigen? Ich komm da irgendwie immernoch durcheinander. |
AW: Undo Redo: Bilder
Ob nun ein Array mit vielen Objekten oder eine TList/TObjectList mit vielen Objekten, das macht grundsätlich keinen Unterschied.
Das ist ja nur die Art, wie die Objektzeiger verwaltet werden, aber auf den Inhalt der Objekte hat es keinerlei Einfluß. Die TObjectList nimmt dir aber etwas Arbeit ab, da sie selbst die Speicherverwaltung übernimmt und auch gleich die enthaltenen Objekte aufräumen/freigeben kann, wenn man einen Eintrag löscht. Über eine generische Objektliste (in neueren Delphis, ab D2009) würde man noch die ganzen Typecasts einsparen und somit typsicherer Arbeiten. PS: Wenn du vom TPicture eh nur die Bitmaps nutzt, dann kannst du auch gleich ein TBitmap verwenden. Ich hab's mal so grob versucht zusammenzutippen. (der Code rein theoretisch, direkt hier hingeschrieben und demnach ungetestet)
Delphi-Quellcode:
Und alle Zeichenoperationen natürlich nur auf Image1.Picture.Bitmap .
//Init
UndoList := TObjectList.Create(True); UndoIndex := 0; BT_Undo.Enabled := False; BT_Redo.Enabled := False; //Free UndoList.Free; //Save BT_Undo.Enabled := True; BT_Redo.Enabled := False; while UndoList.Count > UndoIndex+1 do UndoList.Delete(UndoIndex + 1); B := TBitmap.Create; B.Assign(Image1.Picture.Bitmap); UndoList.Add(B); Inc(UndoIndex); //Clear UndoList.Clear; UndoIndex := 0; BT_Undo.Enabled := False; BT_Redo.Enabled := False; //Undo if UndoIndex > 0 then begin Dec(UndoIndex); Image1.Picture.Bitmap.Assign(TBitmap(UndoList[UndoIndex])); BT_Redo.Enabled := True; BT_Undo.Enabled := UndoIndex > 0; end else BT_Undo.Enabled := False; //Redo if UndoIndex < UndoList.Count-1 then begin Inc(UndoIndex); Image1.Picture.Bitmap.Assign(TBitmap(UndoList[UndoIndex])); BT_Undo.Enabled := True; BT_Redo.Enabled := UndoIndex < UndoList.Count-1; end else BT_Redo.Enabled := False; |
AW: Undo Redo: Bilder
Zitat:
Ausserdem sollte man die ganze Undo/Redo-Logik in eine eigene Klasse (den "Undo/Redo-Manager") auslagern. Damit wären es dann 3 Objekte. Nur so bekommt man eine Lösung, die nicht Spaghetticode erinnert. |
AW: Undo Redo: Bilder
Je nach dem was Du für Manipulationen auf dem "Bild" ausführst, könnte es auch eine Option sein das Bild gar nicht zu verändern sondern es darzustellen und die vorgenommenen Schritte als Information zu verwalten und bei der Darstellung jeweils nacheinander auszuführen.
|
AW: Undo Redo: Bilder
Wenn ich mir himitsu's Quellcode anschaue dürfte das funktionieren, jedoch wird beim ersten mal das Bild vor dem ersten Undo nicht gespeichert...
PS:Hab's grade getestet. Wenn man zwischendurch was neues reinschreibt, wird ein Bild zu oft gespeichert... PSS: Hab im Forum etwas zu dem Thema gefunden, kann aber igendwie damit wenig anfangen: ![]() Das erste Problem hab ich mit einer If Abfrage gelöst. Könnte man das 2. Problem lösen, indem man alle darauffolgenden Beiträge löschen tut und das Momentane dann added? |
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:23 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz