Aller au contenu principal
Version: 20 R5 BETA

Sous-formulaire

Un sous-formulaire est un formulaire inclus dans un autre formulaire.

Terminologie

Afin de bien définir les notions mises en oeuvre avec les sous-formulaires, voici quelques définitions relatives aux termes employés :

  • Subform: a form intended for inclusion in another form, itself called the parent form.
  • Parent form: a form containing one or more subform(s).
  • Subform container: an object included in the parent form, displaying an instance of the subform.
  • Subform instance: the representation of a subform in a parent form. Cette notion est importante car il est possible d’afficher plusieurs instances d’un même sous-formulaire dans un formulaire parent.
  • List form: instance of subform displayed as a list.
  • Detail form: page-type input form associated with a list-type subform that can be accessed by double-clicking in the list.

Sous-formulaires en liste

Un sous-formulaire en liste vous permet de saisir, visualiser et modifier des données dans d’autres tables. Les sous-formulaires en liste sont généralement utilisés avec les bases de données utilisant des liens de type 1 vers N. Un sous-formulaire en liste affiche les enregistrements de la table N liée par un lien automatique de type 1 vers N. Vous pouvez disposer de plusieurs sous-formulaires provenant de différentes tables dans le même formulaire. En revanche, il n’est pas possible de placer deux sous-formulaires appartenant à la même table dans une même page de formulaire.

Par exemple, une base de gestion de contacts peut utiliser une instance de sous-formulaire en liste pour afficher tous les contacts d’une société. Bien que les contacts apparaissent dans l’écran général, l’information est en fait stockée dans la table liée. A l’aide d’un lien 1 vers N, la conception de cette base de données rend facile le stockage d’un nombre illimité de contacts pour chacune des sociétés. Avec des liens automatiques, vous pouvez permettre la saisie de données dans la table liée sans programmation.

Bien que les sous-formulaires en liste soient généralement associés aux tables N, une instance de sous-formulaire peut afficher des enregistrements de toute autre table de la base de données.

Vous pouvez également permettre à l’utilisateur de saisir des données dans le formulaire liste. Suivant la configuration du sous-formulaire, l’utilisateur pourra afficher le formulaire détaillé en double-cliquant sur un sous-enregistrement ou en utilisant les commandes d’ajout et de modification des sous-enregistrements.

4D offers three standard actions to meet the basic needs for managing subrecords: Edit Subrecord, Delete Subrecord, and Add Subrecord. Lorsque le formulaire comporte plusieurs instances de sous-formulaires, l’action s’applique au sous-formulaire ayant le focus.

Sous-formulaires en page

Les sous-formulaires en mode page peuvent afficher des données relatives à l'enregistrement courant ou toute valeur pertinente en fonction du contexte (variables, images, etc.). Il peuvent également, et c'est là leur intérêt majeur, comporter des fonctionnalités avancées et interagir avec le formulaire parent (widgets). Les sous-formulaires en page bénéficient de propriétés et d'événements spécifiques, et peuvent être entièrement contrôlés par programmation.

The page subform uses the input form indicated by the Detail Form property. A la différence d’un sous-formulaire en mode liste, le formulaire utilisé peut provenir de la même table que le formulaire parent. Il est également possible d’utiliser un formulaire projet. En exécution, un sous-formulaire en mode page dispose des caractéristiques d’affichage standard d’un formulaire entrée.

Les widgets 4D sont des objets composés prédéfinis. They are described in detail in a separate manual, 4D Widgets.

Using the bound variable or expression

You can bind a variable or an expression to a subform container object. This is very useful to synchronize values from the parent form and its subform(s).

By default, 4D creates a variable or expression of object type for a subform container, which allows you to share values in the context of the subform using the Form command (see below). However, you can use a variable or expression of any scalar type (time, integer, etc.) especially if you only need to share a single value:

  • Define a bound variable or expression of a scalar type and call the OBJECT Get subform container value and OBJECT SET SUBFORM CONTAINER VALUE commands to exchange values when On Bound Variable Change or On Data Change form events occur. This solution is recommended to synchronize a single value.
  • Define a bound variable or expression of the object type and use the Form command to access its properties from the subform. This solution is recommended to synchronize several values.

Synchronizing parent form and subform (single value)

Binding the same variable or expression to your subform container and other objects of the parent form lets you link the parent form and subform contexts to put the finishing touches on sophisticated interfaces. Imagine a subform that contains a clock displaying a static time, inserted into a parent form containing an input area:

In the parent form, both objects (input area and subform container) have the same value as Variable or Expression. It can be a variable (e.g. parisTime), or an expression (e.g. Form.parisTime).

info

To display a static time, you must use the appropriate data type for the variable or expression:

  • If you use a variable (e.g. parisTime), it must be of the text or time type.
  • If you use an expression (e.g. Form.myValue), it must contain a text value.

The text value must be formatted "hh:mm:ss".

In the subform, the clock object is managed through the Form.clockValue property.

Updating the contents of a subform

Case 1: The value of the parent form variable or expression is modified and this modification must be passed on to a subform.

parisTime or Form.parisTime changes to "12:15:00" in the parent form, either because the user entered it, or because it was updated dynamically (via the String(Current time) statement for example). This triggers the On Bound Variable Change event in the subform's Form method.

The following code is executed:

// Subform form method
If (Form event code=On Bound Variable Change) //bound variable or expression was modified in the parent form
Form.clockValue:=OBJECT Get subform container value //synchonize the local value
End if

It updates the value of Form.clockValue in the subform:

The On Bound Variable Change form event is generated:

  • as soon as a value is assigned to the variable/expression of the parent form, even if the same value is reassigned
  • si le sous-formulaire appartient à la page formulaire courante ou à la page 0.

Note that, as in the above example, it is preferable to use the OBJECT Get subform container value command which returns the value of the expression in the subform container rather than the expression itself because it is possible to insert several subforms in the same parent form (for example, a window displaying different time zones contains several clocks).

Modifying the bound variable or expression triggers form events which let you synchronize the parent form and subform values:

  • Use the On Bound Variable Change form event to indicate to the subform (form method of subform) that the variable or expression was modified in the parent form.
  • Use the On Data Change form event to indicate to the subform container that the variable or expression value was modified in the subform.

Updating the contents of a parent form

Scénario 2 : Le contenu du sous-formulaire est modifié et cette modification doit être répercutée dans le formulaire parent.

Inside the subform, the button changes the value of the Form.clockValue expression of type Text attached to the clock object. This triggers the On Data Change form event inside the clock object (this event must be selected for the object), which updates the Form.parisTime value in the main form.

The following code is executed:

// subform clock object method
If (Form event code=On Data Change) //whatever the way the value is changed
OBJECT SET SUBFORM CONTAINER VALUE(Form.clockValue) //Push the value to the container
End if

Everytime the value of Form.clockValue changes in the subform, parisTime or Form.parisTime in the subform container is also updated.

If the variable or expression value is set at several locations, 4D uses the value that was loaded last. It applies the following loading order: 1-Object methods of subform, 2-Form method of subform, 3-Object methods of parent form, 4-Form method of parent form

Synchronizing parent form and subform (multiple values)

By default, 4D binds a variable or expression of object type to each subform. The contents of this object can be read and/or modified from within the parent form and from the subform, allowing you to share multiple values in a local context.

When bound a the subform container, this object is returned by the Form command directly in the subform. Since objects are always passed by reference, if the user modifies a property value in the subform, it will automatically be saved in the object itself and thus, available to the parent form. On the other hand, if a property of the object is modified by the user in the parent form or by programming, it will be automatically updated in the subform. No event management is necessary.

For example, in a subform, inputs are bound to the Form object properties (of the subform form):

In the parent form, you display the subfom twice. Each subform container is bound to an expression which is a property of the Form object (of the parent form):

The button only creates mother and father properties in the parent's Form object:

//Add values button object method
Form.mother:=New object("lastname"; "Hotel"; "firstname"; "Anne")
Form.father:=New object("lastname"; "Golf"; "firstname"; "Félix")

When you execute the form and click on the button, you see that all values are correctly displayed:

If you modify a value either in the parent form or in the subform, it is automatically updated in the other form because the same object is used:

Using pointers (compatibility)

In versions prior to 4D v19 R5, synchronization between parent forms and subforms was handled through pointers. For example, to update a subform object, you could call the following code:

// Subform form method
If (Form event code=On Bound Variable Change)
ptr:=OBJECT Get pointer(Object subform container)
clockValue:=ptr->
End if

This principle is still supported for compatibility but is now deprecated since it does not allow binding expressions to subforms. It should no longer be used in your developments. In any cases, we recommend to use the Form command or the OBJECT Get subform container value and OBJECT SET SUBFORM CONTAINER VALUE commands to synchronize form and subform values.

Programmation inter-formulaires avancée

Communication between the parent form and the instances of the subform may require going beyond the exchange of a values through the bound variable. En effet, vous pouvez souhaiter mettre à jour des variables dans les sous-formulaires en fonction d’actions effectuées dans le formulaire parent et inversement. Si l’on reprend l’exemple du sous-formulaire de type "pendule dynamique", on peut souhaiter définir une ou plusieurs heures d’alerte par pendule.

Pour répondre à ces besoins, 4D propose les mécanismes suivants :

  • Calling of a container object from the subform using the CALL SUBFORM CONTAINER command
  • Execution of a method in the context of the subform via the EXECUTE METHOD IN SUBFORM command

The GOTO OBJECT command looks for the destination object in the parent form even if it is executed from a subform.

Commande CALL SUBFORM CONTAINER

The CALL SUBFORM CONTAINER command lets a subform instance send an event to the subform container object, which can then process it in the context of the parent form. L’événement est reçu dans la méthode de l’objet conteneur. Il peut s’agir à l’origine de tout événement détecté par le sous-formulaire (clic, glisser-déposer, etc.).

Le code de l’événement est libre (par exemple, 20000 ou -100). You can use a code that corresponds to an existing event (for example, 3 for On Validate), or use a custom code. Dans le premier cas, seuls les événements présents dans la liste des événements "cochables" des conteneurs de sous-formulaire peuvent être utilisés (cf. Liste des propriétés). Dans le second cas, le code ne doit correspondre à aucun événement formulaire existant. Il est conseillé d’utiliser une valeur négative pour avoir l’assurance que 4D n’utilisera pas ce code dans les versions futures.

For more information, refer to the description of the CALL SUBFORM CONTAINER command.

Commande EXECUTE METHOD IN SUBFORM

The EXECUTE METHOD IN SUBFORM command lets a form or one of its objects request the execution of a method in the context of the subform instance, which gives it access to the subform variables, objects, etc. Cette méthode peut en outre recevoir des paramètres.

Ce mécanisme est illustré dans le schéma suivant :

For more information, refer to the description of the EXECUTE METHOD IN SUBFORM command.

Propriétés prises en charge

Border Line Style - Bottom - Class - Detail Form - Double click on empty row - Double click on row - Enterable in list - Expression Type - Focusable - Height - Hide focus rectangle - Horizontal Scroll Bar - Horizontal Sizing - Left - List Form - Method - Object Name - Print Frame - Right - Selection mode - Source - Top - Type - Variable or Expression - Vertical Scroll Bar - Vertical Sizing - Visibility - Width