ImageList&TTreeview und Windows Skalierung

Rund um die LCL und andere Komponenten
MmVisual
Beiträge: 1445
Registriert: Fr 10. Okt 2008, 23:54
OS, Lazarus, FPC: Winuxarm (L 3.0 FPC 3.2)
CPU-Target: 32/64Bit

ImageList&TTreeview und Windows Skalierung

Beitrag von MmVisual »

Hallo,

Irgendwie zerhaut es mir die Skalieung wenn ich die EXE auf WIn7/64 mit 96DPI (100%) übersetze und dann auf einem Win10/64 192DPI (200%) ausführe.
Bei 100% (Win7) sieht es gut aus, das Icon hat die korrekte Größe. Jedoch bei 200% (Win10) wird das Icon 2x vergrößert, so dass es so aus sieht als ob es doppelt so groß ist.

Das zweite:
Wenn ich nun das gleiche Projekt unter Win10 (200%) öffne und einmalig eine kleine Änderung im Formular mache, dann hat Lazarus das erkannt dass mit 192DPI übersetzt werden soll. Dann werden die Icons im Treeview auch in der richtigen Größe gezeichnet. Jedoch sind die nun mit clFuchsia vermischt. Das liegt daran, dass das Bild ein clFuchsia als Background hat, das korrekt in TImageList als Transparent erkannt wird, aber bei 192 DPI erfolgt die Berechnung in der falschen Reihenfolge, also erst vergrößern, dann Transparenz raus rechnen. richtig wäre erst transparenz raus rechnen und dann vergrößern.

Kann das jemand nachvollziehen wie ich das meine?

Lazarus 2.0.12.

Der Quellcode:

Code: Alles auswählen

Procedure TForm1.FormShow(Sender: TObject);
Var n: TTreeNode;
Begin
  AddImagesTV();
  ScaleImageList(imgL, DesignTimePPI);
  n := tvL.Items.Add(Nil, 'Node1');
  n.ImageIndex := 0;
  n.SelectedIndex := 0;
  n := tvL.Items.Add(Nil, 'Node2');
  n.ImageIndex := 1;
  n.SelectedIndex := 1;
  n := tvR.Items.Add(Nil, 'Node1');
  n.ImageIndex := 0;
  n.SelectedIndex := 0;
  n := tvR.Items.Add(Nil, 'Node2');
  n.ImageIndex := 1;
  n.SelectedIndex := 1;
end;

procedure TForm1.AddImagesTV();
Var bm: TBitmap;
  i, iW: Integer;
Begin // Kopiert Bilder für TTreeView
  imgR.Clear;
  imgR.Width := imgL.Width;
  imgR.Height := imgL.Height;
  iW := imgL.Width;
  bm := TBitmap.Create;
  For i := 0 To 1 Do
  Begin
    bm.Width := iW;
    bm.Height := iW;
    imgL.GetBitmap(i, bm);
    imgR.AddMasked(bm, FPColorToTColor(bm.Canvas.Colors[0, imgL.Height - 1]));
  End;
  FreeAndNil(bm);
End;
Viele Grüße, Markus
Win7_96.png
Win7_96.png (4.25 KiB) 1573 mal betrachtet
Win10_192_A.png
Win10_192_A.png (22.21 KiB) 1573 mal betrachtet
Win10_192_B.png
Win10_192_B.png (18.66 KiB) 1573 mal betrachtet
Demo:
LazTreeView.zip
(726.81 KiB) 44-mal heruntergeladen
Die Bilder sind alle im ZIP, auch das 16x16 Bild das in TImageList eingefügt wurde.
EleLa - Elektronik Lagerverwaltung - www.elela.de

Benutzeravatar
six1
Beiträge: 782
Registriert: Do 1. Jul 2010, 19:01

Re: ImageList&TTreeview und Windows Skalierung

Beitrag von six1 »

probiere mal folgendes:

imgR.Width := trunc(imgL.Width * (Form1.PixelPerInch /96));
imgR.Height := trunc(imgL.Height * (Form1.PixelPerInch /96));
Gruß, Michael

Benutzeravatar
Ally
Beiträge: 263
Registriert: Do 11. Jun 2009, 09:25
OS, Lazarus, FPC: Win und Lazarus Stable release
CPU-Target: x64

Re: ImageList&TTreeview und Windows Skalierung

Beitrag von Ally »

Hallo MmVisual,

so richtig gut funktioniert das Ganze erst wenn man für jede Auflösung ein eigenes Icon bereitstellt.
Die ImageList bietet dazu den Button Mehrere Größen hinzufügen... näheres dazu findest du unter https://wiki.lazarus.freepascal.org/TImageList und https://wiki.lazarus.freepascal.org/High_DPI
Wichtig dabei ist, dass die Icons einen Transparenten Hintergrund haben. Dein Icon hat einen violetten Hintergrund. Früher hat man das so gemacht und alles was violett war, mit der Farbe des Hintergrunds gezeichnet. Das ist heute glücklicherweise Vergangenheit, da echte Transparenz auch gleich geglättete Kanten an Schrägen und Rundungen ermöglicht.
Im Anhang drei entsprechende Icons zum testen.

Gruß Roland
ListIcon_200.png
ListIcon_200.png (145 Bytes) 1542 mal betrachtet
ListIcon_150.png
ListIcon_150.png (121 Bytes) 1542 mal betrachtet
ListIcon.png
ListIcon.png (98 Bytes) 1542 mal betrachtet

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: ImageList&TTreeview und Windows Skalierung

Beitrag von wp_xyz »

Also:
  • Die ImageList von Laz 2.0+ skaliert selbst. Die selbst-geschriebene Routine ScaleImagelist ist unnötig
  • ImageList.Scale auf true setzen, genauso wie LCLScaling in den Projekt-Optionen (beides hast du so richtig gemacht)
  • Vor dem Einfügen der Bilder die Auflösungen definieren, die in dem Projekt verwendet werden sollen: Im Imagelist-Editor "Neue Größe/Auflösung" jede weitere Bildgröße eintragen - die erste Auflösung ist durch ImageList.Width und .Height schon automatisch vorgegeben, man muss nur die zusätzlichen angeben. Wenn du unter 192ppi arbeitest, wäre der Wert "32" einzutragen (16px auf 200% vergrößert); du kannst nach einem zweiten Klick auch den Zwischenwert für 150% (144ppi) eintragen: "24".
  • Für die Bilder ist pro Größe eine eigene Datei nötig, wobei aber zu sagen ist, dass fehlende Bilder automatisch aus den vorhandenen Bildern berechnet werden. Da das Herunterskalieren in der Regel viel schönere Icons liefert als das Heraufskalieren, ist unbedingt ratsam, das größte Bild anzugeben (das mit 32 x 32 px), wenn du die anderen Größen hast, kannst du die auch zusätzlich eintragen. Am schnellsten geht die Übernahme der Icons wenn sich alle Ursprungs-Icons im selben Ordner befinden und gleich benannt sind, aber sich in einem größenabhängigen Namenszusatz unterscheiden. Dann kannst du mit "Mehrere Größen hinzufügen" per SHIFT- oder CTRL-Click die im Dateiauswahldialog nebeneinander liegenden Bilder einfach gemeinsam markieren und einfügen. (Navigiere zum Images-Ordner der Lazarus-Installation um zu sehen, was ich meine).
  • Wenn du wie bei der ListView sowohl große als auch kleine Icons brauchst, kannst du dieselbe ImageList verwenden, nur beachten, dass das größte Bild nun 64x64 ist!. Jedes Control mit ImageList hat eine Property ImageWidth mit Default-Wert 0 - das bedeutet: die ImageList wird bei 96ppi mit der Größe verwendet, die als ImageList.Width definiert ist. Wenn du wie bei ListView.LargeImages die großen Icons brauchst, dann trägst du bei ListView.LargeImageWidth den Wert 32 ein (denn bei 96ppi soll die "großen" Icons 32x32 haben). ListView.largeImages weist aber auf dieselbe ImageList wie bei ListView.SmallImages.
  • So große Bilder sind natürlich nicht einfach zu finden. Nach den fotorealistischen Icons früherer Zeiten sind die icons heutzutage sehr minimalistisch, die man sich aber mit minimalem Aufwand selbst zeichnen kann. Alley, der einen Großteil der Icons der jüngeren Lazarus-Versionen entworfen hat, macht dies mit Hilfe von Inkscape als Vektorgraphik, die man in jeder Größe als png exportieren kann. Aber wenn man fertige Icons möchte, empfehle ich die Seite icons8.com, von der man sich die Icons in jeder Größe bis zu max knapp 100x100 erstellen lassen kann; die Icons sind kostenlos, wenn man im Programm einen Hinweis auf die Quelle anbringt (deshalb die Fußzeile in meinem Demo-Programm...)
Im beigefügten Projekt habe ich das alles angewendet. Ich habe das auf 96ppi geschrieben, aber auf 144ppi funktioniert es genauso wie erwartet.
Dateianhänge
imagelist_toggle_viewstyle.zip
(28.4 KiB) 49-mal heruntergeladen

MmVisual
Beiträge: 1445
Registriert: Fr 10. Okt 2008, 23:54
OS, Lazarus, FPC: Winuxarm (L 3.0 FPC 3.2)
CPU-Target: 32/64Bit

Re: ImageList&TTreeview und Windows Skalierung

Beitrag von MmVisual »

Vielen Dank für die sehr ausführliche Erklärung und die vielen Tipps!

Dann werde ich mich mal an die Icons meines Projektes zu schaffen machen ... 69 Stück.
Und auch ein anderes Programm für meine Icon-Bearbeitung nutzen, was auch die echte Transparenz kann.

Ich denke die Skalierung wird in den Programmen zukünftig immer wichtiger werden, da die Bildschirmauflößungen ebenfalls wachsen. Daher macht es Sinn das einmal "richtig" zu machen.

Viele Grüße Markus

Edit: Dieser Icon Editor ist nicht schlecht: http://greenfishsoftware.org/gfie.php
EleLa - Elektronik Lagerverwaltung - www.elela.de

MmVisual
Beiträge: 1445
Registriert: Fr 10. Okt 2008, 23:54
OS, Lazarus, FPC: Winuxarm (L 3.0 FPC 3.2)
CPU-Target: 32/64Bit

Re: ImageList&TTreeview und Windows Skalierung

Beitrag von MmVisual »

Nun habe ich die Grafiken "bereinigt" und den Hintergrund auf Transpartent gestellt, eine mit 16 Pixel und eine mit 32 Pixel breite erstellt.
ImageList hat eine Auflößung von 16x16.
Nun kann ich die Datei für 16 Pixel mit "Zerteilen und hinzufügen" einfügen und es erscheinen alle 70 Bildchen in der Liste und alle sind richtig.
Als nächstes "Neue Größe/Auflößung..." um die 32px Bilder zu erzeugen
Doch nun, wie bekomme ich die 32px Bilder rein? die Funktion "Zerteilen und hinzufügen" macht aus allen 32er Bilder je 4 einzelne 16px Bilder.
Im Anhang die Bild-Dateien mit jeweils 70 Icons.

Wenn ich die ImageList List auf "32" Height/Width umstelle sind alle 16er Bilder gelöscht. Ich kann dann zwar 32px-Bilder mit "Zerteilen und hinzufügen..." rein bekommen und dann jedoch sind die 32er die Default-Bilder für 96DPI und nicht die 16px.
Ich komme da irgendwie nicht weiter.

Die EXE übersetzt mit Win7/96DPI (TImageList.Width = 16, 32px Bilder in TImageList auch vorhanden) und ausgeführt auf WIn10/192DPI, dann stürzt meine EXE ab, also verabschiedet sich und ist weg.

Vielen Dank für die Hilfe, ich habe da wohl noch ein kleines Verständnis Problem.
Grüße Markus
EleLa_btn_Test1_16.png
EleLa_btn_Test1_16.png (16.01 KiB) 1420 mal betrachtet
EleLa_btn_Test1_32.png
(27.35 KiB) Noch nie heruntergeladen
EleLa - Elektronik Lagerverwaltung - www.elela.de

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: ImageList&TTreeview und Windows Skalierung

Beitrag von wp_xyz »

Im Prinzip geht das mit dem Button "Add sliced" bzw "Zerteilen und einfügen". Aber anscheinend arbeiten da die beiden Bildgrößen gegeneinander. Ich fürchte, du musst die Bilder manuell auftrennen.

"Neue Größe/Auflösung" muss immer der erste Befehl sein, sonst werden schon vorhandene Bilder wieder gelöscht.

MmVisual
Beiträge: 1445
Registriert: Fr 10. Okt 2008, 23:54
OS, Lazarus, FPC: Winuxarm (L 3.0 FPC 3.2)
CPU-Target: 32/64Bit

Re: ImageList&TTreeview und Windows Skalierung

Beitrag von MmVisual »

Ich habe nun alle Bilder gelöscht, dann die Größe 32 hinzu gefügt, dann mit "Zerteilen und einfügen" beide Dateien gleichzeitig ausgewählt und eingefügt.
Bei Einfügen wird nicht gemeckert, jedoch die zweite Datei mit den 32px Bildern wird ignoriert. Stattdessen werden die 16px Bilder mit dem Einfügen automatisch auf die 32px gezoomt.

Hier das Bild von TImageList nach dem Einfügen und die Originaldatei im Image Editor:
Man sieht dass die Symbole anders aussehen.
Bild1.png
Bild1.png (66.25 KiB) 1376 mal betrachtet
EleLa - Elektronik Lagerverwaltung - www.elela.de

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: ImageList&TTreeview und Windows Skalierung

Beitrag von wp_xyz »

Wiegesagt, du musst die Bilderstreifen in die Einzelbilder auftrennen und diese einzeln laden. Wahrscheinlich kann irgendein Graphik-Tool genau das, aber es ist nicht schwer sich sowas selbst zu schreiben - siehe Anhang. Damit erhältst du im Unterordner output die Einzelbilder, benannt als "img<nr>_<w>x<h>.png", wobei <nr> eine laufende Nummer, <w> die Bildbreite und <h> die Bildhöhe ist.

Beim Wiedereinfügen in die ImageList nimmst du den Button "Mehrere Größen hinzufügen". Die 16er und 32er Bilder liegen in der Dateiauswahlbox direkt nebeneinander, sind also mit CTRL+Click einfach zu markieren und einzufügen.
Dateianhänge
image_splitter.zip
(46.25 KiB) 46-mal heruntergeladen

MmVisual
Beiträge: 1445
Registriert: Fr 10. Okt 2008, 23:54
OS, Lazarus, FPC: Winuxarm (L 3.0 FPC 3.2)
CPU-Target: 32/64Bit

Re: ImageList&TTreeview und Windows Skalierung

Beitrag von MmVisual »

Dankeschön für den ImageSplitter, funktioniert.
Die 2x70 Bilder konnte ich nun einfügen und ich bin gerade dabei alle Tasten in den Formularen zu ändern.

Zum Teil jedoch verwende ich 4 Bilder aus der ImageList, die ich manuell zusammen baue um dann im TSpeedButton.NumGlyps auf 4 zu setzen. Gibt es dafür eine elegantere Lösung in Lazarus?

Mein Code:

Code: Alles auswählen

  bmFilter := TBitmap.Create;
  bmFilter.TransparentColor := clBlack;
  bmFilter.Transparent := True;
  bm := TBitmap.Create;
  imges.GetBitmap(9, bm);
  bmFilter.Height := bm.Height;
  bmFilter.Width := bmFilter.Height * 4;
  bmFilter.Canvas.Draw(0, 0, bm);  // Filter blau
  imges.GetBitmap(11, bm);
  bmFilter.Canvas.Draw(bmFilter.Height, 0, bm); // Filter grau
  imges.GetBitmap(10, bm);
  bmFilter.Canvas.Draw(bmFilter.Height * 2, 0, bm); // Filter grün
  bmFilter.Canvas.Draw(bmFilter.Height * 3, 0, bm);
  FreeAndNilMm(bm);
  SetSPFilter(spFilterBauteil);
  SetSPFilter(spFilterTyp);
  FreeAndNilMm(bmFilter); 

  procedure SetSPFilter(var sp: TSpeedButton);
  begin
    sp.Caption := '';
    sp.Glyph.Assign(bmFilter);
    sp.NumGlyphs := 4;
  end;
Dieser Code funktioniert zwar und macht was er soll, aber bei Windows mit 200% Skalierung bekommt der nicht automatisch die 32px Grafik sondern nur die 16px (rechts die Filter-Taste mit "Y" ist kleiner):
Bild1.png
Bild1.png (8.2 KiB) 1329 mal betrachtet
EleLa - Elektronik Lagerverwaltung - www.elela.de

Benutzeravatar
Ally
Beiträge: 263
Registriert: Do 11. Jun 2009, 09:25
OS, Lazarus, FPC: Win und Lazarus Stable release
CPU-Target: x64

Re: ImageList&TTreeview und Windows Skalierung

Beitrag von Ally »

Hallo MmVisual,

wenn ich das richtig verstehe, möchtest du "je nach Irgendwas" einem SpeedButton ein bestimmtes Icon aus der ImageList zuweisen.
Dazu genügt es den ImageIndex entsprechend zu setzen.

Code: Alles auswählen

MeinSpeedButton.Images := ImageList1;
MeinSpeedButton.ImageIndex := 4;
Gruß Roland

MmVisual
Beiträge: 1445
Registriert: Fr 10. Okt 2008, 23:54
OS, Lazarus, FPC: Winuxarm (L 3.0 FPC 3.2)
CPU-Target: 32/64Bit

Re: ImageList&TTreeview und Windows Skalierung

Beitrag von MmVisual »

Nein, nicht 1 Image, sondern 4 Images will ich einem TSpeedButton zuweisen. Dieser Button verwendet je nach dem ob Down/Up oder Enabled/Disabled dann eines der 4 Images, die in dem einen drin sind (NumGlyp ist bei der Funktion auf 4 zu stellen) Diese 4 Images baue ich anhand 4 einzelner Images aus der ImageList zusammen und weiße dies der Taste zu.
EleLa - Elektronik Lagerverwaltung - www.elela.de

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: ImageList&TTreeview und Windows Skalierung

Beitrag von wp_xyz »

MmVisual hat geschrieben:
Fr 17. Sep 2021, 12:48
aber bei Windows mit 200% Skalierung bekommt der nicht automatisch die 32px Grafik sondern nur die 16px (rechts die Filter-Taste mit "Y" ist kleiner):
Bild1.png
Die automatische Skalierung wurde bei TBitBtn und TSpeedButton so berücksichtigt, dass eine ImageList und ein ImageIndex eingeführt wurden, so dass die Icons dieser Buttons dann mit Hilfe der Imagelist skaliert werden. Die Glyph-Eigenschaft bleibt als Property als Alternative bestehen, bekommt aber von der Skalierung nichts mit. Es gibt nur die Möglichkeiten: (1) automatische Icon-Skalierung mit Hilfe der ImageList, oder (2) verschiedene Zustandsbilder mit Hilfe von Glyph.

Um mit Hilfe der ImageList verschiedene Zustände anzuzeigen, Ich könnte mir höchstens vorstellen, dass du die MouseEnter/Exit/Down/Up -Events abfängst und dort je nach Zustand auf die Schnelle einen anderen ImageIndex zuordnest.

Ich habe selbst schon mal versucht, die Skalierung auf die Glyph-Property zu übertragen, aber der ganze Skalierungscode ist intern ziemlich kompliziert, so dass mich bald wieder der Mut verlassen hat. Wenn's dir wichtig ist, solltest du einen Bug-Report einreichen, dass Glyph nicht high-DPI fähig ist - vielleich sieht es Ondrej Pokorny, der die ganze LCL-Skalierung geschrieben hat (aber der tritt in letzter Zeit nur noch selten in Erscheinung).

Benutzeravatar
Ally
Beiträge: 263
Registriert: Do 11. Jun 2009, 09:25
OS, Lazarus, FPC: Win und Lazarus Stable release
CPU-Target: x64

Re: ImageList&TTreeview und Windows Skalierung

Beitrag von Ally »

Du musst ja nichts zusammenbauen.
Nimm einfach den Index des gewünschten Icons und weise ihn dem Button zu.

Etwa so:

Code: Alles auswählen

MeinSpeedButton.Images := ImageList1;
MeinSpeedButton.Caption := '';

if Fall = 1 then
  MeinSpeedButton.ImageIndex := 4 // blauer Trichter
else
  MeinSpeedButton.ImageIndex := 12; // roter Trichter

MmVisual
Beiträge: 1445
Registriert: Fr 10. Okt 2008, 23:54
OS, Lazarus, FPC: Winuxarm (L 3.0 FPC 3.2)
CPU-Target: 32/64Bit

Re: ImageList&TTreeview und Windows Skalierung

Beitrag von MmVisual »

Ich mache das nun so:

Die OnPaint Routine wird bei jeder Änderung automatisch angesprungen und diese paar Codezeilen werden nun für alle meine vielen Tasten verwendet.

Code: Alles auswählen

Procedure TfrmMain.spFilterPaint(Sender: TObject);
Var sp: TSpeedButton;
Begin
  If Not (Sender Is TSpeedButton) Then Exit;
  sp := TSpeedButton(Sender);
  sp.Caption := '';
  sp.Images := imges;
  If sp.Down Then
    sp.ImageIndex := 10
  Else If sp.Enabled Then
    sp.ImageIndex := 9
  Else sp.ImageIndex := 11;
end;   
EleLa - Elektronik Lagerverwaltung - www.elela.de

Antworten