Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi SpeedButton - kein Bild? (https://www.delphipraxis.net/76069-speedbutton-kein-bild.html)

MarLe 29. Aug 2006 13:48


SpeedButton - kein Bild?
 
Mit folgender Prozedur möchte ich auf einem SpeedButton ein Bild,
aus einer Anwendung, Verknüpfung etc. (Icon) anzeigen lassen
(ohne eine Icon/Bitmap-Datei speichern zu müssen).

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  IconIndex: Word;
  ImageHandle: HIcon;
  TmpBMP: TBitmap;
  TmpIcon : TIcon;
begin
  if Edit1.Text <> '' then
  begin
    IconIndex := 0;
    ImageHandle := ExtractAssociatedIcon(hInstance, PChar(Edit1.Text), IconIndex);
    if LongInt(ImageHandle) <> 0 then
    begin
      TmpBMP := TBitmap.Create;
      TmpIcon := Icon.Create;
      TmpBMP.Width := Icon.Width;
      TmpBMP.Height := Icon.Height;
      try
        TmpIcon.Handle := ImageHandle;
        TmpBMP.Canvas.Draw(0, 0, TmpIcon);
        SpeedButton1.Glyph.Handle := LoadBitmap(hInstance, PChar(TmpBMP));
      finally
        TmpBMP.Free;
        TmpIcon.Free;
      end;
      Memo1.Lines.Add('Icon gefunden');
    end
    else
      Memo1.Lines.Add('kein Icon gefunden');
  end;
end;
Der SpeedButton bleibt aber bildlos.
Zu dem Thema hab ich schon einiges im Forum gelesen,
mittlerweile hab ich schon so viel rumprobiert dass ich den Wald vor lauter Bäume nicht mehr sehe ;-))).
vllt. hat auch jemand eine bessere (resourenschonende) Variante im Petto

Gruss MarLe

Martin K 29. Aug 2006 14:30

Re: SpeedButton - kein Bild?
 
Du setzt die Größe des Bitmaps auf die Größe des Icons, obwohl das Icon noch leer ist.

Versuche mal:
Delphi-Quellcode:
TmpBMP := TBitmap.Create;
TmpIcon := Icon.Create;
try
  TmpIcon.Handle := ImageHandle; //erst zuweisen
  TmpBMP.Width := Icon.Width; //dann die Größe anpassen
  TmpBMP.Height := Icon.Height;
  TmpBMP.Canvas.Draw(0, 0, TmpIcon);
  //usw.
Bin mir nicht sicher, ob es dann klappt - aber evtl. könnte das die Lösung sein :roll:

MarLe 29. Aug 2006 14:41

Re: SpeedButton - kein Bild?
 
Hab's so probiert, hat aber am Problem nicht's geändert, trotzdem Danke.

Martin K 29. Aug 2006 15:02

Re: SpeedButton - kein Bild?
 
So, hab mal fix was gebastelt :coder:

Ist es das, was Du suchst?

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  ICO: TIcon;
  Large, Small: HIcon;
begin
  ExtractIconEx(PChar(Edit1.Text), 0, Large, Small, 1);
  ICO := TIcon.Create;
  try
    ICO.Handle := Small; //oder Large, wenn du das große Symbol willst
    SpeedButton1.Glyph.Width := ICO.Width;
    SpeedButton1.Glyph.Height := ICO.Height;
    SpeedButton1.Glyph.Canvas.Draw(0, 0, ICO);
  finally
    ICO.Free;
  end;
end

MarLe 30. Aug 2006 08:02

Re: SpeedButton - kein Bild?
 
War bisher immer der Meinung ich müsste ein Bitmap zuweisen?!?.
Da ich mich nicht nur auf EXE/DLL beschränken will verwende ich ExtractAssociatedIcon.
Sinnvoll ist auch noch jeweils das Bild zurückzusetzen ansonsten überlappen
sich die Bilder bei mehrmaliger Zuweisung.

Super funktioniert Danke - anbei leicht geänderte Code für andere "Unwissende"

Delphi-Quellcode:
procedure TForm1.Button4Click(Sender: TObject);
var
  ICO: TIcon;
  Large, Small: HIcon;
  IconIndex: Word;
begin
  ICO := TIcon.Create;
  try
    IconIndex := 0;
    ICO.Handle := ExtractAssociatedIcon(hInstance, PChar(Edit1.Text), IconIndex);
    SpeedButton1.Glyph := nil;
    SpeedButton1.Glyph.Width := ICO.Width;
    SpeedButton1.Glyph.Height := ICO.Height;
    SpeedButton1.Glyph.Canvas.Draw(0, 0, ICO);
  finally
    ICO.Free;
  end;
end;

Martin K 30. Aug 2006 13:15

Re: SpeedButton - kein Bild?
 
Der Glyph eines SpeedButtons ist auch ein Bitmap.
Durch die Funktion Canvas.Draw kann allerdings jede beliebige Graphik auf den Glyph, also das Bitmap, gemalt werden - dies kann ein Icon, Bitmap, JPEG-Bild oder was auch immer sein.
Dadurch wird auch die Zuweisung SpeedButton1.Glyph := nil; überflüssig, da das Bitmap mit Canvas.Draw komplett übermalt wird. Ein Überlappen kann nicht entstehen, da der Glyph - also das Bitmap - vorher auf die Größe des Icons gesetzt wurde.

MarLe 30. Aug 2006 13:20

Re: SpeedButton - kein Bild?
 
Das kann ich jetzt so nicht bestätigen.
Ohne die Zeile

Delphi-Quellcode:
SpeedButton1.Glyph := nil;
wird das letzte Bild über das erste gelegt, ich sehe also noch die Bildreste?!?

Neutral General 30. Aug 2006 13:23

Re: SpeedButton - kein Bild?
 
Zitat:

Zitat von MarLe
Das kann ich jetzt so nicht bestätigen.
Ohne die Zeile

Delphi-Quellcode:
SpeedButton1.Glyph := nil;
wird das letzte Bild über das erste gelegt, ich sehe also noch die Bildreste?!?

Nein es entstehen keine Bildreste. Das ist das gleich, wie wenn du eine Datei ausschneidest, in einen Ordner reinkopierst wo schon eine Datei mit dem Namen ist und du ersetzen klickst.. Danach ist auch nichts mehr von der alten Datei übrig und du musst sie auch nicht vorher löschen ;)

Gruß
Neutral General

MarLe 30. Aug 2006 13:26

Re: SpeedButton - kein Bild?
 
Ich würde Euch ja glauben, aber die Praxis zeigt mir noch Bildreste bei obigen Code?!?

DGL-luke 30. Aug 2006 13:31

Re: SpeedButton - kein Bild?
 
also ich kann sowieso kaum glauben, was ich hier sehe:

Delphi-Quellcode:
    SpeedButton1.Glyph := nil;
    SpeedButton1.Glyph.Width := ICO.Width;
    SpeedButton1.Glyph.Height := ICO.Height;
    SpeedButton1.Glyph.Canvas.Draw(0, 0, ICO);
Man nillt einen Instanzenzeiger und greift dann darauf zu - halte ich für sehr gefährlich.
Lieber so:

Delphi-Quellcode:
    SpeedButton1.Glyph := nil;
    SpeedButton1.Glyph := TBitmap.Create;
    SpeedButton1.Glyph.Width := ICO.Width;
    SpeedButton1.Glyph.Height := ICO.Height;
    SpeedButton1.Glyph.Canvas.Draw(0, 0, ICO);
Damit hat man definitiv ein neues Bild als Glyph erstellt, und es sollte auch keine Bildreste geben, sobald man einmal Invlaidate/Refresh/Repaint aufgerufen hat.

MarLe 30. Aug 2006 13:44

Re: SpeedButton - kein Bild?
 
Aha, kein Problem wenn das die sauberste Lösung darstellt.

DGL-luke 30. Aug 2006 13:56

Re: SpeedButton - kein Bild?
 
Tja, das kommt drauf an. Wenn bereits ein Bild da ist, muss man erstmal überlegen, ob es auch anderswo noch verwendet wird. Wenn nicht, kann man es ohne Probleme überschreiben. Man kann dann sowohl das nillen als auch das Neu-Erzeugen weglassen. Ansonsten sollte man es freigeben, damit es nicht als Speicherleiche rumtreibt.

MarLe 30. Aug 2006 14:08

Re: SpeedButton - kein Bild?
 
Du verwirrst mich jetzt wieder ein bisschen.
Muss ich nach dem Zuweisen des Bildes zusätzlich noch irgendwas unter finally freigeben???

Um das Bild generell wieder sauber loszuwerden reicht dann ein

Delphi-Quellcode:
SpeedButton1.Glyph := nil;

Martin K 30. Aug 2006 16:26

Re: SpeedButton - kein Bild?
 
Sauber freigeben kannst du mit:
Delphi-Quellcode:
FreeAndNil(SpeedButton1.Glyph);
Allerdings gibt es hier eine Exception, wenn dem Glyph noch kein Bitmap zugeordnet ist.
Außerdem sollte alles sauber freigegeben werden, wenn die Form - zu der der SpeedButton gehört - freigegeben wird, also wenn dein Programm beendet wird.

Diese Lösung halte ich nicht für besonders gut:
Delphi-Quellcode:
    SpeedButton1.Glyph := nil;
    SpeedButton1.Glyph := TBitmap.Create;
    SpeedButton1.Glyph.Width := ICO.Width;
    SpeedButton1.Glyph.Height := ICO.Height;
    SpeedButton1.Glyph.Canvas.Draw(0, 0, ICO);
Wenn noch Bildreste da sind, kannst du auch vorher einfach die Größe des Bitmaps auf 0 stellen, dann sollte nichts mehr vom alten Bild übrig sein:
Delphi-Quellcode:
    SpeedButton1.Glyph.Width := 0;
    SpeedButton1.Glyph.Height := 0;
    SpeedButton1.Glyph.Width := ICO.Width;
    SpeedButton1.Glyph.Height := ICO.Height;
    SpeedButton1.Glyph.Canvas.Draw(0, 0, ICO);

Hawkeye219 30. Aug 2006 18:32

Re: SpeedButton - kein Bild?
 
Zitat:

Zitat von Martin K
Sauber freigeben kannst du mit:
Delphi-Quellcode:
FreeAndNil(SpeedButton1.Glyph);

Martin, diesen Code hast du nicht getestet, stimmts? Der Compiler meiner Delphi-Version wollte die Zeile jedenfalls nicht...

Zitat:

Allerdings gibt es hier eine Exception, wenn dem Glyph noch kein Bitmap zugeordnet ist.
Warum sollte es in diesem Fall eine Exception geben?


Noch eine Anmerkung zur Funktion ExtractAssociatedIcon: diese erwartet im zweiten Parameter einen Zeiger auf einen Zeichenpuffer. Sie liefert in diesem Puffer den vollständigen Pfad- und Dateinamen der ausführbaren Datei zurück, in dem das Icon gefunden wurde. Die Übergabe eines dynamischen Strings oder gar einer String-Eigenschaft (Edit1.Text) wird somit früher oder später zu Abstürzen führen. Richtiger wäre es, einen Puffer geeigneter Größe bereitzustellen, diesen mit dem gewünschten Dateinamen zu füllen und schließlich den Puffer an die Funktion zu übergeben:

Delphi-Quellcode:
var
  buf : array [0..max_path] of char;
begin
  buf := 'yourfile.exe';
  ExtractAssociatedIcon(hInstance, buf, IconIndex);
end;
Gruß Hawkeye

Martin K 30. Aug 2006 19:16

Re: SpeedButton - kein Bild?
 
Zitat:

Zitat von Hawkeye219
Zitat:

Zitat von Martin K
Sauber freigeben kannst du mit:
Delphi-Quellcode:
FreeAndNil(SpeedButton1.Glyph);

Martin, diesen Code hast du nicht getestet, stimmts? Der Compiler meiner Delphi-Version wollte die Zeile jedenfalls nicht...

Sorry, stimmt ja...
Weil SpeedButton1 ein Objekt ist und keine Variable.
Aber mit:
Delphi-Quellcode:
SpeedButton1.Glyph.Free;
sollte es klappen.

Aber wie gesagt, viel Sinn macht das nicht, da der SpeedButton und somit auch Glyph zusammen mit der Form freigegeben wird.

Hawkeye219 30. Aug 2006 19:26

Re: SpeedButton - kein Bild?
 
Das ist nicht nur sinnlos, sondern führt auch beim nächsten Klick auf den Button zum Absturz der Applikation. Das Glyph-Objekt wurde vom SpeedButton erzeugt und darf auch nur von diesem freigegeben werden. Die Zuweisung

Delphi-Quellcode:
Speedbutton1.Glyph := NIL;
löscht nicht das Glyph-Objekt, sondern nur den Inhalt der Bitmap. Das Glyph-Objekt wird erst bei der Freigabe des Speedbuttons von diesem zerstört.

Gruß Hawkeye

MarLe 31. Aug 2006 12:28

Re: SpeedButton - kein Bild?
 
Hab's jetzt wie folgt umgesetzt:

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  ICO: TIcon;
  Large, Small: HIcon;
  IconIndex: Word;
  buf: array[0..max_path] of char;
begin
  ICO := TIcon.Create;
  try
    StrPCopy(buf, Edit1.Text);
    IconIndex := 0;
    ICO.Handle := ExtractAssociatedIcon(hInstance, buf, IconIndex);
    SpeedButton1.Glyph.Width := 0;
    SpeedButton1.Glyph.Height := 0;
    SpeedButton1.Glyph.Width := ICO.Width;
    SpeedButton1.Glyph.Height := ICO.Height;
    SpeedButton1.Glyph.Canvas.Draw(0, 0, ICO);
    //SpeedButton1.Refresh;
  finally
    ICO.Free;
  end;
end;
... und Bild wieder entfernen:

Delphi-Quellcode:
procedure TForm1.ButtonResetClick(Sender: TObject);
begin
  SpeedButton1.Glyph := nil;
end;
Die Bildqualität ist teilweise aber ziehmlich mies (ist mir bei vorherigen Versuchen gar nicht so aufgefallen).
Kann man da noch was machen, die sollten eigentlich so ausschauen wie z.B. auf dem Desktop.

Martin K 31. Aug 2006 13:38

Re: SpeedButton - kein Bild?
 
Ich glaub jetzt habe ich die Lösung:

Das mit der "miesen Bildqualität" liegt wohl am Alpha-Kanal der 32 Bit-Icons - das von dem alten Icon noch Reste übrig waren wenn ein neues drübergemalt wurde, liegt an der Transparenz der Icons.
Da ein leeres Bitmap immer weiß ist, bleiben die Stellen wo eine Halbtransparenz beim Alpha-Kanal des Icons ist, beim Bitmap weiß.

Lösung:
Einfach das Bitmap vorher komplett in die Farbe der Form (clBtnFace) einfärben, so wird als transparente Farbe clBtnFace verwendet und nicht mehr weiß.
Der Alpha-Kanal wird nun mit clBtnFace und nicht mehr in weiß dargestellt.

Des Weiteren verschwindet durch das Einfärben in clBtnFace das alte Bitmap komplett und es bleiben keine Reste mehr.
Somit wird die Zuweisung des Bitmaps auf NIL oder das Setzen der Größe des Bitmaps (Width und Height) auf 0 überflüssig.

Außerdem kannst Du die nicht verwendeten Variablen Large, Small: HIcon; logischerweise weglassen. :wink:

So sähe es dann aus:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  ICO: TIcon;
  IconIndex: Word;
  buf: array[0..max_path] of Char;
begin
  ICO := TIcon.Create;
  try
    StrPCopy(buf, Edit1.Text);
    IconIndex := 0;
    ICO.Handle := ExtractAssociatedIcon(hInstance, buf, IconIndex);
    SpeedButton1.Glyph.Width := ICO.Width;
    SpeedButton1.Glyph.Height := ICO.Height;
    SpeedButton1.Glyph.Canvas.Brush.Color := Color; //Farbe der Form
    SpeedButton1.Glyph.Canvas.FillRect(Rect(0, 0, SpeedButton1.Glyph.Width, SpeedButton1.Glyph.Height)); //Bitmap füllen
    SpeedButton1.Glyph.Canvas.Draw(0, 0, ICO);
  finally
    ICO.Free;
  end;
end;
... und Bild wieder entfernen:
Delphi-Quellcode:
procedure TForm1.ButtonResetClick(Sender: TObject);
begin
  SpeedButton1.Glyph.Canvas.Brush.Color := Color;
  SpeedButton1.Glyph.Canvas.FillRect(Rect(0, 0, SpeedButton1.Glyph.Width, SpeedButton1.Glyph.Height));
end;

MarLe 31. Aug 2006 14:03

Re: SpeedButton - kein Bild?
 
Die weißen Ränder sind jetzt weg, aber an der Bildqualität hat sich nicht's geändert.
z.B. wird das schwarze Verknüpfungssymbol von Windows grau dargestellt.
Hab mal gegoogelt und den Artikel
http://www.aboutvb.de/khw/artikel/khwassocicon.htm
gefunden. Da steht u.a. das die ExtractAssociatedIcon-Funktion, wie gesagt, nur bedingt brauchbar ist
und man besser auf die SHGetFileInfo-Funktion zurückgreifen sollte.

Martin K 31. Aug 2006 14:15

Re: SpeedButton - kein Bild?
 
Auch hierfür gibt es eine Lösung:
Das Bitmap verwendet das untere linke Pixel als transparente Farbe.
Bei einer Verknüpfung ist dieses Pixel schwarz, somit wird der schwarze Verknüpfungs-Pfeil transparent.
Durch die Zeile
Delphi-Quellcode:
SpeedButton1.Glyph.TransparentColor := clNone;
sollte das Problem allerdings behoben sein.

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  ICO: TIcon;
  IconIndex: Word;
  buf: array[0..max_path] of Char;
begin
  ICO := TIcon.Create;
  try
    StrPCopy(buf, Edit1.Text);
    IconIndex := 0;
    ICO.Handle := ExtractAssociatedIcon(hInstance, buf, IconIndex);
    SpeedButton1.Glyph.Width := ICO.Width;
    SpeedButton1.Glyph.Height := ICO.Height;
    SpeedButton1.Glyph.TransparentColor := clNone;
    SpeedButton1.Glyph.Canvas.Brush.Color := Color;
    SpeedButton1.Glyph.Canvas.FillRect(Rect(0, 0, SpeedButton1.Glyph.Width, SpeedButton1.Glyph.Height));
    SpeedButton1.Glyph.Canvas.Draw(0, 0, ICO);
  finally
    ICO.Free;
  end;
end;

MarLe 31. Aug 2006 14:31

Re: SpeedButton - kein Bild?
 
... ja, so funktioniert's - Danke.
Der SpeedButton muss aber mindestens 36*36 Pixel haben um das Icon
unterzubringen.
Ich werde dennoch auch noch versuchen das gleiche mit SHGetFileInfo
abbilden zu können, dann könnte man alternativ auch die kleineren Icons
verwenden. Vielleicht hat's auch schon jemand umgesetzt.

Martin K 31. Aug 2006 14:45

Re: SpeedButton - kein Bild?
 
Zitat:

Zitat von MarLe
Ich werde dennoch auch noch versuchen das gleiche mit SHGetFileInfo
abbilden zu können, dann könnte man alternativ auch die kleineren Icons
verwenden. Vielleicht hat's auch schon jemand umgesetzt.

Ja, ich:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  ICO: TIcon;
  SHFileInfo: TSHFileInfo;
begin
  ICO := TIcon.Create;
  try
    FillChar(SHFileInfo, SizeOf(SHFileInfo), #0);
    SHGetFileInfo(PChar(Edit1.Text), 0, SHFileInfo, SizeOf(SHFileInfo), SHGFI_Icon or SHGFI_SmallIcon); //SHGFI_LargeIcon für die großen Symbole
    ICO.Handle := SHFileInfo.hIcon;
    SpeedButton1.Glyph.Width := ICO.Width;
    SpeedButton1.Glyph.Height := ICO.Height;
    SpeedButton1.Glyph.TransparentColor := clNone;
    SpeedButton1.Glyph.Canvas.Brush.Color := Color;
    SpeedButton1.Glyph.Canvas.FillRect(Rect(0, 0, SpeedButton1.Glyph.Width, SpeedButton1.Glyph.Height));
    SpeedButton1.Glyph.Canvas.Draw(0, 0, ICO);
  finally
    ICO.Free;
  end;
end;

MarLe 31. Aug 2006 14:57

Re: SpeedButton - kein Bild?
 
... super, funzt auch.
Werde noch ein bisschen testen ob noch irgendwelche Macken auftauchen.

Danke - Gruss MarLe

MarLe 1. Sep 2006 12:35

Re: SpeedButton - kein Bild?
 
Wenn der SpeedButton kleiner ist als 36*36 Pixel
dann wird mit SHGFI_SmallIcon der SpeedButton total verhunzt?!?

Martin K 1. Sep 2006 14:15

Re: SpeedButton - kein Bild?
 
Jaja, das leigt denke ich mal an der Umwandlung Icon -> Bitmap.
Kann es in Deinem Fall denn nicht eine ToolBar mit ToolButtons sein?
Hier kannst Du mit einer ImageList arbeiten und das Icons kann direkt als Icons eingefügt werden.
Da dürfte so ein Problem nicht auftauchen.

Zu dem eigentlichen Problem:
Habe mir gerade mit einem Trick beholfen - nicht die sauberste Lösung, aber es funktioniert:
- Du weist dem SpeedButton schon zur Designzeit (also bevor Du kompilierst) im OI ein Bitmap zu, das die Abmessungen 16x16 Pixel hat.
- In dem Quellcode streichst Du einfach diese beiden Zeilen:
Delphi-Quellcode:
    SpeedButton1.Glyph.Width := ICO.Width;
    SpeedButton1.Glyph.Height := ICO.Height;
Dann funktioniert's !


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