If you simply want to create a component whos type you know at compile time
then you should read the delphi/doc/VB2Delph.wri file to see how this is done,
it also explains control arrays and is just darn good reading anyway. This post
explains how to utilise the RTTI facilities in Delphi.
The first thing that your application needs to do is register all the classes
that you know you are going to need create at some stage in your program. This
can be done using either the RegisterClass(), RegisterClasses() or
RegisterClassAlias() functions.
eg.
procedure TForm1.FormCreate(Sender: TObject);
begin
RegisterClasses([TButton, TEdit, TMemo, TLabel]);
end;
This may seem like a limitation but then Delphi is a static language. If you
want true dynamic creation of objects in a weakly typed late bound environment
then use a dynamic language like Smalltalk. I have a feeling that Delphi uses
this registration mechanism to register all the components in the DCL when it
starts up, which allows it to create any component at design time.
Creating the components. Use the FindClass() function to return a class
reference to the component that you want to create and call its Create method.
Easy, isn't it? In the example I have typecast SomeComponent to a TControl so
that I can set its parent property (I can do this because I know that all the
classes that I registered were descendants of TControl). You need to set the
parent property of a control to make it appear on the form.
eg.
procedure TForm1.CreateClick(Sender: TObject);
begin
SomeComponent:= TComponentClass(FindClass(ClassName.Text)).Create(Self);
(SomeComponent as TControl).Parent := Self;
end;
Now that you have the component, how do you set it's properties without using
the biggest case statement in the universe? Use the GetPropInfo() function to
get the run-time type information (RTTI) structure for the property, and then
use the SetXXXXProp() set of functions to set it's value. (Note: These
functions are not documented in the Delphi help files. OO programming means
reading other peoples code and building on it, not reinventing the proverbial
wheel.) Each SetXXXXProp() function also has an equivalent GetXXXXProp()
function so you can inspect an objects property values.
eg.
procedure TForm1.SetPropertyClick(Sender: TObject);
var
PropType: PTypeInfo;
PropInfo: PPropInfo;
begin
PropInfo := GetPropInfo(SomeComponent.ClassInfo, PropertyName.Text);
PropType := PropInfo^.PropType;
case PropType^.Kind of
tkInteger:
SetOrdProp(SomeComponent, PropInfo,
StrToInt(PropertyValue.Text));
tkChar:
SetOrdProp(SomeComponent, PropInfo, Ord(PropertyValue.Text[1]));
tkEnumeration:
SetOrdProp(SomeComponent, PropInfo, GetEnumValue(PropType,
PropertyValue.Text));
tkFloat:
SetFloatProp(SomeComponent, PropInfo,
StrToFloat(PropertyValue.Text));
tkString:
SetStrProp(SomeComponent, PropInfo, PropertyValue.Text);
end;
end;
You can also set the values of Set, Class and Method properties but this can be
a little bit more complicated. I might post how to do that a little bit later.
And that's it. It's pretty amazing what you can find out by reading the VCL
source code.
This is tempting feature, but has potential for mass abuse. There is no
substitute for a good understanding of the other ways of achieving the same
things in Delphi and choosing the technique most appropriate to your design.