Search code examples
inheritancedynamiccontrolslazarusrtti

Lazarus. How to invoke inherited method of dynamically created instance?


I've searched this and that and didn't find my situation. I have some variable of a type TCustomControl:

var fcontrol:TCustomControl;

Then I use some RTTI magic to create instance of different classes-descendants of TCustomControl:

constructor TFGControl.Create(TheOwner: TComponent; control: string);    
    var classofcontrol:string; class_ref: TPersistentClass;
begin
  case control of 'formspec': classofcontrol:='TPanel';
                     'label': classofcontrol:='TLabel';
                    'button': classofcontrol:='TSpeedButton';
  end;

  class_ref:=GetClass(classofcontrol);

  fcontrol:=TCustomControl(class_ref.Create); 

So, after this I have fcontrol point to instance of desired class. And can assign some methods of it (given that those was described as needed) like this:

  with fcontrol as class_ref do
       begin
            Parent:=Parent;
            if control='formspec' then
               begin
                    Width:=400;
                    Height:=300;
                    Color:=clGray;
               end
            else
                begin
                     top:=20;
                     left:=20;
                     Width:=50;
                     Height:=20;
                     Caption:=control+' - '+inttostr(Parent.ControlCount);
                     Font.Color:=clwhite;
                     Color:=clRed;
                end;

            OnMouseDown:=@MouseDown;
            OnMouseUp:=@MouseUp;
            OnMouseMove:=@MouseMove;
            OnClick:=@Click;   

And it works just great.

But then I want those dynamically created controls to use different Paint methods. I want my newly created instances to use the Paint method of it's ancestors, e.g if class_ref.ClassName is "TPanel" then I want fcontrol to look like TPanel; and if class_ref.ClassName is "TLabel" then I want fcontrol to be drawn like a common label.

The problem is fcontrol is declared as TCustomControl and if I write like this:

            OnPaint:=@Paint;

I can see that it (substitution) works. But what I'm supposed to put inside my new Paint method to invoke Tpanel.Paint if fcontrol is really a TPanel; and TLabel.Paint if fcontrol is really a TLabel?

Regards!


Solution

  • with fcontrol as class_ref do

    This is not a valid type-cast, nor is it even needed. If you want to set a property dynamically, you can use RTTI instead.

    OnPaint:=@Paint;

    That will only work for actual TCustomControl-derived objects, so use the is operator to check that:

    if fControl is TCustomControl then
      TCustomControl(fControl).OnPaint:=@Paint;