Appliquer des conventions de dénomination avec les macros de formulaire

Traduit automatiquement de Deepl

par l’auteur invité Michael Höhne, développeur 4D (Munich, Allemagne)

 

Il y a une fonctionnalité dans 4D v18 R5 qui a peut-être été négligée, ou du moins qui n’a pas reçu beaucoup d’attention jusqu’à présent : Les macros de formulaire. Pour être honnête, je n’y ai pas consacré beaucoup de temps non plus, jusqu’à récemment. Dans cet article de blog, je vais vous montrer une macro qui permet de gagner beaucoup de temps lors de l’application des conventions de nommage aux colonnes des boîtes de liste, aux en-têtes de colonne et aux pieds de page. Vous pouvez facilement la modifier pour l’adapter à vos besoins. Un repo dédié est également disponible sur Github.

premier contexte …

Nous utilisons des macros dans notre travail quotidien pour faciliter le développement et c’est une fonctionnalité vraiment cool. Comme beaucoup d’autres entreprises, nous avons également des directives de codage. Elles sont essentielles lorsque l’on travaille dans des équipes plus importantes, afin de comprendre plus facilement le code des autres. Le langage 4D n’a pas changé pendant longtemps et nos directives non plus. Puis sont arrivés ORDA, les classes et de nouvelles syntaxes pour les déclarations de variables et de méthodes ! Il était temps d’intégrer ces nouveaux éléments de langage et de procéder à une révision générale de nos spécifications internes. Une partie de cette révision a porté sur les noms des objets de formulaire (bien que cela n’ait rien à voir avec les nouveaux éléments). Nous avons parlé des cases à cocher, des boutons radio, des champs et enfin des listes. Je ne vais pas écrire sur nos styles de dénomination. L’important est qu’une boîte de liste n’a pas un seul nom d’objet. Elle possède des noms pour la liste elle-même, pour chaque colonne et pour chaque en-tête et pied de colonne. Une simple zone de liste à 5 colonnes possède 16 noms d’objets. Si vous souhaitez appliquer des conventions de dénomination à une zone de liste, vous risquez de vous retrouver dans un processus fastidieux. Ne serait-il pas agréable de l’automatiser ?

Les noms d’objets pour une boîte de liste contenant des entreprises pourraient être :

  • listCompanies pour la liste elle-même,
  • listCompaniesCol1, listCompaniesCol2, …, pour les noms des colonnes,
  • listCompaniesCol1Header, listCompaniesCol2Header, …, pour les en-têtes de colonne,
  • listCompaniesCol1Footer, listCompaniesCol2Footer, …, pour les pieds de colonne.

 

Ce n’est qu’une façon possible de procéder. Si vous demandez aux développeurs quelles sont leurs préférences en matière de dénomination, vous obtiendrez très probablement de nombreuses opinions différentes. Cependant, il peut y avoir un modèle similaire aux noms ci-dessus : tous les noms de colonne, d’en-tête et de pied de page sont basés sur le nom de la boîte de liste. Ces noms peuvent être attribués par une macro de formulaire !

Démarrage rapide

Les macros de formulaire sont disponibles dans le menu contextuel du concepteur de formulaire :

Si vous n’avez jamais utilisé de macros de formulaire auparavant, il est probable que votre menu contextuel ne contienne pas de menu Macros :

blank

Dans ce cas, la première chose à faire est de créer un fichier formMacros.json et de le placer dans le dossier Sources de votre projet :

blank

 

Le fichier formMacros.json définit les noms des éléments de menu et les classes qui implémentent le code. Le fichier que j’utilise dans cet exemple est très simple :

    { "macros": { 
         "Rename Listbox columns": { 
         "class": "RenameListboxColumns" 
                } 
          } 
     }

Il indique à 4D d’ajouter un élément de menu nommé « Renommer les colonnes de la boîte de liste » au menu Macros (affiché dans le menu contextuel du concepteur de formulaire). Lorsque vous cliquez sur l’élément de menu, il appelle la méthode onInvoke d’une classe appelée « RenameListboxColumns » (nous y reviendrons). Le fichier formMacros.json est lu une fois lors du chargement du projet. Les modifications apportées au contenu ne sont pas appliquées à l’interface utilisateur avant que vous ne rechargiez le projet. Si vous avez créé le fichier formMacros.json à l’instant, fermez votre projet et ouvrez-le à nouveau pour voir le menu Macros dans le concepteur de formulaires. Des informations détaillées sur les macros de formulaire sont disponibles ici.

Les macros de formulaire sont des classes

L’implémentation d’une macro de formulaire se trouve dans une classe. La propriété « class » dans la définition de la macro (« class » : « RenameListboxColumns ») définit son nom. Pour que notre macro fasse quelque chose, nous devons créer cette classe :

blank

Pour voir si cela fonctionne, ajoutez-y le code suivant :

// Macro invoked in the form designer.
Function onInvoke($editor: Object)->$return: Object
ALERT ("Hello world !") // Return the modified page object
$return :=New object("currentPage" ; $editor.editor)

Lorsque vous sélectionnez l’option « Renommer les colonnes de la boîte de liste » dans le menu Macros, vous devriez obtenir l’alerte :

blank

Il s’agit d’un contrôle de base pour vérifier que tout est correctement configuré. Pour montrer un piège possible, changez le code en :

// Macro invoked in the form designer.
Function onInvoke($editor: Object)->$return: Object
This .showHelloWorldMessage() // Return the modified page object
$return: =New object("currentPage" ; $editor.editor)

Function
showHelloWorldMessage()
ALERT ("Hello world !")

Sélectionnez à nouveau le menu « Rename Listbox columns » :

blank

4D ne charge la définition de la classe qu’une seule fois. Vous pouvez modifier l’implémentation des méthodes de la classe, mais les nouvelles méthodes ou les modifications des paramètres des méthodes ne sont pas disponibles tant que vous n’avez pas rechargé le projet. C’est un peu gênant, mais on s’y habitue. Après avoir rechargé le projet, le code fonctionnera parfaitement.

Ajout de fonctionnalités

Maintenant que vous savez comment configurer une macro de formulaire, ajoutons quelques fonctionnalités ! Afficher un message Hello World, c’est bien, mais il serait logique qu’une macro nommée « Renommer les colonnes de la boîte de liste » fasse plus. Renommer les colonnes, par exemple.

La méthode onInvoke transmet un objet nommé $editor. Cet objet contient des informations sur le formulaire sur lequel vous travaillez actuellement. currentSelection ($editor.editor.currentSelection) contient les noms de tous les objets sélectionnés. Si vous n’en avez sélectionné aucun, il sera vide.

currentPage ($editor.editor.currentPage ) contient tous les objets qui se trouvent sur la page du formulaire en cours. form ($editor.editor.form) contient l’ensemble du formulaire. Ces objets sont simplement des parties de la déclaration JSON des formulaires. Pour avoir un aperçu de la structure des objets, il suffit d’ouvrir le fichier form.4DForm sur lequel vous travaillez dans un éditeur de texte.

Puisque nous voulons renommer les noms d’objet des colonnes de la boîte de liste, des en-têtes de colonne et des pieds de page, la logique principale de l’application sera la suivante :

  • Bouclez à travers les objets sélectionnés. Pour chaque boîte de liste trouvée, faites ce qui suit :
    • Parcourir en boucle les colonnes de la boîte de liste et calculer les noms d’objet de chaque colonne, en-tête de colonne et pied de page en fonction d’un modèle spécifique.
    • Si l’un des noms d’objet calculés est déjà utilisé dans le formulaire, il faut interrompre le processus de renommage et afficher un message d’erreur à l’utilisateur.
    • Sinon, renommez l’objet.

 

Commençons par la première rubrique :

  • Parcourir en boucle les objets sélectionnés. Pour chaque boîte de liste trouvée, effectuez les étapes décrites précédemment :

// Macro invoked in the form designer.
Function onInvoke($editor: Object)->$return: Object

var $objectName : Text
var $formObject : Object

This .editor:=$editor.editor

If (This.editor.currentSelection.length>0)
For each ($objectName; This.editor.editor)
$formObject :=This.editor.currentPage.objects[$objectName]
If (This.isListbox($formObject) )
This .renameListboxColumns($objectName; $formObject)
End if
End for each
End if

// Return the modified page object
$return :=New object("currentPage" ; This.editor.currentPage)

Ce code correspond à la phrase (boucle à travers les objets sélectionnés, vérification des boîtes de liste et renommage de leurs colonnes). Mais comment identifier une boîte de liste ? Mettons un point d’arrêt dans le code et examinons-le :

blank

Chaque objet possède une propriété type. Pour une boîte de liste, elle est définie comme « listbox ». C’est la même chose que vous voyez en ouvrant le fichier form.4dform dans un éditeur de texte :

blank blank

// Check if the form object is a listbox
Function isListbox($formObject: Object)->$isListbox: Boolean
$isListbox :=($formObject.type= "listbox")Plutôt facile ! Bien sûr, cette phrase pourrait être incluse directement dans onInvoke au lieu de déclarer une nouvelle méthode, mais après environ 30 ans de développement orienté objet, j’ai l’habitude de créer de petites méthodes. Cela aide à écrire du code facile à comprendre et à maintenir.

Maintenant que nous savons comment identifier une boîte de liste, passons à l’étape suivante :

  • Bouclez à travers les colonnes de la boîte de liste et calculez les noms d’objets pour chaque colonne, en-tête de colonne et pied de page en fonction d’un modèle spécifique.

// Renames all columns, column headers and footers based on
// the listbox object name.
Function renameListboxColumns( : ; : ) : : : :=1 ( ; . ) $lbxName Text $listbox Object

var
$col Object
var $index Integer
var $newObjectName Text
$index

For each
$col $listboxcolumns
This . ( ; + "Col "+ ( ) ) setObjectName$col $lbxNameString$index
This . ( . ; . +"Footer") setObjectName$colfooter $colname
This . ( . ; . +"Header") := +1setObjectName$colheader $colname
$index$index

End for each

Renommer un objet ne doit pas conduire à des noms d’objets en double.

  • Si l’un des noms d’objet calculés est déjà utilisé dans le formulaire, interrompez le processus de renommage et affichez un message d’erreur à l’utilisateur.
  • Sinon, renommez l’objet.

// Changes the object name of $formObject to the $newObjectName.
// If the new object name is different than the current name
// and form object with that name already exists on any page
// of the form, the processing is aborted and a message is shown in the designer.
Function setObjectName( : ; : ) ( # . ) ( . ( . . ; )) ("Nom d'objet " +" déjà utilisé. Renommage annulé.") $formObject Object $newObjectName Text
If$newObjectName$formObjectname
IfThisisObjectNameUsedInFormThiseditorform $newObjectName
ALERT$newObjectName
ABORT // abort further processing
Else
$formObject. :=name$newObjectName
End if
End if

La vérification d’un nom d’objet existant est effectuée à l’aide de quelques autres méthodes : isObjectNameUsedInForm, isObjectNameUsedInPage, et isObjectNameUsedInListbox. Elles sont incluses dans l’échantillon final disponible sur Github. Il contient également un formulaire que vous pouvez utiliser pour tester la macro :

blank

Utilisation des macros de formulaire dans votre travail quotidien

Si l’implémentation d’une macro de formulaire est spécifique à un seul projet, il est tout à fait logique de l’ajouter directement à ce projet. Mais des macros comme celle-ci peuvent être utiles dans tout projet contenant des formulaires. Vous pouvez, bien sûr, copier la classe dans chaque projet et ajouter la définition de la macro dans chaque fichier formMacros.json, mais il est plus facile de créer un composant à la place.

Un composant macro Form n’est rien d’autre qu’un projet 4D avec un fichier formMacros.json et les classes qui y sont définies. La seule différence est que vous construisez un composant et le placez dans le dossier de composants approprié de votre projet, ou vous le placez dans le dossier de composants de l’application 4D pour qu’il soit disponible dans tous les projets par défaut.

Si vous voulez juste utiliser la macro et ne pas vous soucier de l’implémentation : l’échantillon sur GitHub inclut le composant compilé dans le dossier Build.

Michael Höhne
Michael a commencé à programmer en BASIC à l'âge de 15 ans, puis en code machine pur, en assembleur, en Pascal, en C, en JAVA, en C# et enfin en 4D. Il utilise des langages orientés objet depuis le début des années 90 et est très heureux de voir 4D se diriger dans cette direction. Ayant travaillé dans plusieurs entreprises, dont Microsoft de 1998 à 2001, Michael est depuis lors profondément attaché aux technologies Microsoft et a obtenu quatre fois le titre de MVP pour Microsoft dynamics CRM (de 2007 à 2010). Depuis son départ de Microsoft, il a passé des années à travailler en freelance et a créé sa propre entreprise, Stunnware. Michael a commencé à développer avec 4D en 2018. Aujourd'hui, il est à la tête de l'équipe de développement de Munich chez knk Business Software AG et développeur 4D à plein temps.