Intéressant

Création dynamique de composants (au moment de l'exécution)

Création dynamique de composants (au moment de l'exécution)

Le plus souvent, lors de la programmation dans Delphi, il n'est pas nécessaire de créer dynamiquement un composant. Si vous déposez un composant sur un formulaire, Delphi gère automatiquement la création du composant lors de la création du formulaire. Cet article explique comment créer par programmation des composants au moment de l'exécution.

Création de composant dynamique

Il existe deux manières de créer dynamiquement des composants. Une solution consiste à désigner un formulaire (ou un autre composant TComponent) en tant que propriétaire du nouveau composant. Ceci est une pratique courante lors de la construction de composants composites dans lesquels un conteneur visuel crée et possède les sous-composants. Cela garantira que le composant nouvellement créé est détruit lorsque le composant propriétaire est détruit.

Pour créer une instance (objet) d'une classe, appelez sa méthode "Create". Le constructeur Create est une méthode de classe, contrairement à pratiquement toutes les autres méthodes rencontrées dans la programmation Delphi, qui sont des méthodes objet.

Par exemple, le composant TComponent déclare le constructeur Create comme suit:

constructeur Create (AOwner: TComponent); virtuel;

Création dynamique avec les propriétaires
Voici un exemple de création dynamique, où Soi est un descendant de TComponent ou de TComponent (par exemple, une instance de TForm):

avec TTimer.Create (Self) do
commencer
Intervalle: = 1000;
Activé: = Faux;
OnTimer: = MyTimerEventHandler;
fin;

Création dynamique avec un appel explicite à Free
La deuxième façon de créer un composant est d'utiliser néant en tant que propriétaire. Notez que si vous procédez ainsi, vous devez également libérer explicitement l'objet que vous créez dès que vous n'en avez plus besoin (sinon vous allez générer une fuite de mémoire). Voici un exemple d'utilisation de nil en tant que propriétaire:

avec TTable.Create (nil) do
essayer
DataBaseName: = 'MonAlias';
TableName: = 'MyTable';
Ouvrir;
Modifier;
FieldByName ('Busy'). AsBoolean: = True;
Poster;
enfin
Libre;
fin;

Création dynamique et références d'objet
Il est possible d'améliorer les deux exemples précédents en affectant le résultat de l'appel de création à une variable locale de la méthode ou appartenant à la classe. Cela est souvent souhaitable lorsque des références au composant doivent être utilisées ultérieurement ou lorsque des problèmes de portée potentiellement causés par des blocs "Avec" doivent être évités. Voici le code de création TTimer ci-dessus, utilisant une variable de champ comme référence à l'objet TTimer instancié:

FTimer: = TTimer.Create (Self);
avec FTimer do
commencer
Intervalle: = 1000;
Activé: = Faux;
OnTimer: = MyInternalTimerEventHandler;
fin;

Dans cet exemple, "FTimer" est une variable de champ privé de la forme ou du conteneur visuel (ou quel que soit "Self"). Lors de l'accès à la variable FTimer à partir de méthodes de cette classe, il est très judicieux de vérifier si la référence est valide avant de l'utiliser. Ceci est fait en utilisant la fonction Assigned de Delphi:

si assigné (FTimer), alors FTimer.Enabled: = True;

Création dynamique et références d'objet sans propriétaires
Une variante consiste à créer le composant sans propriétaire, mais à conserver la référence pour une destruction ultérieure. Le code de construction du TTimer ressemblerait à ceci:

FTimer: = TTimer.Create (nil);
avec FTimer do
commencer

fin;

Et le code de destruction (vraisemblablement dans le destructeur du formulaire) ressemblerait à ceci:

FTimer.Free;
FTimer: = nul;
(*
Ou utilisez la procédure FreeAndNil (FTimer), qui libère une référence à un objet et remplace la référence par nil.
*)

La définition de la référence à l'objet sur nil est essentielle pour libérer des objets. L'appel de Free vérifie d'abord si la référence de l'objet est nulle ou non, et si ce n'est pas le cas, il appelle le destructeur Destroy de l'objet.

Création dynamique et références d'objets locaux sans propriétaires

Voici le code de création TTable ci-dessus, utilisant une variable locale comme référence à l'objet instable TTable:

localTable: = TTable.Create (nil);
essayer
avec localTable do
commencer
DataBaseName: = 'MonAlias';
TableName: = 'MyTable';
fin;

// Plus tard, si nous voulons spécifier explicitement la portée:
localTable.Open;
localTable.Edit;
localTable.FieldByName ('Busy'). AsBoolean: = True;
localTable.Post;
enfin
localTable.Free;
localTable: = nil;
fin;

Dans l'exemple ci-dessus, "localTable" est une variable locale déclarée dans la même méthode contenant ce code. Notez qu'après avoir libéré un objet, il est généralement très judicieux de définir la référence sur nil.

Un mot d'avertissement

IMPORTANT: ne mélangez pas un appel à Free avec le transfert d'un propriétaire valide au constructeur. Toutes les techniques précédentes fonctionnent et sont valides, mais les suivantes doivent ne se produit jamais dans votre code:

avec TTable.Create (self) do
essayer

enfin
Libre;
fin;

L'exemple de code ci-dessus introduit des performances inutiles, impacte légèrement la mémoire et présente le potentiel d'introduire des bogues difficiles à trouver. J'ai trouvé pourquoi.

Remarque: Si un composant créé dynamiquement a un propriétaire (spécifié par le paramètre AOwner du constructeur Create), ce propriétaire est alors responsable de la destruction du composant. Sinon, vous devez appeler explicitement Free lorsque vous n'avez plus besoin du composant.

Article écrit à l'origine par Mark Miller

Un programme de test a été créé dans Delphi pour chronométrer la création dynamique de 1 000 composants avec des nombres de composants initiaux variables. Le programme de test apparaît au bas de cette page. Le graphique montre un ensemble de résultats du programme de test, comparant le temps nécessaire pour créer des composants avec ou sans propriétaires. Notez qu'il ne s'agit que d'une partie du résultat. Un délai de performance similaire peut être attendu lors de la destruction de composants. Le temps nécessaire à la création dynamique de composants avec des propriétaires est de 1200% à 107960% plus lent que pour créer des composants sans propriétaires, en fonction du nombre de composants de la fiche et du composant créé.

Le programme de test

Avertissement: Ce programme de test ne dépiste pas et libère les composants créés sans propriétaires. En ne suivant ni libérant ces composants, les temps mesurés pour le code de création dynamique reflètent plus précisément le temps réel nécessaire à la création dynamique d'un composant.

Télécharger le code source

Attention!

Si vous souhaitez instancier dynamiquement un composant Delphi et le libérer explicitement ultérieurement, transmettez toujours nil en tant que propriétaire. Ne pas le faire peut entraîner des risques inutiles, ainsi que des problèmes de performances et de maintenance du code. Lisez l'article "Avertissement concernant l'instanciation dynamique des composants Delphi" pour en savoir plus…