Benennungskonventionen mit Formularmakros anwenden

Automatisch übersetzt von Deepl

von Gastautor Michael Höhne, 4D Entwickler (München, Deutschland)

 

Es gibt ein Feature in 4D v18 R5, das vielleicht übersehen wurde, oder zumindest bisher nicht viel Beachtung gefunden hat: Formular-Makros. Um ehrlich zu sein, hatte auch ich bis vor kurzem nicht viel Zeit mit ihnen verbracht. In diesem Blogbeitrag zeige ich Ihnen ein Makro, das Ihnen viel Zeit bei der Anwendung von Namenskonventionen für Listenfeldspalten, Spaltenüberschriften und Fußzeilen spart. Sie können es leicht an Ihre Bedürfnisse anpassen. Ein entsprechendes Repo ist auch auf Github verfügbar.

Kontext zuerst …

Wir verwenden Makros in unserer täglichen Arbeit, um die Entwicklung zu erleichtern, und das ist eine wirklich coole Funktion. Wie viele andere Unternehmen haben auch wir Kodierungsrichtlinien. Sie sind wichtig, wenn man in größeren Teams arbeitet, um den Code der anderen besser zu verstehen. Die 4D Sprache hat sich lange Zeit nicht verändert und unsere Richtlinien auch nicht. Dann kamen ORDA, Klassen und neue Syntaxen für die Deklaration von Variablen und Methoden! Es war an der Zeit, diese neuen Sprachelemente zu integrieren und eine allgemeine Überprüfung unserer internen Spezifikationen vorzunehmen. Ein Teil dieser Überprüfung waren die Namen von Formularobjekten (die allerdings nichts mit den neuen Elementen zu tun hatten). Wir sprachen über Kontrollkästchen, Optionsfelder, Felder und schließlich Listenfelder. Ich werde nicht über unsere Benennungsstile schreiben. Das Wichtigste ist, dass ein Listenfeld nicht nur einen einzigen Objektnamen hat. Es hat Namen für die Liste selbst, jede Spalte und jede Spaltenüberschrift und -fußzeile. Ein einfaches Listenfeld mit 5 Spalten hat 16 Objektnamen. Wenn Sie Namenskonventionen auf eine Listbox anwenden wollen, kann das ein langwieriger Prozess sein. Wäre es nicht schön, wenn man das automatisieren könnte?

Objektnamen für eine Listbox mit Unternehmen könnten sein:

  • listCompanies für die Liste selbst,
  • listCompaniesCol1, listCompaniesCol2, …, für die Spaltennamen,
  • listCompaniesCol1Header, listCompaniesCol2Header, …, für die Spaltenüberschriften,
  • listCompaniesCol1Footer, listCompaniesCol2Footer, …, für die Spaltenfüße.

 

Dies ist nur eine Möglichkeit, wie man es machen kann. Wenn Sie Entwickler nach ihren Präferenzen bei der Namensgebung fragen, werden Sie höchstwahrscheinlich viele verschiedene Meinungen erhalten. Es kann jedoch ein ähnliches Muster wie bei den obigen Namen geben: Alle Spalten-, Kopf- und Fußzeilennamen basieren auf dem Namen der Listbox. Diese Namen können durch ein Formularmakro zugewiesen werden!

Schnellstart

Formularmakros sind über das Kontextmenü des Formulardesigners verfügbar:

Wenn Sie noch nie mit Formularmakros gearbeitet haben, ist es wahrscheinlich, dass Ihr Kontextmenü überhaupt kein Makro-Menü enthält:

blank

In diesem Fall müssen Sie als Erstes eine formMacros.json-Datei erstellen und diese im Ordner Sources Ihres Projekts ablegen:

blank

 

Die formMacros.json-Datei definiert die Namen der Menüpunkte und die Klassen, die den Code implementieren. Die Datei, die ich in diesem Beispiel verwende, ist sehr einfach:

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

Sie weist 4D an, einen Menüpunkt namens „Rename Listbox columns“ zum Menü Macros hinzuzufügen (im Kontextmenü des Formular-Designers). Wenn Sie auf den Menüpunkt klicken, wird die Methode onInvoke einer Klasse namens „RenameListboxColumns“ aufgerufen (dazu gleich mehr). Die Datei formMacros.json wird einmal beim Laden des Projekts gelesen. Änderungen am Inhalt werden erst beim erneuten Laden des Projekts auf die Benutzeroberfläche angewendet. Wenn Sie die Datei formMacros.json gerade erstellt haben, schließen Sie Ihr Projekt und öffnen Sie es erneut, um das Menü Makros im Formulardesigner anzuzeigen. Ausführliche Informationen über Formularmakros finden Sie hier.

Formularmakros sind Klassen

Die Implementierung eines Formularmakros befindet sich innerhalb einer Klasse. Die Eigenschaft „class“ in der Makrodefinition („class“: „RenameListboxColumns“) definiert den Namen des Makros. Damit unser Makro etwas tun kann, müssen wir diese Klasse erstellen:

blank

Um zu sehen, ob es funktioniert, fügen Sie den folgenden Code hinzu:

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

Wenn Sie im Menü Makros die Option „Listbox-Spalten umbenennen“ auswählen, sollten Sie die Warnmeldung erhalten:

blank

Dies ist eine grundlegende Prüfung, um sicherzustellen, dass alles korrekt eingerichtet ist. Um einen möglichen Fallstrick aufzuzeigen, ändern Sie den Code in:

// 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 ("Hallo Welt!")

Wählen Sie erneut das Menü „Listbox-Spalten umbenennen“:

blank

4D lädt die Klassendefinition nur einmal. Sie können die Implementierung der Klassenmethoden ändern, aber neue Methoden oder Änderungen an Methodenparametern sind nicht verfügbar, bis Sie das Projekt neu laden. Das ist etwas unpraktisch, aber man gewöhnt sich daran. Nach dem Neuladen des Projekts funktioniert der Code einwandfrei.

Hinzufügen von Funktionen

Jetzt, da Sie wissen, wie man ein Formularmakro einrichtet, können wir ein paar Funktionen hinzufügen! Die Anzeige einer Hello World-Meldung ist zwar nett, aber es wäre sinnvoll, wenn ein Makro mit dem Namen „Rename Listbox columns“ mehr tun würde. Zum Beispiel Spalten umbenennen.

Die Methode onInvoke übergibt ein Objekt namens $editor. Dieses Objekt enthält Informationen über das Formular, an dem Sie gerade arbeiten. currentSelection ($editor.editor.currentSelection) enthält die Objektnamen aller ausgewählten Objekte. Wenn Sie kein Objekt ausgewählt haben, ist es leer.

currentPage ($editor.editor.currentPage ) enthält alle Objekte , die sich auf der aktuellen Formularseite befinden. form ($editor.editor.form) enthält das gesamte Formular. Diese Objekte sind einfach Teile der JSON-Deklaration des Formulars. Wenn Sie sich einen Überblick über die Objektstrukturen verschaffen wollen, öffnen Sie einfach die form.4DForm-Datei, an der Sie gerade arbeiten, in einem Texteditor.

Da wir die Objektnamen der Spalten der Listbox, der Spaltenköpfe und der Fußzeilen umbenennen wollen, wird die Hauptanwendungslogik wie folgt aussehen:

  • Schleife durch die ausgewählten Objekte. Führen Sie für jedes gefundene Listenfeld die folgenden Schritte aus:
    • Durchlaufen Sie die Spalten der Listbox und berechnen Sie die Objektnamen für jede Spalte, jede Spaltenüberschrift und jede Fußzeile anhand eines bestimmten Musters.
    • Wenn einer der berechneten Objektnamen bereits im Formular verwendet wird, wird der Umbenennungsprozess abgebrochen und dem Benutzer eine Fehlermeldung angezeigt.
    • Andernfalls benennen Sie das Objekt um.

 

Beginnen wir mit dem ersten Thema:

  • Führen Sie eine Schleife durch die ausgewählten Objekte. Führen Sie für jedes gefundene Listenfeld die zuvor beschriebenen Schritte aus:

// 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)

Dieser Code stimmt mit dem Satz überein (Schleife durch die ausgewählten Objekte, Prüfung auf Listenfelder und Umbenennung ihrer Spalten). Aber wie erkennen wir ein Listenfeld? Setzen wir einen Haltepunkt in den Code und untersuchen ihn:

blank

Jedes Objekt hat eine Eigenschaft type. Für ein Listenfeld wird diese auf „listbox“ gesetzt. Dies ist dasselbe, was Sie sehen, wenn Sie die Datei form.4dform in einem Texteditor öffnen:

blank blank

// Check if the form object is a listbox
Function isListbox($formObject: Object)->$isListbox: Boolean
$isListbox :=($formObject.type="listbox")Ziemlich einfach! Natürlich könnte man diesen Einzeiler auch direkt in onInvoke einfügen, anstatt eine neue Methode zu deklarieren, aber nach rund 30 Jahren objektorientierter Entwicklung bin ich es gewohnt, kleine Methoden zu erstellen. Es hilft, leicht verständlichen und leicht zu wartenden Code zu schreiben.

Da wir nun wissen, wie man ein Listenfeld identifiziert, können wir den nächsten Schritt tun:

  • Führen Sie eine Schleife durch die Spalten der Listbox und berechnen Sie die Objektnamen für jede Spalte, jede Spaltenüberschrift und jede Fußzeile anhand eines bestimmten Musters.

// 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 . ( . ; . +"Kopfzeile") := +1setObjectName$colheader $colname
$index$index

End for each

Die Umbenennung eines Objekts sollte nicht zu doppelten Objektnamen führen.

  • Wenn einer der berechneten Objektnamen bereits im Formular verwendet wird, brechen Sie den Umbenennungsprozess ab und zeigen dem Benutzer eine Fehlermeldung an.
  • Andernfalls benennen Sie das Objekt um.

// 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( : ; : ) ( # . ) ( . ( . . ; )) ("Objektname " +" bereits verwendet. Umbenennung abgebrochen.") $formObject Object $newObjectName Text
If$newObjectName$formObjectname
IfThisisObjectNameUsedInFormThiseditorform $newObjectName
ALERT$newObjectName
ABORT // abort further processing
Else
$formObject. :=name$newObjectName
End if
End if

Die Prüfung auf einen vorhandenen Objektnamen erfolgt mit einigen weiteren Methoden: isObjectNameUsedInForm, isObjectNameUsedInPage, und isObjectNameUsedInListbox. Sie sind in dem endgültigen Beispiel enthalten, das auf Github verfügbar ist. Es enthält auch ein Formular, das Sie zum Testen des Makros verwenden können:

blank

Formularmakros in der täglichen Arbeit verwenden

Wenn die Implementierung eines Formularmakros spezifisch für ein einzelnes Projekt ist, dann macht es durchaus Sinn, es direkt zu diesem Projekt hinzuzufügen. Aber Makros wie dieses können in jedem Projekt nützlich sein, das Formulare enthält. Sie können die Klasse natürlich in jedes Projekt kopieren und die Makrodefinition zu jeder formMacros.json-Datei hinzufügen, aber es ist einfacher, stattdessen eine Komponente zu erstellen.

Eine Formularmakrokomponente ist nichts anderes als ein 4D Projekt mit einer formMacros.json Datei und den darin definierten Klassen. Der einzige Unterschied besteht darin, dass Sie eine Komponente erstellen und sie in den entsprechenden Komponentenordner Ihres Projekts oder in den Komponentenordner der 4D Anwendung legen, damit sie standardmäßig in allen Projekten verfügbar ist.

Wenn Sie nur das Makro verwenden möchten und sich nicht um die Implementierung kümmern: Das Beispiel auf GitHub enthält die kompilierte Komponente im Ordner Build.

Michael Höhne
Michael begann im Alter von 15 Jahren mit der Programmierung von BASIC und fuhr mit reinem Maschinencode, Assembler, Pascal, C, JAVA, C# und schließlich 4D fort. Er verwendet seit den frühen 90er Jahren objektorientierte Sprachen und ist sehr froh, dass 4D in diese Richtung geht. Nachdem er von 1998 bis 2001 bei verschiedenen Unternehmen, darunter auch Microsoft, gearbeitet hat, hat er sich seither stark für Microsoft-Technologien engagiert und wurde viermal als MVP für Microsoft Dynamics CRM ausgezeichnet (von 2007 bis 2010). Seit er Microsoft verlassen hat, war er jahrelang freiberuflich tätig und gründete sein eigenes Unternehmen, Stunnware. Michael begann 2018 mit 4D zu entwickeln. Heute ist er Leiter des Münchner Entwicklungsteams bei der knk Business Software AG und hauptberuflicher 4D Entwickler.