Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi PNGImageList zu langsam / Alternative gesucht (https://www.delphipraxis.net/107184-pngimagelist-zu-langsam-alternative-gesucht.html)

Spes 23. Jan 2008 22:14


PNGImageList zu langsam / Alternative gesucht
 
Hi zusammen,

ich würde gerne die PngImageList verwenden transparente Icons an verschiedenen Stellen (Images, Menüs, Tabellen, ...) anzeigen zu lassen. Hierzu verwende ich knapp 100 Icons jeweils in 2 Größen (16x16 und 32x32), welche ich wie folgt (abgeschaut bei stz) lade:
Code:
PngList := TPngImageList.Create(nil);
PngItem := PngList.PngImages.Add ;
PngItem.PngImage.LoadFromFile(Filename);
Und dann beispielsweise wie folgt auf ein Image bringe
Code:
ImageFront.Picture.Assign(PngList.PngImages[I].PngImage);
Bei Laden konnte ich beobachten, wie folgende Methoden abgearbeitet werden:
PngList.PngImages.Add (PngImages ist vom Typ TPngImageCollectionItems)
-> TPngImageCollectionItem.Create
-> TCollectionItem.Create
-> TCollection.RemoveItem
-> TList.Remove
-> TList.IndexOf
Beim IndexOf rennt der dann natürlich im Worst-Case über die gesammte Liste und zwar für jedes Icon, so dass ich eine Laufzeit von irgendwas in 0(n²) je PngImageList bekomme. Da ich jetzt leider auch noch zwei Listen habe - jeweils eine pro Icongröße - dauert der Vorgang bei mir eine knappe Minute, bis das Programm gestartet ist.

Kann ich das irgendwie Beschleunigen ohne die Icon-Anzahl eingrenzen zu müssen?

Folgende Ideen kamen mir dabei:
- Irgendwie ein Array von TPngObjects auf die TPngList casten?
- Nur eine Liste anlegen und daraus dann die andere per Skalieren der PNGs erzeugen?
- Auf entweder die TCollection oder die TList verzichten (brauche ich wirklich beides?)?

Weiterhin habe ich versucht, die TPngImageCollectionItems zu entfernen und durch eine von TObjectList abgeleitete Liste zu ersetzen. Das Laden ging dann zwar fühlbar schneller, aber die 16x16-Icons wurden dann nicht mehr angezeigt (die 32er wohl - komisch).

Gibt es sonst vielleicht irgendwo ein Tutorial oder eine Anwendung in der ich mir die richtige Verwendung der PngImageList mal ansehen kann? (Google spuckt zur "PngImageList" bzw. "TPngImageList" jeweils lediglich drei Seiten aus und beim [ulr=http://www.delphipraxis.net/internal_redirect.php?t=111689&highlight=pngimagel ist]Secretizer[/url] finde ich die Verwendung der PngImageLists ilTreeIcons und ilGlyphs nicht).

Dani 24. Jan 2008 00:05

Re: PNGImageList zu langsam / Alternative gesucht
 
Verwende ImgList.PngImages.BeginUpdate und ImgList.PngImages.EndUpdate, das dürfte den Vorgang erheblich beschleunigen.

Edit: Beispiel ohne Fehlerbehandlung

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
const
  TimeFormat = 'nn:ss:zzz';
var I: Integer;
    StartTime, EndTime: TDateTime;
    TempFileName: String;
    TempImg: TPNGObject;
    TempBMP: TBitmap;
    RandomRect: TRect;
    C: TCanvas;
begin
  TempBMP := TBitmap.Create;
  TempBMP.Width := 32;
  TempBMP.Height := 32;

  C := TempBMP.Canvas;
  C.Pen.Style := psSolid;
  C.Brush.Style := bsSolid;
  for I := 0 to 100 do begin
    C.Pen.Color := Random(clWhite);
    C.Brush.Color := Random(clWhite);
    RandomRect := Rect(Random(TempBMP.Width), Random(TempBMP.Height),
                  Random(TempBMP.Width), Random(TempBMP.Height));
    C.FillRect(RandomRect);
  end;

  TempFileName := IncludeTrailingPathDelimiter(GetEnvironmentVariable('Temp')) +
                  'PngImageListTest.png';

  TempImg := TPNGObject.Create;
  TempImg.Assign(TempBMP);
  TempImg.SaveToFile(TempFileName);
  TempBMP.Free;
  TempImg.Free;

  StartTime := Now;
  ImgList.PngImages.BeginUpdate;
  for I := 0  to 300 do begin
    ImgList.PngImages.Add(False).PngImage.LoadFromFile(TempFileName);
  end;
  ImgList.PngImages.EndUpdate;
  EndTime := Now;
  Label1.Caption := 'Total: ' + FormatDateTime(TimeFormat, EndTime - StartTime);
end;

Spes 24. Jan 2008 21:18

Re: PNGImageList zu langsam / Alternative gesucht
 
Vielen Dank Dani :thumb:
Dank deinem Beispiel klappts jetzt in unter einer Sekunde. Wie bist du darauf gekommen die BeginUpdate und EndUpdate zu verwenden? ist das unter Delphi gängige Praxis, oder gabs dazu irgendwo Hinweise?

Vg,
Spes

Dani 24. Jan 2008 21:27

Re: PNGImageList zu langsam / Alternative gesucht
 
Bin den Code per Debugger durchgegangen und dort wurde nach jeder Einfügeoperation die Update-Methode der TPngImageCollectionItems aufgerufen:
Delphi-Quellcode:
procedure TPngImageCollectionItems.Update(Item: TCollectionItem);
begin
inherited Update(Item);
if FOwner is TPngImageList
then TPngImageList(FOwner).CopyPngs;
end;
wobei CopyPngs so aussieht:

Delphi-Quellcode:
procedure TPngImageList.CopyPngs;
var
   I: Integer;
   Png: TPNGObject;
   Icon: HIcon;
begin
//Are we adding a bunch of images?
if FLocked > 0
then Exit; {... danach werden alle PNGs neu erstellt}
...dann erst hab ich die Methoden BeginUpdate und EndUpdate entdeckt, hatte vorher keine Ahnung. :stupid:

Zitat:

Ist das unter Delphi gängige Praxis
Ja, wenn mehrere Datensätze sich ändern, ohne dass die View (also Formulare usw) darauf reagieren soll, sollte man diese Methoden verwenden. Man findet sie z.B. auch in TListItem oder TStrings.


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:14 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 by Thomas Breitkreuz