Solved

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

Posted on 2001-06-19
9
357 Views
Last Modified: 2013-11-23
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();
0
Comment
Question by:dnoelpp
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 6
  • 3
9 Comments
 
LVL 4

Accepted Solution

by:
DMN earned 100 total points
ID: 6208528
It's is a very simple demo below:

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

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

type
  TAbstractComponent=class(TComponent)
    procedure Whoami; virtual; abstract;
  end;
  TAbstractComponentClass=class of TAbstractComponent;

  TComponentAlpha=class(TAbstractComponent)
    procedure Whoami; override;
  end;

  TComponentBeta=class(TAbstractComponent)
    procedure Whoami; override;
  end;

  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    FList:TStrings;
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TComponentAlpha.WhoAmI;
begin
  ShowMessage('Alpha');
end;

procedure TComponentBeta.WhoAmI;
begin
  ShowMessage('Beta');
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FList := TStringList.Create; //Creating factory
  try
    FList.AddObject('Alpha',pointer(TComponentAlpha));
    FList.AddObject('Beta',pointer(TComponentBeta));

    // Now we will create Alpha by name, next Beta.
    with TAbstractComponentClass(FList.Objects[FList.IndexOf('Alpha')]).Create(Self) do
      begin
        WhoAmI; // Should be Alpha, it's Alpha component, not Abstract...
        Free;
      end;

    with TAbstractComponentClass(FList.Objects[FList.IndexOf('Beta')]).Create(Self) do
      begin
        WhoAmI; // Should be Beta...
        Free;
      end;

  finally
    FList.Free; // Destroying factory
  end;
end;

end.

---------------->8---------------------------

Hope this helps...
0
 
LVL 3

Author Comment

by:dnoelpp
ID: 6209229
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)
0
 
LVL 4

Expert Comment

by:DMN
ID: 6213337
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....
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 4

Expert Comment

by:DMN
ID: 6213338
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....
0
 
LVL 3

Author Comment

by:dnoelpp
ID: 6213357
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... :-)
0
 
LVL 3

Author Comment

by:dnoelpp
ID: 6213363
Er, an other TObject, I wanted to say!
0
 
LVL 3

Author Comment

by:dnoelpp
ID: 6213388
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<--------------

0
 
LVL 3

Author Comment

by:dnoelpp
ID: 6226934
This question is still open, I up to 100 points!
0
 
LVL 3

Author Comment

by:dnoelpp
ID: 6289119
Your solution doesn't quite work... It gives AV, but since nobody else answered I honor your work...
0

Featured Post

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…

752 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question