Recent

Author Topic: [SOLVED] Runtime component creation  (Read 3947 times)

pcurtis

  • Hero Member
  • *****
  • Posts: 951
[SOLVED] Runtime component creation
« on: February 02, 2022, 09:08:27 pm »
So, we can create a runtime component as such

Code: Pascal  [Select][+][-]
  1. var
  2.   MyComp: TDBGrid;
  3.  
  4. begin
  5.   MyComp:= TDBGrid.Create(Self);
  6.   ......
  7.  

How can I create a runtime component when the only thing
known is the classname?

So, for example, I could create a TLabel, then a TScrollbox and so on.

How to define MyComp? and how to create the component from a string holding the classname?

All components are visual.
« Last Edit: February 04, 2022, 10:27:06 am by pcurtis »
Windows 10 20H2
Laz 2.2.0
FPC 3.2.2

pcurtis

  • Hero Member
  • *****
  • Posts: 951
Re: Runtime component creation
« Reply #1 on: February 03, 2022, 02:16:07 am »
No.
Pseudo code ...
var
  MyComp: array of TUniversalBaseComponent;

  MyComp[0] := 'TLabel'.Create(nil);
  MyComp[1] := 'TMemo'.Create(nil);
  MyComp[2] := 'TDBGrid'.Create(nil);
  .....
  .....
  MyComp[0].Free;
  MyComp[1].Free;
  MyComp[2].Free;
« Last Edit: February 03, 2022, 02:42:09 am by pcurtis »
Windows 10 20H2
Laz 2.2.0
FPC 3.2.2

pcurtis

  • Hero Member
  • *****
  • Posts: 951
Re: Runtime component creation
« Reply #2 on: February 03, 2022, 03:16:16 am »
Close but

Quote
Var
  J:TClass;

.....
  J := Tmemo;  <--

--- in script land.

 If J.ClassName = StringFromScript('Tmemo') Then myComponentArray[?] := J.Create;

How can I tell "J" to be a TMemo from a string that holds 'TMemo' or a TScrollbox if the string contains 'TScrollbox'?

Or do I have to do a If .. Then for each component type? There are a lot of them and there new ones all the time.
Windows 10 20H2
Laz 2.2.0
FPC 3.2.2

pcurtis

  • Hero Member
  • *****
  • Posts: 951
Re: Runtime component creation
« Reply #3 on: February 03, 2022, 03:37:05 am »
Maybe this makes it a little clearer

Code: Pascal  [Select][+][-]
  1. var
  2.   ComponentNames: Array[0..10] of String;
  3.   Components: Array[0..10] of TClass;
  4.  
  5.   ComponentNames[0]:= 'TLabel';
  6.   ComponentNames[1]:= 'TDBGrid';
  7.   ComponentNames[2]:= 'TSomeComponent';
  8.  
  9.   for i:= 0 to 2 do
  10.     Components[i]:= ComponentNames[i].Create; <-- Here

Something like
StringToClass(ComponentNames).Create
« Last Edit: February 03, 2022, 04:11:46 am by pcurtis »
Windows 10 20H2
Laz 2.2.0
FPC 3.2.2

Handoko

  • Hero Member
  • *****
  • Posts: 5536
  • My goal: build my own game engine using Lazarus
Re: Runtime component creation
« Reply #4 on: February 03, 2022, 04:25:43 am »
Write a new function and use case statement:

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, StdCtrls;
  9.  
  10. type
  11.  
  12.   { TForm1 }
  13.  
  14.   TForm1 = class(TForm)
  15.     Button1: TButton;
  16.     procedure Button1Click(Sender: TObject);
  17.   private
  18.     function CreateClassFromName(const S: string): TControl;
  19.   end;
  20.  
  21. var
  22.   Form1: TForm1;
  23.  
  24. implementation
  25.  
  26. {$R *.lfm}
  27.  
  28. { TForm1 }
  29.  
  30. function TForm1.CreateClassFromName(const S: string): TControl;
  31. begin
  32.   case S.ToUpper of
  33.     'TLABEL':  Result := TLabel.Create(Self);
  34.     'TBUTTON': Result := TButton.Create(Self);
  35.     else
  36.       Result := nil;
  37.   end;
  38.   if Assigned(Result) then
  39.     Result.Parent := Self;
  40.   Assert(Result <> nil, 'Wrong class name for CreateClassFromName.');
  41. end;
  42.  
  43. procedure TForm1.Button1Click(Sender: TObject);
  44. begin
  45.   with CreateClassFromName('TButton') do
  46.   begin
  47.     Left    := 120;
  48.     Top     := 50;
  49.     Caption := 'Button';
  50.   end;
  51.   with CreateClassFromName('TLabel') do
  52.   begin
  53.     Left    := 60;
  54.     Top     := 80;
  55.     Caption := 'A new button has been created.';
  56.   end;
  57.   Button1.Enabled := False;
  58. end;
  59.  
  60. end.

~edit~
Because the result is TControl, I think it will be better to name it CreateControlFromName.
« Last Edit: February 03, 2022, 04:29:31 am by Handoko »

pcurtis

  • Hero Member
  • *****
  • Posts: 951
Re: Runtime component creation
« Reply #5 on: February 03, 2022, 07:14:44 am »
Thanks Hanoko, but

  case S.ToUpper of
    'TLABEL':  Result := TLabel.Create(Self);
    'TBUTTON': Result := TButton.Create(Self);
    else
      Result := nil;
  end;

Is what I am trying to avoid. The types of components is large, and is constantly growing. The list of cases would become unmanageable. There must be a way.
When the IDE reads a *.lfm file component names are just strings.
Problem is I don't see how.
Windows 10 20H2
Laz 2.2.0
FPC 3.2.2

PascalDragon

  • Hero Member
  • *****
  • Posts: 6387
  • Compiler Developer
Re: Runtime component creation
« Reply #6 on: February 03, 2022, 08:57:43 am »
When the IDE reads a *.lfm file component names are just strings.
Problem is I don't see how.

As long as your components are registered correctly so that they could also be handled with a form you can retrieve them using Classes.FindClass (which will throw an exception if the class isn't found) or Classes.GetClass (which doesn't throw an exception but returns Nil). Please note that this will only work for classes that descend from TPersistent (any TComponent descendant and thus any LCL control does that). If you need to register a descendant of TPersistent that isn't yet registered you need to use Classes.RegisterClass.

avk

  • Hero Member
  • *****
  • Posts: 826
Re: Runtime component creation
« Reply #7 on: February 03, 2022, 11:42:44 am »
It seems that, if desired, a similar system of registration can be done only for controls.

pcurtis

  • Hero Member
  • *****
  • Posts: 951
Re: [SOLVED] Runtime component creation
« Reply #8 on: February 04, 2022, 10:28:09 am »
Thanks all.
Windows 10 20H2
Laz 2.2.0
FPC 3.2.2

 

TinyPortal © 2005-2018