Link to home
Start Free TrialLog in
Avatar of dnoelpp
dnoelppFlag for Switzerland

asked on

How to dynamically invoke Create(Owner) on a component?

I have a frame TBaseFrame and two derived frames TDerivedFrameAlpha and TDerivedFrameBeta. In a form I put a TBaseFrame, but the TBaseFrame is abstract and will never be used. Only the derived frames. Because there will be a lot more derived frames than Alpha and Beta I want to use the Factory pattern to create derived frames. Like this:

function GetDerivedFrame(ClassName: String): TBaseFrame;

Now I have a detail question. Components need to be created with Create(Owner). Like this:

Button := TButton.Create(Self);

How to do this dynamically?

Like this:

// Globals.ClassMap is a TList with registered classes
Clazz := Globals.ClassMap.Get('TButton');
Button := Clazz.NewInstance();

But this only calls:

Button := TButton.Create();
ASKER CERTIFIED SOLUTION
Avatar of DMN
DMN

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of dnoelpp

ASKER

Thanks! And what happens if you call .Create(Self) on a stored class which is not a TComponent?

TAbstractComponentClass(FList.Objects[FList.IndexOf('Alpha')]).Create(Self)
Avatar of DMN
DMN

What do you mean? When you creating factory you should define one common "abstract", all other objects in factory should be objects of common class or its descendants....
What do you mean? When you creating factory you should define one common "abstract" class, all other objects in factory should be objects of common class or its descendants....
Avatar of dnoelpp

ASKER

Yes it SHOULD. But what, if you make a mistake and put erroneously an other TComponent into the TList? Code defensively and think about, what happens... :-)
Avatar of dnoelpp

ASKER

Er, an other TObject, I wanted to say!
Avatar of dnoelpp

ASKER

By the way, I tried your solution. But I get an Access Violation.

--------8<-----------8<--------------

procedure TClassMap.Add(Clazz: TClass);
begin
  ClassList.AddObject(Clazz.ClassName(), Pointer(Clazz));
end;

function TClassMap.Get(const Name: String): TClass;
var
  Index: Integer;
begin
  Index := ClassList.IndexOf(Name);
  if Index < 0 then Result := nil
  else Result := TClass(ClassList.Objects[Index]);
end;

function TClassMap.CreateComponent(
  const Name: String; Owner: TComponent
): TComponent;
var
  Clazz: TClass;
begin
  Clazz := Get(Name);
  if Clazz <> nil then begin
    Result := TComponent(Clazz).Create(Owner);
  end else begin
    Result := nil;
  end;
end;

--------8<-----------8<--------------

I replaced CreateComponent with following code. This works perfectly, but I don't have a Create(Owner) any more, and we are again at the beginning of my question.

--------8<-----------8<--------------

function TClassMap.CreateComponent(
  const Name: String; Owner: TComponent
): TComponent;
var
  Clazz: TClass;
begin
  Clazz := Get(Name);
  if Clazz <> nil then begin
    Result := Clazz.Create() As TComponent;
  end else begin
    Result := nil;
  end;
end;

--------8<-----------8<--------------

Avatar of dnoelpp

ASKER

This question is still open, I up to 100 points!
Avatar of dnoelpp

ASKER

Your solution doesn't quite work... It gives AV, but since nobody else answered I honor your work...