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/)
-   -   Wie verwendet man die neue TVirtualImageList (https://www.delphipraxis.net/198699-wie-verwendet-man-die-neue-tvirtualimagelist.html)

DieDolly 24. Nov 2018 14:07

Wie verwendet man die neue TVirtualImageList
 
Wie verwendet man die neue TVirtualImageList? Ich verstehe noch nicht so rich tig was die überhaupt soll, wofür die ImageCollection ist, warum man die im OI mit der VirtualList verknüpft und noch mehr. Mein erster Versuch geht in die Hose
Delphi-Quellcode:
Image1.Picture.Icon := VirtualImageList1.Images.Items[ImageCollection1.GetIndexByName('icon')];
Auf der Form habe ich TVirtualImageList und TImageCollection1. Alle Icons sind im TImageCollection und komischerweise auch im TVirtualImageList. Sieht aus wie unnötige doppelte Arbeit.

Uwe Raabe 24. Nov 2018 14:40

AW: Wie verwendet man die neue TVirtualImageList
 
Die beiden Komponenten spielen ihre Vorteile eigentlich erst dann aus, wenn es um High DPI geht. Die ImageCollection hält zunächst erstmal nur die Icons, gegebenenfalls auch in unterschiedlichen Größen. Die VirtualImageList holt sich ihre Icons aus der ImageCollection in der Größe, die sie gerade braucht. Damit wird eine automatische Anpassung an unterschiedliche DPI Werte ermöglicht. Damit das funktioniert muss die VirtualImageList zwingend auf ein Form platziert werden. Das Form bemerkt die DPI Änderung und benachrichtigt die VirtualImageList. Diese besorgt sich dann die Icons in der passenden Größe von der ImageCollection, die bei Bedarf auch skaliert wenn die passende Größe nicht vorhanden ist.

Dein Code-Beispiel
Delphi-Quellcode:
Image1.Picture.Icon := VirtualImageList1.Images.Items[ImageCollection1.GetIndexByName('icon')];

kann so nicht funktionieren, da Images.Items kein TIcon oder TBitmap zurückliefert, sondern ein TVirtualImageListItem. Es übrigens auch gar nicht nötig, über die VirtualImageList zu gehen. Das Icon bekommst du wesentlich bequemer direkt aus der ImageCollection. Dabei gibst du gleich die Größe an, in der du es haben willst.

Delphi-Quellcode:
  Image1.Picture.Graphic := ImageCollection1.GetSourceImage(ImageCollection1.GetIndexByName('icon'), 256, 256);

DieDolly 24. Nov 2018 14:47

AW: Wie verwendet man die neue TVirtualImageList
 
Ich benutze aktuell deine PngImageList mit mehreren Helpern. So gesehen benutze ich 5 PngImageLists mit 5 verschiedenen Icongrößen.
Über eine eigene Prozedur lasse ich mir dann das Icon zurückgeben was ich brauche. Was gebraucht wird, übergebe ich in den Parametern.

Delphi-Quellcode:
procedure ... LoadIcon(const AName: string; IconSize: TIconSize; Icon: TIcon);
begin
 case IconSize of
  is16:
   Icons16.LoadImageByName(AName, Icon);
  is32:
   Icons32.LoadImageByName(AName, Icon);
  is48:
   Icons48.LoadImageByName(AName, Icon);
  is64:
   Icons64.LoadImageByName(AName, Icon);
  is128:
   Icons128.LoadImageByName(AName, Icon);
 end;
end;
HighDPI wird auch die nächsten Jahre an mir vorbei gehen. Danke für deine Erklärung. Habe demnach keinen Gebrauch für diese neue Komponente.

EWeiss 24. Nov 2018 16:09

AW: Wie verwendet man die neue TVirtualImageList
 
ein..

Delphi-Quellcode:
  is256:
    Icons256.LoadImageByName(AName, Icon);
wäre nicht schlecht ist ja fast schon Standard.

gruss

DieDolly 24. Nov 2018 17:43

AW: Wie verwendet man die neue TVirtualImageList
 
Wo sollte ich das denn benutzen? Wenn ich an einer Stelle an 16x16 Icon brauche, nehme ich 16x16. Ich habe keine Stelle wo ich jemals 256 bräuchte.

EWeiss 24. Nov 2018 17:58

AW: Wie verwendet man die neue TVirtualImageList
 
Zitat:

Zitat von DieDolly (Beitrag 1419053)
Wo sollte ich das denn benutzen? Wenn ich an einer Stelle an 16x16 Icon brauche, nehme ich 16x16. Ich habe keine Stelle wo ich jemals 256 bräuchte.

Du eventuell nicht aber das System vielleicht?
Es sei denn deine Anwendungen laufen nur auf deinem System Privat.. dann kannst du das natürlich ignorieren.

Wenn du also nur! Größen definierst die Dir zusagen und das System ist so eingestellt das es bei größeren Monitoren zum Beispiel 256 Icons anzeigt.
Nun dann bist du leicht aufgeschmissen bzw.. es wird das maximal größte verwendet was dann vom System skaliert wird.

War auch nur ein Vorschlag. :)

gruss

DieDolly 24. Nov 2018 18:05

AW: Wie verwendet man die neue TVirtualImageList
 
Keine Ahnung was du meinst. Bei mir wird alles richtig angezeigt. Egal welche Auflösung und DPI.

Redeemer 24. Nov 2018 18:29

AW: Wie verwendet man die neue TVirtualImageList
 
Wer UI-Grafiken 2018 als Rastergrafiken speichert, hat die Kontrolle über sein Leben verloren.

DieDolly 24. Nov 2018 18:32

AW: Wie verwendet man die neue TVirtualImageList
 
Statt solche sinnlosen Sätze zu äußern wär ich dankbar wenn man wenigstens erklärt wie es anders geht.

Zitat:

hat die Kontrolle über sein Leben verloren.
Dümmer gehts echt nicht.

Der schöne Günther 24. Nov 2018 19:31

AW: Wie verwendet man die neue TVirtualImageList
 
Zitat:

Zitat von Redeemer (Beitrag 1419062)
Wer UI-Grafiken 2018 als Rastergrafiken speichert, hat die Kontrolle über sein Leben verloren.

Hehe, basiert nicht FireMonkey noch komplett auf Bitmap-Grafiken? :duck:

jaenicke 24. Nov 2018 20:36

AW: Wie verwendet man die neue TVirtualImageList
 
Zitat:

Zitat von DieDolly (Beitrag 1419065)
Statt solche sinnlosen Sätze zu äußern wär ich dankbar wenn man wenigstens erklärt wie es anders geht.

Am sinnvollsten sind SVG-Grafiken (für die es auch eine Unit hier im Forum gibt), denn die kann man einfach in jede beliebige Größe skalieren.

DieDolly 24. Nov 2018 20:51

AW: Wie verwendet man die neue TVirtualImageList
 
Dankeschön. Werde ich irgendwann mal versuchen.

creehawk 12. Mai 2020 07:30

AW: Wie verwendet man die neue TVirtualImageList
 
Moin Moin.

Etwas älterer Thread, Problem ist trotzdem noch da:

Auf meiner Form habe ich ein TImageCollection Element plaziert und 163 PNG's in 128x128px geladen. Diese Collection wird dann in der TVirtualImageList angegeben das als Height/Width eine 32 hat. Infolge werden bei Controls wie dem Listview die optisch einwandfrei skalierten Bildchen als 32er angezeigt.

Ein solch sauber skaliertes Bild möchte ich jetzt aber auch einem TImage zuweisen, wie ja die Kernfrage des Threads hier war.

Die weiter oben angegebene Empfehlung wäre in meinem Fall
Delphi-Quellcode:
Image1.Picture.Graphic := ImageCollection1.GetSourceImage(ImageCollection1.GetIndexByName('icon'), 32,32);
Was dann aber im Ergebnis wieder eine tödliche Bildqualität produziert weil ich für das TImage ja Stretch benutzen muss. Oder?

Also hole ich mir via

Delphi-Quellcode:
VirtualImageList1.GetBitmap(Main.VirtualImageList1.GetIndexByName('BILD'),Image1.Picture.Bitmap)
das gewünschte Bild, das auch prompt und in guter Qualität kommt. Und natürlich ohne Transparenz, die ich benötige.


Frage : Wie kriege ich transparenz?

Oder : wie überrede ich TImageCollection mir das Bildchen in hübsch skaliert abzuliefern? Für was ist sonst die Property InterpolationMode gedacht?

creehawk

Uwe Raabe 12. Mai 2020 08:12

AW: Wie verwendet man die neue TVirtualImageList
 
Zitat:

Zitat von creehawk (Beitrag 1464321)
Ein solch sauber skaliertes Bild möchte ich jetzt aber auch einem TImage zuweisen, wie ja die Kernfrage des Threads hier war.

Die weiter oben angegebene Empfehlung wäre in meinem Fall
Delphi-Quellcode:

Image1.Picture.Graphic := ImageCollection1.GetSourceImage(ImageCollection1.GetIndexByName('icon'), 32,32);
Was dann aber im Ergebnis wieder eine tödliche Bildqualität produziert weil ich für das TImage ja Stretch benutzen muss. Oder?

Wieso musst du Stretch benutzen? Gib doch gleich die passende Größe bei GetSourceImage an.
Delphi-Quellcode:

Image1.Picture.Graphic := ImageCollection1.GetSourceImage(ImageCollection1.GetIndexByName('icon'), Image1.Width, Image1.Height);

DieDolly 12. Mai 2020 10:59

AW: Wie verwendet man die neue TVirtualImageList
 
Zitat:

Wieso musst du Stretch benutzen? Gib doch gleich die passende Größe bei GetSourceImage an.
Ich dachte eigentlich das wäre die Lösung.
Aber wenn ich ein 32x32 Image habe und das so mache wie du sagst, wird ein Bild reingeladen was in etwa 48x48 groß ist.

TImage auf Form und dann deine Zeile. Mehr nicht. Egal welche Größe ich als Parameter angebe. Das geladene Bild ist immer größer als das TImage. Mit TToolButtons auf einer ToolBar habe ich keine Probleme aus der VirtualImageList zu laden.

Hat die ImageCollection überhaupt mehrere Größen der Bilder? Das hat doch nur die VirtualImageList.
Irgendwie muss man diese neuen Listen doch auch auf ganz normale TImages anwenden können. Ich kann nicht überall ToolButtons hinhauen.

Uwe Raabe 12. Mai 2020 11:15

AW: Wie verwendet man die neue TVirtualImageList
 
Zitat:

Zitat von DieDolly (Beitrag 1464351)
Hat die ImageCollection überhaupt mehrere Größen der Bilder? Das hat doch nur die VirtualImageList.

Umgekehrt: Die ImageCollection hat Bilder in verschiedenen Größen - die VirtualImageList nur die Größe, die in ihren Eigenschaften Width und Height angegeben ist. Die VirtualImageList passt diese Größe aber bei DPI-Änderungen an.

Kannst du mal konkret ein Beispielprojekt anhängen, mit dem man das mal nachstellen kann?

DieDolly 12. Mai 2020 11:27

AW: Wie verwendet man die neue TVirtualImageList
 
Liste der Anhänge anzeigen (Anzahl: 1)
Ja. Siehe Anhang
Die Schleife habe ich Vcl.ImageCollection.pas genommen (TImageCollection.GetSourceImageIndex) um zu sehen, was da eigentlich das Ergebnis ist.

Uwe Raabe 12. Mai 2020 11:40

AW: Wie verwendet man die neue TVirtualImageList
 
In der Tat. GetSourceImage gibt einfach nur das nächst-größere Image zurück. In meinen Tests passte das zufällig.

Es gibt aber eine kleine Ergänzung, mit der das gewünschte Ergebnis erreicht werden kann:
Delphi-Quellcode:

type
  TImageCollectionHelper = class helper for TImageCollection
  public
    function GetScaledImage(AIndex, AWidth, AHeight: Integer): TWICImage; overload;
  end;

function TImageCollectionHelper.GetScaledImage(AIndex, AWidth, AHeight: Integer): TWICImage;
begin
  Result := GetScaledImage(GetSourceImage(AIndex, AWidth, AHeight), AWidth, AHeight);
end;


...
 Image3.Picture.Graphic := Images.GetScaledImage(Images.GetIndexByName('krankenwagen'), Image3.Width, Image3.Height);
...

DieDolly 12. Mai 2020 11:46

AW: Wie verwendet man die neue TVirtualImageList
 
Also doch nicht ganz meine Blödheit. Danke dafür.
Ich frage mich wieso sowas nicht schon direkt in der Komponente enthalten ist. Ich finde es ist logisch, dass wenn man dem Aufruf Width und Height mit gibt, man auch nach Möglichkeit diese Größe haben möchte.

DieDolly 12. Mai 2020 12:21

AW: Wie verwendet man die neue TVirtualImageList
 
Ich merke gerade, dass es eine AV am Ende des Programms gibt. Besser gesagt ein Speicherleck was mit TWICImage zu tun hat. Wie bekommt man denn das weg?
Ein Image3.Picture.Graphic.Free; im FormDestroy bringt nur noch mehr Ärger.

Uwe Raabe 12. Mai 2020 12:30

AW: Wie verwendet man die neue TVirtualImageList
 
Stimmt. SetGraphic macht ein Assign.

Delphi-Quellcode:
 img := Images.GetScaledImage(Images.GetIndexByName('krankenwagen'), Image3.Width, Image3.Height); // img: TWICImage;
 try
   Image3.Picture.Graphic := img;
 finally
   img.Free;
 end;

DieDolly 12. Mai 2020 13:18

AW: Wie verwendet man die neue TVirtualImageList
 
Ist es möglich img als var Parameter dem Aufruf mitzugeben um Zeilen zu sparen?
Weil ich ändere die Bilder öfter und nicht nur zum Programmstart.

Delphi-Quellcode:
procedure TImageCollectionHelper.GetScaledImage(AIndex, AWidth, AHeight: Integer; var Graphic: TGraphic);
var
 Img: TWICImage;
begin
 Img := GetScaledImage(GetSourceImage(AIndex, AWidth, AHeight), AWidth, AHeight);
 try
  Graphic := Img;
 finally
  Img.Free;
 end;
end;

Uwe Raabe 12. Mai 2020 13:57

AW: Wie verwendet man die neue TVirtualImageList
 
Da Graphic ein Property ist, kann man das nicht als var-Parameter übergeben. Allerdings kann man noch einen anderen Class Helper schreiben:
Delphi-Quellcode:
type
  TImageHelper = class helper for TImage
  public
    procedure UpdateImage(Source: TImageCollection; Index: Integer); overload;
    procedure UpdateImage(Source: TImageCollection; const AName: string); overload;
  end;

procedure TImageHelper.UpdateImage(Source: TImageCollection; Index: Integer);
var
  img: TWICImage;
begin
  img := Source.GetScaledImage(Index, Width, Height);
  try
    Picture.Graphic := img;
  finally
    img.Free;
  end;
end;

procedure TImageHelper.UpdateImage(Source: TImageCollection; const AName: string);
begin
  UpdateImage(Source, Source.GetIndexByName(AName));
end;


...
 Image3.UpdateImage(Images, 'krankenwagen');
...

creehawk 13. Mai 2020 15:48

AW: Wie verwendet man die neue TVirtualImageList
 
Moin Moin.

Etwas verspätet wieder am Platz, aber mein Router war abgeraucht.

Ich bedanke mich ebenfalls für die Antwort(en) und Hinweise.

creehawk

himitsu 14. Mai 2020 10:07

AW: Wie verwendet man die neue TVirtualImageList
 
Zitat:

Zitat von DieDolly (Beitrag 1464369)
Ist es möglich img als var Parameter dem Aufruf mitzugeben um Zeilen zu sparen?
Weil ich ändere die Bilder öfter und nicht nur zum Programmstart.

Nein, denn es wird nicht die Referenz kopiert,
selbst wenn es das würde, dann wäre es Fatal die kopierte Referenz (Img) sofort freizugeben,
und da es nicht möglich ist einen Property zu übergeben, sondern nur den wert aus/für dessen Getter oder Setter,
ist VAR hier sowieso nutzlos.


Du kannst aber TPicture als Parameter übergeben und darüber auf den Setter des Picture.Graphic zugreifen,
oder z.B. wie im schon gezeigten ClassHelper, an TImage oder auch an TPicture, das .Graphic in der Methode benutzen.

TurboMagic 15. Mai 2020 06:34

AW: Wie verwendet man die neue TVirtualImageList
 
Zitat:

Zitat von DieDolly (Beitrag 1464358)
Also doch nicht ganz meine Blödheit. Danke dafür.
Ich frage mich wieso sowas nicht schon direkt in der Komponente enthalten ist. Ich finde es ist logisch, dass wenn man dem Aufruf Width und Height mit gibt, man auch nach Möglichkeit diese Größe haben möchte.

Die Frage ist natürlich berechtigt.
Hast du schon mal in quality.embarcadero.com nachgeschaut ob die dort auch schon jemand gestellt hat?
Falls nicht wäre es toll, wenn du das dort als Feature Request eintragen könntest und uns hier
dann die Report Nummer verrätst, damit wir dafür stimmen können.

Grüße
TurboMagic

DieDolly 11. Jun 2020 12:27

AW: Wie verwendet man die neue TVirtualImageList
 
Gibt es sowas auch für Icon? Ich versuche mich hier gerade wieder dumm und dämlich.
Ich habe das aktuell so
Delphi-Quellcode:
type
 TImageHelper = class helper for TImage
 public
  procedure GetImage(Source: TImageCollection; Index: Integer); overload;
  procedure GetImage(Source: TImageCollection; const AName: string); overload;
 end;

type
 TImageCollectionHelper = class helper for TImageCollection
 public
  function GetScaledImage(AIndex, AWidth, AHeight: Integer): TWICImage; overload;
 end;

implementation

procedure TImageHelper.GetImage(Source: TImageCollection; Index: Integer);
var
 img: TWICImage;
begin
 img := Source.GetScaledImage(Index, Width, Height);
 try
  Picture.Graphic := img;
 finally
  img.Free;
 end;
end;

procedure TImageHelper.GetImage(Source: TImageCollection; const AName: string);
var
 Index: Integer;
begin
 Index := Source.GetIndexByName(AName);
 if Index > -1 then
  GetImage(Source, Index);
end;

function TImageCollectionHelper.GetScaledImage(AIndex, AWidth, AHeight: Integer): TWICImage;
begin
 Result := GetScaledImage(GetSourceImage(AIndex, AWidth, AHeight), AWidth, AHeight);
end;

Carsten Hölscher 21. Dez 2021 15:21

AW: Wie verwendet man die neue TVirtualImageList
 
Etwas weiter vorne war die Frage nach der Transparenz aufgekommen aber bisher nicht beantwortet. Wenn ich ein Bitmap aus der virtualcollection ziehe, dann werden die transparenten Bereiche schwarz gezeichnet (ich zeichne hier ein Symbol in ein Stringgrid).

Carsten

Carsten Hölscher 29. Dez 2021 15:58

AW: Wie verwendet man die neue TVirtualImageList
 
Falls hierzu mal wieder jemand knobelt:

Bitmap.alphaformat:=afDefined;

muss man beim TBitmap setzen, bevor man es zeichnet. Geht zumindest für meine PNG-Dateien mit transparentem Hintergrund, die in einer VirtualImagelist einsortiert sind.

Carsten

Rollo62 30. Dez 2021 09:06

AW: Wie verwendet man die neue TVirtualImageList
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1419072)
Hehe, basiert nicht FireMonkey noch komplett auf Bitmap-Grafiken? :duck:

Ja, Alles landet am Ende als Bitmap auf dem Display, Vektor-Displays müssten erst noch erfunden werden.
Genau wie die VirtualImageLists auf Ende auch nur Raster-Bitmaps sind.

Aber FMX Images basierten schon auf "MultiBitmaps", welche sinngemäß den VirtualImageLists entsprechen,
um genau diese HighDPI und "Retina" Probleme abzufangen.
Das gab es schon standardmäßig als VCL noch gar nichts mit DPI anzufangen wusste :stupid:

Uwe Raabe 30. Dez 2021 09:08

AW: Wie verwendet man die neue TVirtualImageList
 
Zitat:

Zitat von Rollo62 (Beitrag 1499820)
Vektor-Displays müssten erst noch erfunden werden.

Na ja: https://de.wikipedia.org/wiki/Vektorbildschirm

Rollo62 30. Dez 2021 09:28

AW: Wie verwendet man die neue TVirtualImageList
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1499821)
Zitat:

Zitat von Rollo62 (Beitrag 1499820)
Vektor-Displays müssten erst noch erfunden werden.

Na ja: https://de.wikipedia.org/wiki/Vektorbildschirm

Ja stimmt, aber das wollen wir doch nun wirklich nicht mehr haben, oder etwa doch ? :-D


Alle Zeitangaben in WEZ +1. Es ist jetzt 15:19 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