Custom button inherited from TButton does not show
Asked Answered
P

1

8

I am converting a large project to Firemonkey and we have some custom buttons, which does not show on the form. I have isolated the problem to a very simple project:

With the code below, on both mobile and desktop (using default new applications in Delphi XE6), creating tTestButton1 works fine, but tTestButton2 does not show on the form. How is that possible?

type
tTestButton1 = class(TButton);
tTestButton2 = class(tTestButton1);

tMainForm = class(TForm)
private
  fTestButton: TButton;
public
  constructor Create(aOwner: TComponent); override;
end;

constructor tMainForm .Create(aOwner: TComponent);
begin
  inherited;

//  fTestButton := tTestButton1.Create(Self); // this works fine (used instead of next line)
  fTestButton := tTestButton2.Create(Self);  //this button does not show up
  fTestButton.Text := 'Test';
  fTestButton.Parent := Self;
  fTestButton.Visible := True;
  fTestButton.Position.X := 20;
  fTestButton.Position.Y := 20;
end;
Priscella answered 16/9, 2014 at 9:4 Comment(9)
+1 excellent question, wonderful repro code, if only they were all this goodBookish
Can reproduce the same in Delphi XE3.Traver
And XE7. Looks like an FMX bug, hard though it may be to believe that could be the case ......Bookish
This is by design. A visual component must have a style registered. Otherwise it will not be shown. Internally the compiler looks for the first derived class only.Margretmargreta
It shows up if you name the derived class TButton!! So perhaps the workaround is that you give all of your derived buttons the same class name!! Ha ha!Bookish
@LURD So why is a direct subclass of TButton OK, but not a grandchild?Bookish
@DavidHeffernan, it can find ButtonStyle in the first example, but not in the second where TestButton1Style is not registered.Margretmargreta
@DavidHeffernan, it is discussed here, codeverge.com/embarcadero.delphi.firemonkey/….Margretmargreta
I wish Embarcadero had chosen to show at least something on the screen when the style was not found. It is really unpredictable behavior that the control disappears completely. It took many hours of debugging to isolate the problem to the simple code above. I wish I could have used them productive instead...Priscella
B
4

The problem is that the control does not have a style registered for it. So the natural solution is for you to do that.

But that's a reasonable amount of work, and I expect that all you really want to do is arrange that the control uses the same style as TButton. Achieve that like so:

type
  TButtonBase = class(TButton)
  protected
    function GetDefaultStyleLookupName: string; override;
  end;

function TButtonBase.GetDefaultStyleLookupName: string;
begin
  Result := 'Buttonstyle';
end;

Now derive your classes from TButtonBase.

type
  tTestButton1 = class(TButtonBase);
  tTestButton2 = class(tTestButton1);

Instead of looking for styles based on the control's class name, classes derived from TButtonBase will use the style named Buttonstyle.

Bookish answered 16/9, 2014 at 9:53 Comment(5)
In the real code I now set StyleLookup in the constructor of "tTestButton1" and both classes now show up as buttons on the form. Nice when there is a simple solution to a problem :-)Priscella
@Priscella That's pretty much exactly what I suggested. I inserted an extra class TButtonBase to give you scope to derive other button classes if you wish to do so. But perhaps tTestButton1 was already that base class. I appreciate that you've simplified the real code to a small and simple reproduction for the benefit of asking the question. And once again I cannot commend you more highly on doing that.Bookish
A much more elegant solution is to override the DefaultStyleLookupName method to return 'ButtonStyle'.Clyte
@Mike I'm sure you are right. Could you explain why it's more elegant that way please.Bookish
@Mike OK. I think I can see why.Bookish

© 2022 - 2024 — McMap. All rights reserved.