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
Seite 1 von 3  1 23      
Schwedenbitter

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

TImages verwalten

  Alt 10. Okt 2014, 18:16
Hallo,

ich habe ein Programm zum Scannen. Dieses legt die Bilder zunächst nacheinander in einer 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 TImage nebst 3 TRadioButtons in einer 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 TStringList zu organisieren. In dieser kann man mit 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
Miniaturansicht angehängter Grafiken
scan-modul.png  
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
 
#2

AW: TImages verwalten

  Alt 10. Okt 2014, 19:18
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
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
Schwedenbitter

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

AW: TImages verwalten

  Alt 11. Okt 2014, 10:16
Danke für die Antwort.
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.

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.

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

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 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
Angehängte Dateien
Dateityp: zip Scan-Modul.zip (3,4 KB, 11x aufgerufen)
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
 
#4

AW: TImages verwalten

  Alt 11. Okt 2014, 10:57
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 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 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
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 (11. Okt 2014 um 11:00 Uhr)
  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 11. Okt 2014, 12:58
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 onDockNewForm finden. Und dann habe ich noch das Problem wo bzw. wie ist 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
Alex Winzer

Geändert von Schwedenbitter (11. Okt 2014 um 13:29 Uhr)
  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 11. Okt 2014, 15:04
Ich kann aber nirgends ein Ereignis wie 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;
Und dann habe ich noch das Problem wo bzw. wie ist 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
[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 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
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
Schwedenbitter

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

AW: TImages verwalten

  Alt 14. Okt 2014, 18:16
Danke für die Erläuterungen.
... 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 function statt procedure heißen?
Und wo genau wird die Instanz übergeben (Result:=... oder Var in der Definition der Procedure)?

Was interessiert es dich, was in dem 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.

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.
Alex Winzer
  Mit Zitat antworten Zitat
mkinzler
(Moderator)

Registriert seit: 9. Dez 2005
Ort: Heilbronn
39.861 Beiträge
 
Delphi 11 Alexandria
 
#8

AW: TImages verwalten

  Alt 14. Okt 2014, 18:20
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.
Markus Kinzler
  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
 
#9

AW: TImages verwalten

  Alt 14. Okt 2014, 19:40
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 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.
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
Schwedenbitter

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

AW: TImages verwalten

  Alt 14. Okt 2014, 20:20
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]
Alex Winzer

Geändert von Schwedenbitter (14. Okt 2014 um 20:44 Uhr) Grund: Mögliche Teillösung gefunden.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 3  1 23      


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 15:08 Uhr.
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