AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

TImages verwalten

Ein Thema von Schwedenbitter · begonnen am 10. Okt 2014 · letzter Beitrag vom 5. Nov 2014
Antwort Antwort
Jumpy

Registriert seit: 9. Dez 2010
Ort: Mönchengladbach
1.740 Beiträge
 
Delphi 6 Enterprise
 
#1

AW: TImages verwalten

  Alt 15. Okt 2014, 13:21
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.
Ralph
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#2

AW: TImages verwalten

  Alt 15. Okt 2014, 14:22
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 FDataList (Sortieren, Hinzufügen, Entfernen) ruft man einfach 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 TImageView Form muss jetzt natürlich im OnShow Event die Daten aus dem 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)
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Blup

Registriert seit: 7. Aug 2008
Ort: Brandenburg
1.493 Beiträge
 
Delphi 12 Athens
 
#3

AW: TImages verwalten

  Alt 15. Okt 2014, 14:22
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;
  Mit Zitat antworten Zitat
Schwedenbitter

Registriert seit: 22. Mär 2003
Ort: Finsterwalde
622 Beiträge
 
Turbo Delphi für Win32
 
#4

AW: TImages verwalten

  Alt 15. Okt 2014, 20:39
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.
Angehängte Grafiken
Dateityp: png DockForms.png (236,2 KB, 9x aufgerufen)
Alex Winzer
  Mit Zitat antworten Zitat
Schwedenbitter

Registriert seit: 22. Mär 2003
Ort: Finsterwalde
622 Beiträge
 
Turbo Delphi für Win32
 
#5

AW: TImages verwalten

  Alt 4. Nov 2014, 13:13
Ich bin jetzt (urlaubsbedingt) schon etwas weiter:
Mein DockForm bietet ein Ereignis an, welches vor dem Löschen ausgelöst wird und die Adresse des DockForms übergibt. Damit bekommt das Hauptfenster mit, das und was gelöscht wurde. Danke insoweit für Eure wertvollen Tipps!

Jetzt wollte ich das gern auf Speicherlecks untersuchen, bevor ich weitermache. Dazu habe ich mir FastMM4991 runtergeladen. Ich hatte FastMM schon vor Jahren benutzt. Meiner Erinnerung nach muss man es einfach als erste Unit in die dpr-Datei einbinden. Anderes Infos habe ich trotz Suche im Forum nicht gefunden.
Kann es sein, dass FastMM unter Delphi XE5 nicht mehr funktioniert?

Es kommt keine Meldung. Auch dann nicht, wenn ich in FormCreate einfach folgenden Code einfüge:
Delphi-Quellcode:
With tStringList.Create Do
Begin
  Append('Datenmüll');
End;
FastMM scheint schon lange nicht mehr gepflegt und explizit zu XE5 und FastMM konnte ich nichts finden.

Was mache ich falsch?
Falls FastMM nicht mehr funktioniert, womit erforscht man denn heutzutage Speicherlecks?

Gruß, Alex
Alex Winzer
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#6

AW: TImages verwalten

  Alt 4. Nov 2014, 13:41
FastMM ist seit ??? in Delphi integriert, wird also schon direkt mitgeliefert.

Wenn du den Bericht über Speicherlecks am Ende haben möchtest, dann musst du das lediglich einschalten mit ReportMemoryLeaksOnShutdown := true; (am besten gleich am Anfang in der Projekt-Datei)
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)

Geändert von Sir Rufo ( 5. Nov 2014 um 09:23 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.550 Beiträge
 
Delphi 12 Athens
 
#7

AW: TImages verwalten

  Alt 4. Nov 2014, 14:13
FastMM ist seit ??? in Delphi integriert,
Ich glaub D2006/TDE, also würde passen.

Das externe FastMM braucht man eigentlich nur, wenn man z.B. die erweiterten Debuggingfunktionen nutzen möchte. (Prüfen auf Pufferüberläufe, Schreiben nach Free, wer hat was wann erstellt usw.)


FastMM funktioniert noch und ja, es muß als Erstes in die DPR (außer man benutzt Packages, denn da muß es als Erstes in die DPK des ersten Packages)
Ein Therapeut entspricht 1024 Gigapeut.
  Mit Zitat antworten Zitat
Schwedenbitter

Registriert seit: 22. Mär 2003
Ort: Finsterwalde
622 Beiträge
 
Turbo Delphi für Win32
 
#8

AW: TImages verwalten

  Alt 5. Nov 2014, 09:33
Danke!
Und da ich Delphi jetzt einfach mal so glaube, freue ich mich, dass mein Code bis hierhin keine Speicherlecks produziert hat.

Eine letzte Frage habe ich dann aber trotzdem noch:
Ich hatte hier (etwas weiter unten) bereits geschrieben, wie ich auf die einzelnen Forms im PageControl zugreife. Den Code habe ich um 2 Zeilen kürzen können. Ich würde es aber gern noch übersichtlicher gestalten und daher den Zugriff casten. Folgendes funktioniert leider nicht:
Delphi-Quellcode:
// Aus diesem hier ...
Procedure TMainForm.FormKeyDown(Sender: TObject; Var Key: Word;
   Shift: TShiftState);
Var
   lDockForm   : TDockForm;
Begin
   If (PCPics.PageCount = 0) Then Exit;
   If (Key = VK_DELETE) Then
   Begin
      lDockForm:=fPicList.Items[PCPics.ActivePageIndex];
      lDockForm.BtnDelete.Click;
   End;
End;

// ... soll auch an mehreren anderen Stellen so etwas hier werden:
Procedure TMainForm.FormKeyDown(Sender: TObject; Var Key: Word;
   Shift: TShiftState);
Begin
   If (PCPics.PageCount = 0) Then Exit;
   If (Key = VK_DELETE) Then
      With (fPicList.Items[PCPics.ActivePageIndex] As TDockForm) Do
         BtnDelete.Click;
      // geht auch nicht :-)
      (fPicList.Items[PCPics.ActivePageIndex] As TDockForm).BtnDelete.Click;
End;
Wieso geht es so nicht?
Kann man es irgendwie (anders) machen?

[edit]
Ich wäre nicht auf die Idee gekommen, dass es mind. 3 Varianten gibt, wie man casten kann. So klappt es:
Delphi-Quellcode:
Procedure TMainForm.FormKeyDown(Sender: TObject; Var Key: Word;
   Shift: TShiftState);
Begin
   If (PCPics.PageCount = 0) Then Exit;
   If (Key = VK_DELETE) Then
      TDockForm(fPicList.Items[PCPics.ActivePageIndex]).BtnDelete.Click;
End;
Aus 8 Zeilen 3 gemacht. Sehr schön.
[/edit]

Gruß, Alex
Alex Winzer

Geändert von Schwedenbitter ( 5. Nov 2014 um 09:44 Uhr) Grund: Lösung gefunden
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:35 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