II. Gérer des composants créés dynamiquement▲
Créer des composants dynamiquement, c'est bien ; savoir s'en servir, c'est mieux !
C'est pour répondre à cette problématique que j'ai écrit cette 2e page. En effet, nous venons de voir comment créer des composants dynamiquement, mais ils ne sont pas vraiment fonctionnels. Car, avec la méthode que je vous ai donnée, on est confronté à plusieurs problèmes : tous les boutons ont les mêmes propriétés ; ces propriétés ne peuvent plus être changées par la suite ; c'est le même événement qui est exécuté pour chaque bouton.
II-A. Première méthode : enregistrer chaque bouton▲
Quand j'ai débuté, la première solution a laquelle j'ai pensé, c'est d'utiliser une variable globale (de type TButton). On peut modifier les propriétés de cette variable, ce qui modifiera l'aspect du bouton. Le problème, c'est quand on a créé plusieurs composants : on n'a le pouvoir que sur le dernier. On peut contourner cette limite en créant une variable de type : array of TButton. Ce tableau doit être dynamique (lui aussi !), car on ne sait pas à l'avance le nombre de boutons que l'on créera. Voici un exemple de cette technique :
var
ListeBoutons: array
of
TButton;
Nombre: integer
= 0
;
procedure
TForm1.Button1Click(Sender: TObject);
begin
inc(Nombre);
SetLength(ListeBoutons, Nombre+1
);
ListeBoutons[Nombre] := TButton.Create(self
);
with
ListeBoutons[Nombre] do
begin
Parent := Self
;
Left := Nombre*20
;
Width := 20
;
Caption := IntToStr(Nombre);
end
;
end
;
procedure
TForm1.Button2Click(Sender: TObject);
var
i: Integer
;
begin
for
i := 1
to
Nombre do
ListeBoutons[i].Top := ListeBoutons[i].Top + 10
;
end
;
Quand l'utilisateur appuie sur Button1, on agrandit le tableau d'un élément (qui servira pour le bouton). Puis, on crée simplement le bouton et on modifie ses propriétés. Ainsi chaque bouton est enregistré dans le tableau. Button2 montre comment modifier les propriétés ultérieurement. Il suffit donc de connaître le numéro du bouton pour pouvoir le contrôler.
II-B. Deuxième méthode : rechercher les boutons▲
Il existe plusieurs fonctions qui permettent d'accéder à un composant quelconque. Il existe notamment la propriété ComponentCount qui renvoie le nombre de composants qu'il y a sur la fiche. Pour accéder à un composant, on utilise Components.
Remarque issue de l'aide de Delphi : « Pratiquement, Components s'utilise avec ComponentCount pour des traitements itératifs. Néanmoins, gardez à l'esprit que la propriété ComponentCount d'un composant correspond au nombre d'éléments de la liste Components de ce composant. La propriété ComponentCount est supérieure d'une unité à l'indice du dernier élément de Components, car l'indice du premier élément est toujours 0 ».
Pour reprendre le même exemple, pour faire descendre les composants de la fiche, on procède comme suit :
procedure
TForm1.Button2Click(Sender: TObject);
var
i: Integer
;
begin
for
i := 0
to
pred(ComponentCount) do
if
Components[i] is
TControl then
with
(Components[i] as
TControl)do
Top := Top + 10
;
end
;
Les TComponents n'ont pas de propriété Top, car certains composants n'ont pas à être affichés. On regarde d'abord si le composant est un TControl (il a donc la propriété Top) et on le considère ensuite ainsi pour modifier sa propriété. De la même façon, on peut savoir si le composant est un TButton. C'est astuce permet le contrôle de tous les composants d'une fiche, quels qu'ils soient.
Cependant, vous remarquerez que, dans ce dernier exemple, tous les boutons sont déplacés, même ceux qui n'ont pas été créés dynamiquement. Il nous faut trouver quelque chose pour les distinguer. Ce peut-être leur position dans la fiche, leur propriété Cpation ou n'importe quoi d'autre. Je vous conseille la propriété Tag, car elle est commune à TOUS les composants, et elle n'influe pas sur le programme. Ainsi, les procédures précédentes deviennent :
procedure
TForm1.Button1Click(Sender: TObject);
begin
with
TButton.Create(self
) do
begin
Parent := Self
;
Left := Random(400
);
Top := Random(400
);
Tag := 1
;
end
;
end
;
procedure
TForm1.Button2Click(Sender: TObject);
var
i: Integer
;
begin
for
i := 0
to
pred(ComponentCount) do
if
Components[i].Tag = 1
then
(Components[i] as
TControl).Top := (Components[i]as
TControl).Top + 10
;
end
;
Ici, tous les composants créés dynamiquement ont leur propriété Tag mise à 1. Cette valeur est bien sûr arbitraire, vous pouvez prendre n'importe laquelle. On aurait pu également utiliser la propriété Name du composant, qui permet, elle, de stocker un string.
D'un point de vue théorique, la propriété Tag ne sert à rien. Il est noté dans l'aide : « La propriété Tag n'a pas de rôle prédéfini. Cette propriété est proposée afin de pouvoir stocker une valeur entière ou elle peut être transtypée sur n'importe quelle valeur 32 bits, comme une référence de composant ou un pointeur ». En fait, puisque chaque composant possède cette propriété, elle peut servir à donner une valeur au composant. Cela permet par exemple de repérer les composants, comme on vient de le faire. Elle peut aussi remplacer des variables entières, relatives à un composant. Avec l'habitude, elle peut donc devenir très intéressante. On peut ainsi regrouper des composants par cette propriété.
II-C. Différencier les événements▲
Hé, oui ! Si vous avez suivi ce cours, vous aurez remarqué que tous les boutons créés font la même chose. Et là encore, il faut différencier les composants. La méthode reste la même : récupérer la propriété Tag (ou Name, ou autre chose) et agir en conséquence.
procedure
TForm1.MaProcedure(Sender: TObject);
begin
case
(Sender as
TComponent).Tag of
1
: {instructions...}
;
2
: {instructions...}
;
{ autres valeurs ... }
else
{instructions par défaut...}
;
end
;
end
;
Ce n'est qu'un exemple… Vous pouvez faire comme bon vous semble. Par exemple, il est possible d'effectuer des calculs en fonction de la valeur Tag et de retourner le résultat. Il est souvent intéressant de numéroter les composants. Pensez à utiliser une variable globale pour cela.