1
votes

The below question discusses how inheritance chain between TButton and TBitBtn has changed, namely the introduction of a common ancestor, TCustomButton.

What happened to TBitBtn and TButton inheritance chain?

In the past, those who wanted graphics on their button would opt for a TBitBtn, as it offered usage of bitmap glyphs.

In more recent versions of Delphi, the standard TButton allows to specify a TImageList, for png / jpg support, while TBitBtn does not.

My (long-time) button subclass inherits from TBitBtn, and changing that would mean a potential application-wide button redesign. No time for that. I want the ability to migrate things over time, in baby steps, without deleting and re-creating buttons (chance to miss the migration of a property or an event). Optimally, pick a button, wipe its glyph, put a png in its imagelist, over.

Looking at the sources of VCL.Buttons and VCL.StdCtrls, the bulk of the work for ImageList, ImageIndex ... is done at the common ancestor, TCustomButton. TButton only publishes those properties to be used at design-time.

Great, I can simply make my TBitBtn subclass publish those same properties. The properties are now visible in the object inspector. I can select an imagelist component, even pick an image index from the available images.

And this is where things stop working: the selected image doesn't get displayed at design-time, nor at runtime. Assign a glyph, it gets displayed without any problems. I tried looking at other properties which may interfere in the painting of the png (maybe some kind of transparency option), in vain.

EDIT:

This link mentions that TBitBtn purposely disables the usage of ImageList in favor of its own drawing:

http://codeverge.com/embarcadero.delphi.graphics/tbitbtn-with-png-on-d2009/1077124

Nonetheless, any suggestions on how I can achieve my "baby steps" migration described above from bmp icons to png ones, as smoothly as possible?

Version info: 10.3.1

Thanks!

3
There is a significant difference between TBitBtn and TButton that will make your "baby steps" very hard. You see unlike standard TButton which is always showing just one image TBitBton can actually contain up to four Glyphs stored in same image. These four images are used to show different state of the button (Up, Disabled, Clicked, Down). In order to draw the needed image it uses ImageList code to extract the needed Glyph from the provided image. This makes loading of image/s to TBitBtn from image list not possible.SilverWarior
Now looking at documentation for Delphi 10.4 it seems that there were significant changes in TCustomButton class which introduces additional properties to determine Image Index for different button states essentially allowing any Button to have multiple images for multiple states.SilverWarior
So whatever "baby steps" you make in current version be aware that they could get broken when you decide to migrate to Delphi 10.4 or later. In your case I would consider upgrading to latest version of Delphi before making any changes to your custom version of TButBtn. Maybe the new changes to TCustomButton will also help you simply the code of your custom buttons.SilverWarior
right, so a migration to 10.4 will effectively allow me to alter one button at a time, with no possible side-effects across the application. That seems indeed like the optimal way to go. Now, does that make the difference between TButton and TBitBtn a historical one, or are there still any use-cases where one would choose this over that?Khorkhe
Also, if you wouldn't mind writing that up as an answer so I can accept it. Thanks!Khorkhe

3 Answers

1
votes

I tested with Delphi 10.4.1 and it works perfectly.

At first, I tought about an interposer class ot make ImageIndex and Images published. This is not even required. TBitBtn in Delphi 10.4.1 has both properties already published. I had not noticed that before !

Here is the code:

unit BitBtnInheritenceDemoMain;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Buttons,
  System.ImageList, Vcl.ImgList;

type   
  TForm1 = class(TForm)
    BitBtn1: TBitBtn;
    ImageList1: TImageList;
    procedure FormCreate(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
    // Properties could also be assigned thru object inspector
    BitBtn1.Images     := ImageList1;
    BitBtn1.ImageIndex := 1;
end;

end.
1
votes

There is a significant difference between TBitBtn and TButton that will make your "baby steps" very hard. You see unlike standard TButton which is always showing just one image TBitBtn can actually contain up to four Glyphs stored in same image. These four images are used to show different state of the button (Up, Disabled, Clicked, Down). In order to draw the needed image TBitBtn uses ImageList code to extract the needed Glyph from the provided image. This makes loading of image/s to TBitBtn from image list not possible.

Fun fact:

Did you know that in older versions of Delphi basic TButton didn't support showing any icons at all. So in the past if you wanted to have button with an icon on it you had to use TBitBtn instead.

Now looking at documentation for Delphi 10.4 it seems that there were significant changes in TCustomButton class which introduces additional properties to determine Image Index for different button states essentially allowing any Button to have multiple images for multiple states. Same goes for standard TButton in Delphi 10.4.

While this brings standard TButton functionality much closer to the one from TBitBtn there are still many cases were you would prefer to use TBitBtn instead. For instance one notable drawback of standard TButton is that you can't fully change font property of its caption like changing Color of the Button text. But this is fully supported on TBitBtn.


So whatever "baby steps" you make in current version be aware that they might get broken when you decide to migrate to Delphi 10.4 or later.

In your case I would strongly advice you to consider upgrading to the latest version of Delphi before making any changes to your custom version of TBitBtn. Maybe the new changes to TCustomButton and subsequently to TBitBtn itself will also help you simplify the code of your custom buttons.

0
votes

I am using Delphi XE5, in my case I tried with this code and it works:

ImageList1.GetBitmap(0, BitBtn1.Glyph);