Qu'est-ce qu'un sous-formulaire précisément ? Et pourquoi y a-t-il parfois 2 noms pour y faire référence ?

Définition

Un sous-formulaire est "un formulaire posé sur un formulaire".
La combinaison est souvent utilisée lorsqu'il s'agit de représenter graphiquement une relation de 1 à plusieurs.

Exemple

Dans notre exemple de vidéoclub, un client effectue plusieurs locations. Vous avez donc construit une table Clients et une table Locations. Pour la saisie, il est plus pratique de tout faire tenir sur un seul écran. De cette manière, vous consultez en même temps la fiche Client, ainsi que la liste complète des locations (non seulement vous consultez les données, mais vous pouvez également les mettre à jour).

D'un point de vue technique, Access stocke dans la base 2 formulaires autonomes : le formulaire principal (ou formulaire parent), et le formulaire secondaire (ou formulaire enfant). Les 2 formulaires peuvent d'ailleurs être ouverts indépendamment. A ce stade, il n'y a pas de sous-formulaire. Ce n'est qu'à partir du moment où vous "posez" le formulaire secondaire sur le formulaire principal qu'on peut parler de sous-formulaire.

Info
Si vous êtes tentés, un prochain article pourra détailler la construction de l'exemple ci-dessus (laissez vos commentaires sur ce billet pour vous manifester !)

Sous-formulaire et rectangle container

Lorsque le formulaire secondaire est posé sur un formulaire principal, il est en fait incrusté dans un rectangle container. Ceci veut dire que :

  • le formulaire secondaire n'est plus ouvert comme formulaire autonome, mais bien cette fois comme "objet embarqué" ;
  • ce formulaire secondaire existe toujours, avec son nom propre, lorsqu'on le regarde dans la fenêtre Base de données ;
  • le rectangle container porte également un nom (en tant qu'objet du formulaire principal). Vous voyez ce nom en affichant les propriétés du rectangle container, en mode Création.
Attention
Ce qu'on appelle techniquement "sous-formulaire" est en fait le rectangle container, et non pas son formulaire embarqué. Mais il est vrai qu'on amalgame souvent les deux, ne serait-ce que parce que, visuellement, le rectangle container n'est pratiquement pas perceptible (du côté utilisateur final, en tout cas !). Par abus de langage, on dit souvent "sous-formulaire" pour désigner le rectangle container, mais aussi le formulaire embarqué...
Les 2 noms (celui du rectangle container et celui du formulaire sous-jacent) sont souvent les mêmes, mais ce n'est pas obligatoire. Vérifiez les systématiquement, notamment si vous devez écrire une formule faisant référence à un champ du formulaire embarqué. Ce type de formule s'écrit :
Forms![Nom du formulaire principal]![Nom du rectangle container].Form![Nom du champ du formulaire embarqué]
Sur l'illustration ci-dessus, on suppose que :
  • le formulaire Clients s'appelle frm Clients ;
  • le formulaire de locations s'appelle frm Clients - Locations, lorsqu'il est vu dans la fenêtre Base de données ;
  • le rectangle container se nomme sfm Locations ;
  • le formulaire embarqué contient un champ Date de location.
Par conséquent, pour référencer la date de location dans une formule quelconque, vous écririez :
Forms![frm Clients]![sfm Locations].Form![Date de location]
C'est bien le nom du rectangle container qui sert dans la formule, et pas le nom du formulaire enfant.

Dans la vidéo associée à ce billet, vous verrez comment différencier le formulaire embarqué de son rectangle container...

Du côté du programmeur...

Suite au commentaire avisé de Maxence :-), c'est vrai que le repérage entre les termes "formulaire" et "sous-formulaire" peut être délicat, selon qu'on se place du côté construction des formulaires ("je vois 2 formulaires dans la fenêtre Base de données") ou programmation ("je référence un champ du sous-formulaire") ! Je complète donc un peu l'article sous l'angle Programmation, ce qui devrait donner quelques clés supplémentaires...

Un peu de syntaxe

  • Lorsqu'un formulaire simple est ouvert (par un double-clic ou par un DoCmd.OpenForm, notamment), il peut être référencé en VBA par Forms![frm Clients] ou Forms("frm Clients"). Il est également décompté dans la liste des formulaires ouverts (la "collection" Forms), dont le nombre est obtenu par Forms.Count.
  • Suite à ce qui a été dit plus haut, on est d'accord que le champ Nom Client du formulaire sera désigné par Forms![frm Clients]![Nom Client], ou sa variante Forms("frm Clients")("Nom Client").
  • Maintenant, si le formulaire Clients contient un sous-formulaire, le "formulaire embarqué" n'est pas ouvert en tant que formulaire autonome. Ce qui veut dire que si vous ouvrez frm Clients (et aussi son sous-formulaire, nécessairement), Forms.Count vaut 1, et non pas 2.
  • Ceci implique que vous ne pouvez pas référencer le formulaire embarqué par Forms![frm Clients - Locations], ni par Forms("frm Clients - Locations"). Il faut au contraire pointer l'objet embarqué dans le rectangle container du formulaire parent (ouf !). D'où la syntaxe : Forms![frm Clients]![sfm Locations].Form. Pour compléter l'exemple plus haut, la date de location ne peut pas s'obtenir par Forms![frm Clients - Locations]![Date de location], mais bien par Forms![frm Clients]![sfm Locations].Form![Date de location].
  • A noter, tant qu'à être précis (!), que la date de location du sous-formulaire peut prendre plusieurs valeurs (il y a plusieurs enregistrements dans la grille des locations). Du coup, la formule ci-dessus renvoie la date de location de la ligne active, dans le formulaire embarqué...

La classe !

Si on se penche un peu plus en détail sur les classes d'objets impliquées...
  • Le formulaire est une instance de la classe Form.
  • Le rectangle container est une instance de la classe SubForm (encore une fois, il s'agit du rectangle uniquement, pas du formulaire embarqué dans ce rectangle).
  • Ce rectangle container fournit deux informations sur l'objet embarqué :
    le nom (chaîne de caractères) du formulaire embarqué est donné par la propriété SourceObject de la classe SubForm ;
    l'instance elle-même du formulaire embarqué est donnée par la propriété Form. C'est par cette instance que vous accédez aux données du formulaire embarqué, d'où la syntaxe .Form![Date de location].
  • Par extension, si modifiez la propriété SourceObject du rectangle container, vous remplacez le formulaire embarqué par un autre. Du style : Forms![frm Clients]![sfm Location].SourceObject = "frm Test".
Conseil
Il y a sûrement encore plein de choses à dire sur le sujet. Bah, ça fera l'objet d'autres articles sur le blog :-) Consultez les classes Form et SubForm dans l'Explorateur d'objets de Visual Basic Editor, pour plus de détails. Sinon, vous pouvez toujours laisser vos commentaires sur le blog !