La vérité ne sort pas toujours de la bouche des enfants... méfiez-vous en !

On a l'habitude de dire que la vérité sort de la bouche des enfants, mais c'est loin d'être vrai. En matière d'informatique les enfants peuvent même être de faux amis et vous tendre des pièges honteux !

Dans Firemonkey chaque composant visuel peut être le parent d'autres composants visuels. On en retrouve l'arborescence grâce à la propriété Children et ChildrenCount. Quand on affecte un Parent à un composant, celui-ci se retrouve dans les Children de son Parent. Il hérite ainsi de son positionnement et de ses attributs d'affichage (largeur / hauteur de la zone de cliping, opacité, rotation, effets éventuels, ...).

Pour rappel, la propriété Owner d'un composant gère la mémoire allouée pour chaque composant et l'arborescence pour la création / destruction des objets. On retrouve l'arborescence correspondante dans la propriété Components de chaque composant, y compris pour les composants non visuels directement rattachés aux fiches. La propriété Parent quant à elle est utilisée pour l'affichage des composants visuels dans la VCL comme dans Firemonkey.

Ce qui est vrai partout dans Firemonkey ne l'est plus pour les enfants d'un descendant de TCustomScrollBox...

Quand un composant a pour parent une scrollbox, il n'apparaît pas directement dans ses enfants, ce qui peut perturber lorsqu'on cherche à parcourir l'arborescence des composants sans se méfier.

En fait une scrollbox a pour enfants un TLayout et un TScrollContent. Les composants dont le parent est la scrollbox sont associés à son TScrollContent. On peut y accéder en regardant les enfants de Children[1]. Cependant cette façon de faire est non seulement moche mais en plus non maintenable sur le long terme !
Nous ne sommes pas à l'abris de changements de hiérarchie ou d'ordre dans les descendants de TCustomScrollBox sur de futures versions de Firemonkey... et allez donc relire du code où un Children[1] apparaît quand vous ne savez pas à quoi il correspond.

J'en parle et j'insiste sur ce point car je viens encore de trouver cette erreur de conception sur des exemples disponibles sur GitHub.

Pour obtenir la liste des composants visuels d'une scrollbox, vous ne devez pas regarder Children[1].Children mais les enfants de sa propriété Content. Celle-ci pointe vers son TScrollContent et donc son Children[1] (pour le moment).

Ne vous laissez donc pas piéger quand vous ajoutez par programmation des composants à une scroll box et désirez ensuite lire cette liste. C'est comme ça que vous devez faire :

if (ScrollBox1.Content.ChildrenCount > 0) then
  for i := 0 to ScrollBox1.Content.ChildrenCount - 1 do
    Memo1.Lines.Add(ScrollBox1.Content.Children[i].Name + ':' + ScrollBox1.Content.Children[i].ClassName);

et non comme ça :

if (ScrollBox1.ChildrenCount > 0) then
  for i := 0 to ScrollBox1.ChildrenCount - 1 do
    Memo1.Lines.Add(ScrollBox1.Children[i].Name + ':' + ScrollBox1.Children[i].ClassName);

Bien entendu vous pouvez aussi utilisez les énumérateurs disponibles si vous ne voulez pas utiliser une boucle à indice classique. Enumérateur qui ne fonctionne que sur Children et non sur Content dans la version Delphi 10.2 Tokyo.

if (ScrollBox1.ChildrenCount > 0) then
  for obj in ScrollBox1.Children do
    Memo1.Lines.Add(obj.Name + ':' + obj.ClassName);

 


Mug Toucan DX dans la baie de RioMug Toucan DX dans la baie de Rio