Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Undo Redo: Bilder (https://www.delphipraxis.net/168172-undo-redo-bilder.html)

R56 8. Mai 2012 18:27

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:
//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;
Wenn das Fenster geschlossen wird:
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;

DeddyH 8. Mai 2012 18:31

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:

Delphi-Quellcode:
SetLength(Bitmap2, High(Bitmap2) + 1);

Kann es sein, dass Du High mit Length verwechselt hast? [/edit]

R56 8. Mai 2012 18:37

AW: Undo Redo: Bilder
 
Ich glaube, der Quellcode würde dann nur unnötig länger als zuvor. Oder?

PS: Kann sein...

DeddyH 8. Mai 2012 18:38

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.

Uwe Raabe 8. Mai 2012 18:39

AW: Undo Redo: Bilder
 
Zitat:

Zitat von R56 (Beitrag 1165433)
Delphi-Quellcode:
//Auf das Bild schreiben
procedure TForm1.BT_WriteClick(Sender: TObject);
var i,z,x,y: integer;
begin
  SetLength(Bitmap2, Length(Bitmap2) + 1); // hier muss es Length heißen!
  Bitmap2[High(Bitmap2)] := TPicture.Create;
  Bitmap2[High(Bitmap2)].Bitmap.Assign(Image1.Picture);
  inc(Bitmap2X);
...
...
end;

An dieser Stelle hängst du zwar das neue Bild an das Ende des Arrays dran, aber wer sagt dir denn, daß Bitmap2X auch wirklich am Ende des Arrays steht?

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: UndoManager

R56 8. Mai 2012 21:50

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.

himitsu 9. Mai 2012 02:56

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:
//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;
Und alle Zeichenoperationen natürlich nur auf Image1.Picture.Bitmap .

sx2008 9. Mai 2012 03:24

AW: Undo Redo: Bilder
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1165437)
Für eine saubere Undo/Redo-Implementierung brauchst du zwei Stacks: einen für die Undo- und einen für die Redo-Operation.

Das sehe ich auch so.
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.

Bummi 9. Mai 2012 05:53

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.

R56 9. Mai 2012 08:54

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:
http://www.delphipraxis.net/48543-undo-redo-klasse.html

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