Delphi-PRAXiS
Seite 2 von 3     12 3      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   TImages verwalten (https://www.delphipraxis.net/182231-timages-verwalten.html)

himitsu 14. Okt 2014 20:54

AW: TImages verwalten
 
Zitat:

Zitat von Sir Rufo (Beitrag 1275928)
Die Form-Instanz wird eben nicht freigegeben, ausser es kommt innerhalb der Methode zu einer Exception, dann wird abgebrochen,
Delphi-Quellcode:
LFoo := TFoo.Create;
try
  ...
  Result := Lfoo;
  LFoo := nil; // auf nil setzen
finally
  // bei einer Exception wird die Instanz freigegeben,
  // sonst nicht, denn dann zeigt LFoo ja auf nil ;o)
  LFoo.Free;
end;

Warum schreibt man den Code dann nicht so, wie das, was er machen soll und sparrt dabei auch gleich noch die leicht verwirrende doppelte Variable?
Delphi-Quellcode:
Result := TFoo.Create;
try
  ...
except
  Result.Free;
  raise;
end;

Sir Rufo 14. Okt 2014 21:53

AW: TImages verwalten
 
Ich habe das doch so geschrieben, wie das was er machen soll. Und
Delphi-Quellcode:
try finally
ist ein Ressourcen-Schutzblock - wenn ich mich da richtig erinnere - und genau den will ich haben und darum schreibe ich ihn so.

himitsu 15. Okt 2014 09:14

AW: TImages verwalten
 
Zitat:

Zitat von Sir Rufo (Beitrag 1275940)
das was er machen soll.

Also bei einem Fehler eine Aktion ausführen? :mrgreen:

OK, es funktioniert Beides, aber IMHO ist es mit'm Finally etwas schneller missverständlicher.

Delphi-Quellcode:
LFoo := TFoo.Create;
try
  ...
  LFoo := nil; // Womöglich auch noch tief in irgendwelchen IFs versteckt auf nil setzen.
  ...
finally
  LFoo.Free; // IMMER freigeben, außer irgendwo anders wurde vorher die Variable heimlich auf nil gesetzt.
end;
Delphi-Quellcode:
Result := TFoo.Create;
try
  ...
except
  Result.Free; // NUR freigeben, wenn es geknallt hat.
  raise;
end;
Ich weiß, im Falle von Free muß nicht geprüft werden, da es das selber macht, aber irgenwie sollte man hier schon, beim Free, einen Hinweis geben ... sei es in Form eines Codes oder als Kommentar, daß sich oben irgendwo noch ein :=nil versteckt.
Delphi-Quellcode:
LFoo := TFoo.Create;
try
  ...
  LFoo := nil;
  ...
finally
  if Assigned(LFoo) then
    LFoo.Free;
end;

Sir Rufo 15. Okt 2014 10:33

AW: TImages verwalten
 
Das werde ich definitiv nicht machen, denn ich schreibe keine Kommentare, die sich auf Basis-Funktionalitäten (
Delphi-Quellcode:
TObject.Free
prüft selber auf assigned) beziehen, noch füge ich unnützen Code hinzu
Delphi-Quellcode:
if (Assigned( LFoo ) then LFoo.Free;
). Ich schreibe keine Tutorials sondern Anwendungen und wer das verstehen möchte, der soll die Sprache beherrschen.

Wie man Instanzen aufräumt sollte eigentlich bekannt sein und gehört zum Basiswissen:
Delphi-Quellcode:
procedure Example;
var
  LFoo : TFoo;
  LBar : TBar;
begin
  LFoo := nil;
  LBar := nil;
  try
    LFoo := TFoo.Create;

    while LFoo.NeedsMore do
    begin
      LBar := TBar.Create;
      LFoo.InteractWith( LBar );
      FreeAndNil( LBar );
    end;

  finally
    LFoo.Free;
    LBar.Free;
  end;

himitsu 15. Okt 2014 12:14

AW: TImages verwalten
 
Dein
Delphi-Quellcode:
finally LFoo.Free; end;
wird immer ausgeführt, macht aber meistens (hoffentlich immer) nichts, was schon einen Kommentar wert wäre. :stupid:

Schwedenbitter 15. Okt 2014 12:42

AW: TImages verwalten
 
Danke für Eure erhellenden Antworten. Natürlich lerne ich gern dazu. Einen "Krieg" anzuzetteln, war das Letzte, was ich mit meiner Fragestellung wollte.
Zitat:

Zitat von Sir Rufo (Beitrag 1275981)
...
Wie man Instanzen aufräumt sollte eigentlich bekannt sein und gehört zum Basiswissen:
...

Vermutlich bezog sich das auf mich. Und damit muss ich zugeben, dass mir Basiswissen fehlt. In der Regel lasse ich über meinen "fertigen" Code FastMM drüber laufen und evtl. Speicherlecks anzeigen. Bislang habe ich noch immer aufräumen können. Ich bin mir auch nicht wirklich sicher, ob wir nicht vom Selben reden. Denn das übliche Konstrukt ist mir trotzdem bekannt:
Delphi-Quellcode:
Procedure Example;
Var
   SL         : TIrgendwas;
Begin
   SL:=TIrgendwas.Create;
   Try
      SL.TuEtwas;
   Finally
      SL.Free;
   End;
End;
Ich habe jetzt aber konkret das Problem, dass meine (Object)Liste und die tatsächlich in den TabSheets vorhandenen Forms auseinanderfallen können. Denn mir fehlt immer noch das Wissen und auch eine Idee, wie die angedockte Form den Umstand des Schließens und damit das Löschen aus dem Tabsheet an das Hauptprgramm/-form weiterleitet.
Die Änderung des TabSheets wird mir über
Delphi-Quellcode:
TPageControl.OnChange
mitgeteilt. Aber wie filtere ich jetzt das verschwundene Fenster aus meiner Liste? Eine Idee wäre natürlich einen Zugriff zu machen, damit dann künstlich eine Exception zu erzeugen und das betreffende Fenster zu löschen; so klappt es jedenfalls. Ich kann mir aber kaum vorstellen, dass das so legitim ist:
Delphi-Quellcode:
Procedure TMainForm.PCPicsChange(Sender: TObject);
Var
   I            : Integer;
   lDockForm   : TDockForm;
Begin
   I:=0;
   While (fPicList.Count > I) Do
   Begin
      lDockForm:=fPicList.Items[I];
      Try
         lDockForm.RBorgjpg.Checked;
         Inc(I);   // <- hat geklappt, ist also noch vorhanden
      Except
         fPicList.Delete(I);
      End;
   End;
End;
Daher eben nochmal meine Frage, wie man das macht richtig?

Gruß, Alex

Jumpy 15. Okt 2014 13:21

AW: TImages verwalten
 
Die ganzen DockFormen werden ja im Hauptformular/Programm kreiert.
Da könntest du denen doch eine Callback-Funktion mitgeben, die im OnClose des DockFormulars ausgelöst wird. Methodenzeiger ist hier glaub ich das Stichwort.

Sir Rufo 15. Okt 2014 14:22

AW: TImages verwalten
 
Richtiger wäre es den ganzen Kram zu trennen.

Es gibt eine Liste mit Datenobjekten
Delphi-Quellcode:
// ein Datenobjekt
TImageData = class
  property Filename : string;
end;
Für das DatenObjekt gibt es eine Form, die dieses DatenObjekt anzeigen kann
Delphi-Quellcode:
TImageView = class( TDockForm )
  property ImageData : TImageData;
end;
Die MainForm kann nun aus der Liste mit den DatenObjekten die passenden Forms erzeugen und natürlich auch wieder entfernen.
Delphi-Quellcode:
TMainForm = class( TForm )
  FDataList : TObjectList;
  FViewList : TObjectList;
  procedure PresentDataList;
end;

procedure TMainForm.PresentDataList;
var
  LView : TImageView;
begin
  for LIdx := 0 to FDataList.Count - 1 do
  begin
    if LIdx < FViewList.Count then
      LView := FViewList[LIdx] as TImageView
    else
      begin
        LView := TImageView.Create( PageControl1 );
        FViewList.Add( LView );
        LView.ManualDock( PageControl1, nil, alClient );
      end;
    LView.Visible := false;
    LView.ImageData := FDataList[LIdx] as TImageData;
    LView.Visible := true;
  end;
  // überflüssige Views entfernen
  for LIdx := FViewList.Count - 1 downto FDataList.Count do
  begin
    LView := FViewList[LIdx] as TImageView;
    FViewList.Delete( LIdx );
    LView.Close;
  end;
end;
Nach jeder Änderung an der
Delphi-Quellcode:
FDataList
(Sortieren, Hinzufügen, Entfernen) ruft man einfach
Delphi-Quellcode:
PresentDataList
auf und der Keks ist gegessen.

Auf der MainForm ist nun ein Button um das aktuell angezeigte Bild zu entfernen, dann muss man folgendes ausführen
Delphi-Quellcode:
procedure TMainForm.Button1Click( Sender : TObject );
begin
  FDataList.Delete( PageControl1.TabIndex );
  PresentDataList;
end;
Richter wäre es aber auch hier eine sprechendere Programmierung zu wählen
Delphi-Quellcode:
procedure TMainForm.Button1Click( Sender : TObject );
begin
  RemoveCurrentItem;
end;

procedure TMainForm.RemoveCurrentItem;
begin
  RemoveItem( FDataList[PageControl1.TabIndex] );
end;

procedure TMainForm.RemoveItem( AItem : TObject );
begin
  FDataList.Remove( AItem );
  PresentDataList;
end;
Wenn man nämlich aus der ImageView heraus dieses Entfernen auslösen möchte, dann gibt man jeder ImageView einfach dieses als Event mit
Delphi-Quellcode:
procedure TMainForm.PresentDataList;
  ...
  LView.OnRemoveItem := RemoveItem;
  ...
und in der ImageView wird das dann einfach aufgerufen und alles passiert von selber
Delphi-Quellcode:
procedure TImageView.RemoveButtonClick( Sender : TObject );
begin
  OnRemoveItem( ImageData );
end;
Das möchte ich jetzt aber nicht weiter ausführen, sonst sprengt es den Rahmen.

Die
Delphi-Quellcode:
TImageView
Form muss jetzt natürlich im
Delphi-Quellcode:
OnShow
Event die Daten aus dem
Delphi-Quellcode:
ImageData
lesen und entsprechend anzeigen. Hier kann man in dem Setter von ImageData auch noch ein Flag setzen, ob sich ImageData überhaupt geändert hat und kann sich das erneute Einlesen sparen.

(da das mit dem Resourcenschutzblock nur zu Verwirrung führt, habe ich mal alles weggelassen, was nicht unbedingt notwendig ist)

Blup 15. Okt 2014 14:22

AW: TImages verwalten
 
Mir ist nicht klar für was du überhaupt ein angedocktes Fenster benötigst.
Ich vermute du vermischt die Anzeige und das Halten der Daten.

Wenn zum Bild zusätzliche Einstellungen gehören, dann erweitere einfach die Klasse.
Delphi-Quellcode:
TMyColorStyle = (mycsDefault, mycsGray, mycsBlackAndWhite);

TMyPicture = class(TPicture)
private
  FColorStyle: TMyColorStyle;
protected
  procedure Draw(ACanvas: TCanvas; const Rect: TRect); override;
  procedure DrawBlackAndWhite((ACanvas: TCanvas; const Rect: TRect);
  procedure DrawGray(ACanvas: TCanvas; const Rect: TRect);
published
  property ColorStyle: TMyColorStyle read FColorStyle write FColorStyle;
end;

TMyPictureList = TObjectList<TMyPicture>;

procedure TMyPicture.Draw(ACanvas: TCanvas; const Rect: TRect);
begin
  case FColorStyle of
    mycsGray:         DrawGray(ACanvas, Rect);
    mycsBlackAndWhite: DrawBlackAndWhite(ACanvas, Rect);
  else
    inherited Draw(ACanvas, Rect);
  end;
end;
Für die Anzeige genügt eine Paintbox, im OnPaint wird das aktuell ausgewählte Bild mit seinen Einstellungen gezeichnet.
Den Steuerelementen werden die zum Bild gehörenden Einstellungen zugewiesen.
Vereinfacht:
Delphi-Quellcode:
TMyForm = class(TForm)

  procedure DoOnTabChanged(Sender: TObject);
  procedure DoOnRadioClick(Sender: TObject);
  procedure DoOnPaintBoxPaint(Sender: TObject);
private
  FPictureList: TMyPictureList;
  function GetCurrentPicture: TMyPicture;
end;

procedure TMyForm.DoOnTabChanged(Sender: TObject);
var
  Picture: TMyPicture;
  ColorStyle: TMyColorStyle;
begin
  Picture := GetCurrentPicture;
  if Assigned(Picture) then
    ColorStyle := Picture.ColorStyle
  else
    ColorStyle := mycsDefault;

  RBtnDefault.Checked := ( ColorStyle = mycsDefault );
  RBtnGray.Checked   := ( ColorStyle = mycsGray );
  RBtnBW.Checked     := ( ColorStyle = mycsBlackAndWhite );
  {neu zeichnen}
  PaintBox.Invalidate;
end;

procedure TMyForm.DoOnRadioClick(Sender: TObject);
var
  Picture: TMyPicture;
  ColorStyle: TMyColorStyle;
begin
  ColorStyle := mycsDefault;
  Picture := GetCurrentPicture;
  if Assigned(Picture) then
  begin
    if     RBtnBW.Checked  then ColorStyle := mycsBlackAndWhite
    else if RBtnGray.Checked then ColorStyle := mycsGray;
  end;
  Picture.ColorStyle := ColorStyle;
  {neu zeichnen}
  PaintBox.Invalidate;
end;

procedure TMyForm.DoOnPaintBoxPaint(Sender: TObject);
begin
  PaintBox.Canvas.StretchDraw(PaintBox.ClientRect, GetCurrentPicture);
end;

function TMyForm.GetCurrentPicture: TMyPicture;
var
  idx: Integer;
begin
  idx := TabControl.TabIndex;
  if (idx >= 0) and (idx < FPictureList.Count) then
    Result := FPictureList[idx]
  else
    Result := nil;
end;

Schwedenbitter 15. Okt 2014 20:39

AW: TImages verwalten
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von Blup (Beitrag 1276043)
Mir ist nicht klar für was du überhaupt ein angedocktes Fenster benötigst.
Ich vermute du vermischt die Anzeige und das Halten der Daten.
...

Diese Vermutung wird richtig sein.
Ich finde aber die Forms nicht schlecht. Denn ich kann den Code für diese separat verwalten, was den Code später sogar besser warten lässt. Und ich möchte auch keine Querverweise haben. Das heißt, die Fenster wissen nichts voneinander und kümmern sich - bei Bedarf - um das Umwandeln selbst. Es verkompliziert es daher, eine Liste mit den Bilder im Hauptprogramm (=Code des MainForm) vorzuhalten und zu warten - mit Ausnahme der Liste für die Instanzen der Fenster.

Ich hatte bereits in meinem ersten Post eingestellt, wie ich es gern hätte. Genau so sieht es jetzt auch aus.
Der Zugriff auf die Bild-Daten klappt. Die Bilder sollen auch nicht in Grau angezeigt, sondern nur in Grau gespeichert werden. Ich habe dennoch noch einmal einen Screenshot angehängt.


Alle Zeitangaben in WEZ +1. Es ist jetzt 10:26 Uhr.
Seite 2 von 3     12 3      

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