Title: CREATING COMPONENTS DYNAMICALLY - PART I OF III
Question: In most cases when you are programming with Delphi you dont need to dynamically create a component, you just drop it in a form, so Delphi handles the component creation for you. However there comes the time when you need to programmatically create a component at run time.
Answer:
CLASS METHOS AND OBJECTS METHODS
Objects Methods can be called only from an instance class(e.g. myForm.Repaint), most methods that you find in Delphi components are object methods.
Class Methods is a method of a class and can be called from an object (e.g. myForm.ClassName), or it can be called wiout and instance (e.g. TForm.ClassName).
A constructor is a class method which create instances of some class, it allocates memory for the object, for example if you want to create a form at run time you can use:
myForm := TForm.Create(nil);
THE OWNER PARAMETER
All Delphi components have a common ancestor TComponent, TComponents constructor has the following declaration:
constructor Create(AOwner: TComponent); virtual;
As you can see this is a virtual method, so descendant classes can override this method to add extra functionality.
If you assign an Owner, when Delphi creates the object instance, it as added to its Owners internal owned component list, this list is uses in three events that affect the Owner:
1.- When a new component is created and added to the list, every other component of the list is notified by a call to Notification (which is a virtual method), passing a reference to the nwe component.
2.- When a component is destoyed and removed from the list, every other component of the list is notified again by a call to Notification.
3.- When the Owner is destroyed, every component in the list is destoyed (and if this components owns other components they are destroyed recursively).
The third event explains why you dont have to explicitly destroy components that are owned, Delphi does the dirty work for you.
DYNAMIC COMPONENT CREATION.
Dynamic Creation with an Owner
When you create dinamically components you can choose two ways. One way is to make another TComponent the owner of the new component. This is usually what you have to do when you need to keep track of the new components as long as your application is running, so when the owner is destroyed your component is destroyed too.
The following gives a example:
myButton := TButton.Create(Self)
with myButton do
begin
Parent := Self;
Left := 100;
Top := 100;
Caption := 'Click me';
OnClick := mycustomClick;
end;
Dynamic Creation with an explicit call to Free
The other way is to create a component with nil as its owner, but you have to take care to explicitly free the object, since there is no longer an Owner to do it.
For example:
FQuery := TQuery.Create(nil)
with FTimer do
try
//your code here
finally
FQuery.Free;
end;
SOMETHING TO BEWARE OF
Domt pass a valid owner to the constructor if a block of code where you explicitly call Free, in other words you should avoid the following in your code:
with TQuery.Create(Self) do
try
//your code here
finally
Free;
end;
This code affects performance, impacts memory and can introduce hard to find bugs.
DINAMIC FORM CREATION
Dinamically created and freed forms must be created witout owners. It is common to do the following:
//DONT do this
with myForm.Create(Application) do
try
ShowModal;
finally;
Free;
end;
At this point you may be wondering why is that I ask you to avoid this, I have seen this code over and over and it is wrong. It causes a time delay due to the notification method which is fired in every component and form owned directly or indirectly by the object Application. In a bad case where your application consists of many forms and thousands of components (which can actually be a reality), the delay can be serious.
All this can be avoided passing nil as the owner instead that Application.
Here is the right way to do it:
with myForm.Create(nil)
try
ShowModal;
finally
Free;
end;
SUMMARY
Dynamic creation is an excellent technique when you need control over when a component will be created, and it's especially useful for components that need only be instantiated for short duration, such as within the scope of a method. If a dynamically created component has an owner (specified by the AOwner parameter of the Create constructor), then that owner is responsible for destroying the component. Otherwise, you must explicitly call Free when you no longer need the component.
In my next article I will go further and will explain step by step why I told you to avoid passing a valid owner to the constructor when you Free the object in the same block of code.