Delphi-PRAXiS
Seite 1 von 3  1 23      

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)

Schwedenbitter 10. Okt 2014 17:16

TImages verwalten
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo,

ich habe ein Programm zum Scannen. Dieses legt die Bilder zunächst nacheinander in einer
Delphi-Quellcode:
TImageList
ab und speichert die dann als png-Dateien.

Jetzt möchte ich das Programm gern erweitern. Dazu sollen die Bilder statt in einer TImageList jeweils erst als
Delphi-Quellcode:
TImage
nebst 3
Delphi-Quellcode:
TRadioButtons
in einer
Delphi-Quellcode:
TScrollBox
untereinander angezeigt werden. Hintergrund ist der, dass die Bilder standardmäßig in schwarzweiß eingescannt werden. Allerdings soll/muss es hin und wieder auch mal Fotos geben. Auch diesen Fall löst mein Programm im Ansatz. Allerdings gibt es immer wieder Nutzer, die einfachen Text mit 16 Mio. Farben einscannen und damit sinnloser Weise riesige Dateien erzeugen. Die Bilder sollen daher selbst beim Einscannen in Farbe nachträglich umgewandelt werden können - dafür die TRadioButtons.
Ein Screenshot, wie ich es gern hätte, ist angehängt.

Wie man TImage und TRadioButton zur Laufzeit erzeugt, ist klar. Klar ist mehr oder weniger auch die Umwandlung. Es geht also wirklich nur um das Vorhalten/Anzeigen für den Benutzer zur Laufzeit.

Meine Überlegung geht jetzt dahin, Image und Buttons in ein Object zu packen und dann das ganze in einer Liste abgeleitet von
Delphi-Quellcode:
TStringList
zu organisieren. In dieser kann man mit
Delphi-Quellcode:
AddObject();
derartiges erledigen.

Wäre das völlig abwegig?
Falls ja, wie macht man es richtig[tm]?

Ich lese gern selbst. Im Moment fehlen mir aber die passenden Suchworte für mein Problem. Daher bitte nicht gleich meckern, falls das Problem schon einmal ausführlich behandelt wurde, sondern lieber eine Links setzen. Danke.

Gruß, Alex

Sir Rufo 10. Okt 2014 18:18

AW: TImages verwalten
 
Zunächst würde ich die Bilder nicht komplett im Speicher behalten sondern jeden Scan direkt auf die Platte schreiben und merken (in einer Liste).

Für eine Komponenten-Komposition (TImage, TRadioButtons) eignen sich Frames sehr schön. Einfach ein Frame bauen und dann für jeden Scan eine Instanz erzeugen und in die Scrollbox packen.

Die Bilder werden für die Ansicht ja nicht in der vollen Auflösung benötigt, somit wäre es auch ratsam die Bilder selber nur in einer reduzierten Auflösung für die Anzeige bereitzustellen. Mit einer PaintBox könnte man auch auf gecachte Bilder zurückgreifen, die im Hintergrund geladen werden.

Auch das Umrechnen der Bilder sollte in einem Thread erfolgen, somit musst du eh mit Threads hantieren ;)

Schwedenbitter 11. Okt 2014 09:16

AW: TImages verwalten
 
Liste der Anhänge anzeigen (Anzahl: 1)
Danke für die Antwort.
Zitat:

Zitat von Sir Rufo (Beitrag 1275583)
Zunächst würde ich die Bilder nicht komplett im Speicher behalten sondern jeden Scan direkt auf die Platte schreiben und merken (in einer Liste).

Das ist mehr als unhandlich. Das Behalten der Bilder im Speicher ist über 5 Jahr erprobt und klappt prima. Denn die meisten Bilder in schwarzweiß sind bei einer Auflösung von 200dpi kleiner als 1 MB und der Scanner liefert 60 Seiten/min. Wenn ich da speichere, halte ich den Arbeitsablauf auf.

Zitat:

Zitat von Sir Rufo (Beitrag 1275583)
Für eine Komponenten-Komposition (TImage, TRadioButtons) eignen sich Frames sehr schön. Einfach ein Frame bauen und dann für jeden Scan eine Instanz erzeugen und in die Scrollbox packen.

Ich hatte mir das gestern Abend mal angesehen. Das sieht sehr schwierig aus. Ich habe aber evtl. eine Lösung gefunden, an deren Umsetzung es aber praktisch noch hapert.

Zitat:

Zitat von Sir Rufo (Beitrag 1275583)
Die Bilder werden für die Ansicht ja nicht in der vollen Auflösung benötigt, somit wäre es auch ratsam die Bilder selber nur in einer reduzierten Auflösung für die Anzeige bereitzustellen. Mit einer PaintBox könnte man auch auf gecachte Bilder zurückgreifen, die im Hintergrund geladen werden.

Auch das Umrechnen der Bilder sollte in einem Thread erfolgen, somit musst du eh mit Threads hantieren ;)

Zum ersten - Siehe oben.
Zum zweiten - das kommt noch :-D

Und nun zu meiner Lösung:
Ich hatte bei der Suche nach Frames im Netz die Möglichkeit entdeckt, Formulare anzudocken. Das klappt prima in einer
Delphi-Quellcode:
TPageControl
. Und der Vorteil (mit Frames kenne ich mich nicht aus) ist der, dass ich die Formulare schon zu Entwurfszeit basteln kann. Ich habe jetzt bloß noch ein Problem:
Wie schaffe ich es in der TPageControl auf das Schließen eines Fensters zu reagieren, so dass ich den TabSheet ebenfalls schließen kann? Ich habe meinen Code mal angehängt.

Wenn dazu jemand eine Lösung hätte, wäre mein Problem - wenn auch anders als in der Überschrift evtl. gedacht - gelöst.

Gruß und danke für den Push in diese Richtung!
Alex

Sir Rufo 11. Okt 2014 09:57

AW: TImages verwalten
 
Die Anwendung wird nicht aufgehalten, wenn die Aktionen in einem Thread erfolgen (speichern, laden, umrechnen) ;)

Zum Schließen des Tabs musst du eigentlich rein gar nichts machen ... ok bis auf eins:
Delphi-Quellcode:
type
  TDockForm = clas( TForm )
  protected
    // Ich könnte auch den Event OnClose nehmen, da ich aber von dieser Form
    // weitere ableiten möchte, ist dieser Weg etwas robuster :o)
    procedure DoClose( var Action: TCloseAction ); override;
  end;

  TDockFormClass = class of TDockForm;

procedure TDockForm.DoClose( var Action: TCloseAction );
begin
  Action := caFree;
  inherited; // <- dort wird der Event OnClose gefeuert

end;
Wenn du jetzt das Formular schließt, dann wird es durch das Setzen von
Delphi-Quellcode:
Action := caFree
auch automatisch zerstört, was wiederum automatisch den Tab aus dem PageControl entfernt :)

Vorausgesetzt, die Form wird auch so dort eingedockt:
Delphi-Quellcode:
procedure TMyForm.DockNewForm( APageControl : TPageControl; ADockFormClass : TDockFormClass );
var
  LForm : TDockForm;
begin
  LForm := TDockFormClass.Create( APageControl );
  try
    LForm.ManualDock( APgeControl, nil, alClient );
    LForm.Visible := True;
    LForm := nil;
  finally
    LForm.Free;
  end;
end;
Wenn du diese
Delphi-Quellcode:
TDockForm
als Basis für deine weiteren DockFOrms nimmst, dann kannst du nach Belieben dort die unterschiedlichsten DockForms an dein PageControl hängen und diese werden dann beim Schließen automatisch aufgeräumt und der Tab geschlossen :)

Schwedenbitter 11. Okt 2014 11:58

AW: TImages verwalten
 
Zitat:

Zitat von Sir Rufo (Beitrag 1275595)
Vorausgesetzt, die Form wird auch so dort eingedockt:
Delphi-Quellcode:
procedure TMyForm.DockNewForm( APageControl : TPageControl; ADockFormClass : TDockFormClass );
var
  LForm : TDockForm;
begin
  LForm := TDockFormClass.Create( APageControl );
  try
    LForm.ManualDock( APgeControl, nil, alClient );
    LForm.Visible := True;
    LForm := nil;
  finally
    LForm.Free;
  end;
end;
...

Danke für die ausführlich Beschreibung.
Ich kann aber nirgends ein Ereignis wie
Delphi-Quellcode:
onDockNewForm
finden. Und dann habe ich noch das Problem wo bzw. wie ist
Delphi-Quellcode:
TDockFormClass
definiert?

[edit]
Und noch ein Problem fällt mir ein:
Wie greife ich auf die einzelnen Komponenten (TImage etc.) nach dem Erstellen des angedockten Forms zu?
Der Benutzer soll die Bilder erst scannen. Dann mit dem Button Bilder, die er nicht haben will, löschen können und schließlich über einen zentralen Save-Button alle Bilder nacheinander abspeichern.
Letzteres soll dann über einen Thread vom Hauptformular erfolgen. Ich muss also irgendwie rankommen...
[/edit]

Gruß, Alex

Sir Rufo 11. Okt 2014 14:04

AW: TImages verwalten
 
Zitat:

Zitat von Schwedenbitter (Beitrag 1275599)
Ich kann aber nirgends ein Ereignis wie
Delphi-Quellcode:
onDockNewForm
finden.

Wieso ein Ereignis? Das ist eine Methode, die ich geschrieben habe ... die allerdings besser die Form-Instanz zurückliefert
Delphi-Quellcode:
procedure TMyForm.DockNewForm( APageControl : TPageControl; ADockFormClass : TDockFormClass ) : TDockForm;
var
  LForm : TDockForm;
begin
  LForm := TDockFormClass.Create( APageControl );
  try
    LForm.ManualDock( APgeControl, nil, alClient );
    LForm.Visible := True;
    Result := LForm;
    LForm := nil;
  finally
    LForm.Free;
  end;
end;
Zitat:

Zitat von Schwedenbitter (Beitrag 1275599)
Und dann habe ich noch das Problem wo bzw. wie ist
Delphi-Quellcode:
TDockFormClass
definiert?

steht doch in dem CodeSchnipsel
Delphi-Quellcode:
type
  TDockForm = class( TForm )
  protected
    // Ich könnte auch den Event OnClose nehmen, da ich aber von dieser Form
    // weitere ableiten möchte, ist dieser Weg etwas robuster :o)
    procedure DoClose( var Action: TCloseAction ); override;
  end;

  TDockFormClass = class of TDockForm; // <--- DA
Zitat:

Zitat von Schwedenbitter (Beitrag 1275599)
[edit]
Und noch ein Problem fällt mir ein:
Wie greife ich auf die einzelnen Komponenten (TImage etc.) nach dem Erstellen des angedockten Forms zu?
Der Benutzer soll die Bilder erst scannen. Dann mit dem Button Bilder, die er nicht haben will, löschen können und schließlich über einen zentralen Save-Button alle Bilder nacheinander abspeichern.
Letzteres soll dann über einen Thread vom Hauptformular erfolgen. Ich muss also irgendwie rankommen...
[/edit]

Was interessiert es dich, was in dem
Delphi-Quellcode:
TImage
drin ist? Das wird für die Anzeige benötigt ... aus und Ende.

Erstelle dir ein Daten-Objekt, was alle Informationen beinhaltet und merke dir dort alle Informationen zu jedem gescannten Bild und organisiere diese in einer Liste. Zu jedem Daten-Objekt gibt es dann eine Form (der du das zugehörige Daten-Objekt an die Hand gibts), die die Inhalte aus dem Daten-Objekt anzeigen und auch die Eingaben des Benutzers dort ablegen kann.

Wenn der Benutzer fertig ist, dann gehts du einfach durch deine Liste und arbeitest die einzelnen Bilder ab. Die einzelnen Forms interessieren nicht mehr ;)

Schwedenbitter 14. Okt 2014 17:16

AW: TImages verwalten
 
Danke für die Erläuterungen.
Zitat:

Zitat von Sir Rufo (Beitrag 1275609)
... Das ist eine Methode, die ich geschrieben habe ... die allerdings besser die Form-Instanz zurückliefert
Delphi-Quellcode:
procedure TMyForm.DockNewForm( APageControl : TPageControl; ADockFormClass : TDockFormClass ) : TDockForm;
var
  LForm : TDockForm;
begin
  LForm := TDockFormClass.Create( APageControl );
  try
    LForm.ManualDock( APgeControl, nil, alClient );
    LForm.Visible := True;
    Result := LForm;
    LForm := nil;
  finally
    LForm.Free;
  end;
end;

OK.
Aber müsste es nicht richtiger Weise dann
Delphi-Quellcode:
function
statt
Delphi-Quellcode:
procedure
heißen?
Und wo genau wird die Instanz übergeben (Result:=... oder Var in der Definition der Procedure)?

Zitat:

Zitat von Sir Rufo (Beitrag 1275609)
Was interessiert es dich, was in dem
Delphi-Quellcode:
TImage
drin ist? Das wird für die Anzeige benötigt ... aus und Ende.

Es interessiert mich deshalb, weil ich damit gern arbeiten würde. Es soll 4 Möglichkeiten geben, die Bilder zu speichern. Über den Button soll das Bild gelöscht werden können. Und damit schließe ich (und geben den Speicher frei) dann zunächst erst einmal bloß die Form. Ich will/muss also nicht nur an die Bilddaten, sondern auch herausbekommen, welches der RadioButtons gewählt wurde. Und das sollte theoretisch über das Code-Beispiel funktionieren, wenn ich Deine Antwort richtig interpretiere. Ich verstehe bloß nicht wie.

Zitat:

Zitat von Sir Rufo (Beitrag 1275609)
Erstelle dir ein Daten-Objekt, was alle Informationen beinhaltet und merke dir dort alle Informationen zu jedem gescannten Bild und organisiere diese in einer Liste. Zu jedem Daten-Objekt gibt es dann eine Form (der du das zugehörige Daten-Objekt an die Hand gibts), die die Inhalte aus dem Daten-Objekt anzeigen und auch die Eingaben des Benutzers dort ablegen kann.

Wenn der Benutzer fertig ist, dann gehts du einfach durch deine Liste und arbeitest die einzelnen Bilder ab. Die einzelnen Forms interessieren nicht mehr ;)

Genau das war/ist ja meine (Ausgangs)Frage. Wie organisiere ich diese Liste? Leite ich sie von TStringList ab? Oder einfach bloß von TList?... Mit TImageList arbeite ich im Moment schon. Aber das ist mir zu unkomfortabel.

mkinzler 14. Okt 2014 17:20

AW: TImages verwalten
 
Zitat:

Aber müsste es nicht richtiger Weise dann function statt procedure heißen?
Ja.
Zitat:

Und wo genau wird die Instanz übergeben (Result:=... oder Var in der Definition der Procedure)?
Als Result nur im gezeigten Code wird diese vorher freigegeben ( im finally), was imho keinen Sinn macht.

Sir Rufo 14. Okt 2014 18:40

AW: TImages verwalten
 
Zitat:

Zitat von mkinzler (Beitrag 1275911)
Als Result nur im gezeigten Code wird diese vorher freigegeben ( im finally), was imho keinen Sinn macht.

Die Form-Instanz wird eben nicht freigegeben, ausser es kommt innerhalb der Methode zu einer Exception, dann wird abgebrochen, demzufolge nichts zurückgegeben und darum durch das
Delphi-Quellcode:
finally
die Instanz freigegeben.

Das ist eigentlich eine sehr übliche und sinnvolle Vorgehensweise wenn man nicht auf Speicherlecks steht.
Delphi-Quellcode:
function FooFactory : TFoo;
var
  LFoo : TFoo;
begin
  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;
end;
Auch wenn es sich im Beispiel um eine Komponente mit Owner handelt, was für eine korrekte Freigabe durch den Owner sorgt. Eine ungenutzte Instanz im Speicher ist zuviel und solche Fehler (Speicher läuft im Betrieb voll) sind nachher nur schwer zu finden, denn beim Beenden gibt es kein Speicherleck, dafür ist irgendwann der Speicher voll und die Anwendung verabschiedet sich.

Schwedenbitter 14. Okt 2014 19:20

AW: TImages verwalten
 
Danke. Es wird langsam klarer und zeigt sich, dass es für Gelegenheitprogrammierer wie mich schwer werden dürfte. Ich habe jetzt folgendes zusammengebastelt. Allerdings weiß ich nicht, wie ich herausbekomme, ob der Benutzer ein Form selbst mit Close "zerstört" hat:
Delphi-Quellcode:
Type
   TMainForm   = Class(TForm)
                     BtnAdd   : TButton;
                     BtnInfo   : TButton;
                     PCPics   : TPageControl;
                     Procedure FormCreate(Sender: TObject);
                     Procedure BtnAddClick(Sender: TObject);
                     Procedure BtnInfoClick(Sender: TObject);
                     Procedure FormDestroy(Sender: TObject);
                 Protected
                     fCount   : Integer;
                     fPicList   : TList;
                 End;

Var
   MainForm      : TMainForm;

Implementation

{$R *.dfm}

Procedure TMainForm.FormCreate(Sender: TObject);
Begin
   fCount:=0;
   fPicList:=TList.Create;
End;

Procedure TMainForm.BtnAddClick(Sender: TObject);
Var
   aPNG         : TPngImage;
   lForm         : TDockForm;
Begin
   aPNG:=TPngImage.Create;
   Try
      aPNG.LoadFromFile('.TestBilder\_0001.png');
      aPNG.RemoveTransparency;
      lForm:=TDockFormClass.Create(PCPics);
      Try
         lForm.ManualDock(PCPics, nil, alClient);
         lForm.Visible:=True;
         LForm.IMGScan.Picture.Bitmap.Assign(aPNG);
         Inc(fCount);
         lForm.Caption:='Bild ' + FormatFloat('0,', fCount);
         fPicList.Add(lForm);   // <- in Liste merken
         lForm:=nil;            // 1:1 übernommen
      Finally
         lForm.Free;            // 1:1 übernommen
         PCPics.ActivePageIndex:=Pred(PCPics.PageCount);
      End;
   Finally
      aPNG.Free;
   End;
End;

Procedure TMainForm.BtnInfoClick(Sender: TObject);
Var
   I            : Integer;
   lDockForm         : TDockForm;
Begin
   If (fPicList.Count = 0) Then Exit;
   I:=PCPics.ActivePageIndex;
   lDockForm:=fPicList.Items[I];// <- so greife ich jetzt zu.
   With lDockForm Do
   Try
      ShowMessage('Original' + #09 + BoolToStr(RBorgjpg.Checked, True));
   Finally
   End;
End;

Procedure TMainForm.FormDestroy(Sender: TObject);
Begin
   Try
      While (fPicList.Count > 0) Do fPicList.Delete(0);
   Finally
      fPicList.Free;
   End;
End;

End.
[edit]
Also der Zugriff klappt.
Bleibt die Frage, wie ich herausbekomme, ob der Benutzer eine Form gelöscht hat...
[/edit]


Alle Zeitangaben in WEZ +1. Es ist jetzt 17:35 Uhr.
Seite 1 von 3  1 23      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz