The first part is about how the Glyph
property of TSpeedButton
works, as you seem to be asking that as a part of your problem.
While TSpeedButton
's FGlyph
field is declared as an TObject
, you will find that in code it actually contains an instance of TButtonGlyph
.
In the TSpeedButton
constructor you will find the line FGlyph := TButtonGlyph.Create;
and the setter and getter for the Glyph
property of TSpeedButton
look like this:
function TSpeedButton.GetGlyph: TBitmap;
begin
Result := TButtonGlyph(FGlyph).Glyph;
end;
procedure TSpeedButton.SetGlyph(Value: TBitmap);
begin
TButtonGlyph(FGlyph).Glyph := Value;
Invalidate;
end;
So TSpeedButton
's Glyph
property actually accesses the Glyph
property of the TButtonGlyph
class, an internal class defined in Vcl.Buttons
, which encapsulates - among other things - the actual TBitMap
with following property
property Glyph: TBitmap read FOriginal write SetGlyph;
So the TButtonGlyph
has an TBitMap
field FOriginal and the setter is implemented like this:
procedure TButtonGlyph.SetGlyph(Value: TBitmap);
var
Glyphs: Integer;
begin
Invalidate;
FOriginal.Assign(Value);
if (Value <> nil) and (Value.Height > 0) then
begin
FTransparentColor := Value.TransparentColor;
if Value.Width mod Value.Height = 0 then
begin
Glyphs := Value.Width div Value.Height;
if Glyphs > 4 then Glyphs := 1;
SetNumGlyphs(Glyphs);
end;
end;
end;
At this point it is important how accepts .PNG is defined:
- Being able to use the PNG image, with some trade-offs.
- Fully supports PNG images
For the latter I believe the answer of Remy Lebeau is the best advice. The internal class TButtonGylph
makes OOP approaches like inheritance with png capable class impossible as far as I see. Or even go further and do as Remy suggests in a comment: third-party component.
If trade-offs are acceptable however:
Note the FOriginal.Assign(Value);
which can already help in using PNGs, as TPNGImage
's AssignTo
procedure knows how to assign itself to a TBitMap
.
With the above known about the Glyph
property, we can simply assign a PNG with the following code:
var
APNG: TPngImage;
begin
APNG := TPngImage.Create;
try
APNG.LoadFromFile('C:\Binoculars.png');
SpeedButton1.Glyph.Assign(APNG);
finally
APNG.Free;
end;
Due to differences between bitmap and PNG this might however ignore alpha channel of the PNG, but based on an answer from Andreas Rejbrand there is a partial solution for that:
var
APNG: TPngImage;
ABMP: TBitmap;
begin
APNG := TPngImage.Create;
ABMP := TBitmap.Create;
try
APNG.LoadFromFile('C:\Binoculars.png');
ABMP.SetSize(APNG.Width, APNG.Height);
ABMP.Canvas.Brush.Color := Self.Color;
ABMP.Canvas.FillRect(Rect(0, 0, ABMP.Width, ABMP.Height));
ABMP.Canvas.Draw(0, 0, APNG);
SpeedButton1.Glyph.Assign(APNG);
finally
APNG.Free;
ABMP.Free;
end;
end;