Applicare le convenzioni di denominazione con le macro del modulo

Tradotto automaticamente da Deepl

dell’autore ospite Michael Höhne, sviluppatore 4D (Monaco, Germania)

In 4D v18 R5 c’è una funzione che forse è stata trascurata, o almeno non ha ricevuto molta attenzione finora: Le macro di forma. A dire il vero, anch’io non ci avevo dedicato molto tempo fino a poco tempo fa. In questo post del blog, vi mostrerò una macro che consente di risparmiare molto tempo nell’applicazione delle convenzioni di denominazione alle colonne delle caselle di riepilogo, alle intestazioni delle colonne e ai piè di pagina. È possibile modificarla facilmente per adattarla alle proprie esigenze. Su Github è disponibile anche un repo dedicato.

contesto prima …

Nel nostro lavoro quotidiano usiamo le macro per facilitare lo sviluppo ed è una funzione davvero interessante. Come molte altre aziende, anche noi abbiamo delle linee guida per la codifica. Sono essenziali quando si lavora in team più grandi per comprendere meglio il codice degli altri. Il linguaggio 4D non è cambiato per molto tempo e nemmeno le nostre linee guida. Poi sono arrivati ORDA, le classi e le nuove sintassi per le dichiarazioni di variabili e metodi! Era giunto il momento di incorporare questi nuovi elementi del linguaggio e di effettuare una revisione generale delle nostre specifiche interne. Una parte di questa revisione riguardava i nomi degli oggetti dei moduli (anche se totalmente estranei alle novità). Abbiamo parlato di caselle di controllo, pulsanti di opzione, campi e infine caselle di riepilogo. Non scriverò dei nostri stili di denominazione. La cosa importante è che una casella di riepilogo non ha un solo nome di oggetto. Ha nomi per l’elenco stesso, per ogni colonna e per l’intestazione e il piè di pagina di ogni colonna. Un semplice elenco con 5 colonne ha 16 nomi di oggetti. Se si vogliono applicare le convenzioni di denominazione a una casella di riepilogo, ci si può trovare in un processo noioso. Non sarebbe bello poterlo automatizzare?

I nomi degli oggetti per una casella di riepilogo contenente aziende potrebbero essere:

  • elencoAziende per l’elenco stesso,
  • listCompaniesCol1, listCompaniesCol2, …, per i nomi delle colonne,
  • listAziendeCol1Header, listAziendeCol2Header, …, per le intestazioni delle colonne,
  • listCompaniesCol1Footer, listCompaniesCol2Footer, …, per i piè di pagina delle colonne.

Questo è solo un modo possibile per farlo. Se si chiede agli sviluppatori quali sono le loro preferenze di denominazione, si otterranno probabilmente molte opinioni diverse. Tuttavia, potrebbe esserci uno schema simile ai nomi di cui sopra: tutti i nomi delle colonne, delle intestazioni e dei piè di pagina sono basati sul nome della casella di riepilogo. Questi nomi possono essere assegnati da una macro di Form!

Avvio rapido

Le macro del modulo sono disponibili nel menu contestuale del designer del modulo:

Se non avete mai usato le macro dei moduli, è probabile che il vostro menu contestuale non includa affatto il menu Macro:

blank

In questo caso, la prima cosa da fare è creare un file formMacros.json e collocarlo nella cartella Sources del progetto:

blank

Il file formMacros.json definisce i nomi delle voci di menu e delle classi che implementano il codice. Il file che sto usando in questo esempio è molto semplice:

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

Indica a 4D di aggiungere una voce di menu denominata “Rinomina colonne Listbox” al menu Macros (visualizzato nel menu contestuale del designer del modulo). Quando si fa clic sulla voce di menu, viene richiamato il metodo onInvoke di una classe chiamata “RenameListboxColumns” (di cui si parlerà più avanti). Il file formMacros.json viene letto una volta al caricamento del progetto. Le modifiche al contenuto non vengono applicate all’interfaccia utente finché non si ricarica il progetto. Se avete creato il file formMacros.json in questo momento, chiudete il progetto e riapritelo per vedere il menu Macro nel designer Form. Informazioni dettagliate sulle macro dei form sono disponibili qui.

Le macro dei form sono classi

L’implementazione di una macro di un modulo si trova all’interno di una classe. La proprietà “class” nella definizione della macro (“class”: “RenameListboxColumns”) ne definisce il nome. Per far sì che la nostra macro faccia qualcosa, dobbiamo creare questa classe:

blank

Per vedere se funziona, aggiungete il seguente codice:

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

Quando si seleziona “Rinomina colonne Listbox” nel menu Macro, si dovrebbe ottenere l’avviso:

blank

Si tratta di un controllo di base per verificare che tutto sia impostato correttamente. Per mostrare una possibile insidia, modificare il codice 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 ("Hello world!")

Selezionate nuovamente il menu “Rinomina colonne Listbox”:

blank

4D carica la definizione della classe una sola volta. È possibile modificare l’implementazione dei metodi della classe, ma i nuovi metodi o le modifiche ai parametri dei metodi non sono disponibili finché non si ricarica il progetto. Questo è un po’ scomodo, ma ci si abitua. Dopo aver ricaricato il progetto, il codice funzionerà perfettamente.

Aggiunta di funzionalità

Ora che sapete come impostare una macro Form, aggiungiamo qualche funzionalità! Visualizzare un messaggio di Hello World è bello, ma sarebbe logico che una macro chiamata “Rinomina colonne Listbox” facesse di più. Rinominare le colonne, ad esempio.

Il metodo onInvoke passa un oggetto chiamato $editor. Questo oggetto contiene informazioni sul modulo su cui si sta lavorando. currentSelection ($editor.editor.currentSelection) contiene i nomidegli oggetti selezionati. Se non è stato selezionato alcun oggetto, sarà vuoto.

currentPage ($editor.editor.currentPage ) contiene tutti gli oggetti che si trovano nella pagina del modulo corrente. form ($editor.editor.form) contiene l’intero modulo. Questi oggetti sono semplicemente parti della dichiarazione JSON del modulo. Per avere una visione d’insieme delle strutture degli oggetti, basta aprire il file form.4DForm su cui si sta lavorando in un editor di testo.

Poiché vogliamo rinominare i nomi degli oggetti delle colonne delle caselle di riepilogo, delle intestazioni delle colonne e dei piè di pagina, la logica principale dell’applicazione sarà:

  • Eseguire il loop degli oggetti selezionati. Per ogni casella di riepilogo trovata, procedere come segue:
    • Eseguire il loop delle colonne della casella di riepilogo e calcolare i nomi degli oggetti per ogni colonna, intestazione di colonna e piè di pagina in base a uno schema specifico.
    • Se uno dei nomi degli oggetti calcolati è già utilizzato nel modulo, interrompere il processo di ridenominazione e visualizzare un messaggio di errore all’utente.
    • Altrimenti, rinominare l’oggetto.

Cominciamo con il primo argomento:

  • Eseguire il loop degli oggetti selezionati. Per ogni casella di riepilogo trovata, eseguire i passaggi descritti in precedenza:

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

Questo codice corrisponde alla frase (eseguire il loop degli oggetti selezionati, verificare la presenza di caselle di riepilogo e rinominare le loro colonne). Ma come si identifica una casella di riepilogo? Inseriamo un punto di interruzione nel codice e indaghiamo:

blank

Ogni oggetto ha una proprietà type. Per una casella di riepilogo, questa è impostata su “listbox”. È la stessa che si vede aprendo il file form.4dform in un editor di testo:

blank blank

// Check if the form object is a listbox
Function isListbox($formObject: Object)->$isListbox: Boolean
$isListbox :=($formObject.type="listbox")Abbastanza facile! Naturalmente, questo passaggio potrebbe essere incluso direttamente in onInvoke invece di dichiarare un nuovo metodo, ma dopo circa 30 anni di sviluppo orientato agli oggetti, sono abituato a creare piccoli metodi. Aiuta a scrivere codice facile da capire e da mantenere.

Ora che sappiamo come identificare una casella di riepilogo, facciamo il passo successivo:

  • Eseguire il loop delle colonne della casella di riepilogo e calcolare i nomi degli oggetti per ogni colonna, intestazione di colonna e piè di pagina in base a uno schema specifico.

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

La ridenominazione di un oggetto non deve portare alla duplicazione dei nomi degli oggetti.

  • Se uno dei nomi degli oggetti calcolati è già utilizzato nel modulo, interrompere il processo di ridenominazione e visualizzare un messaggio di errore per l’utente.
  • Altrimenti, rinominare l’oggetto.

// 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( : ; : ) ( # . ) ( . ( . . ; )) ("Nome oggetto " +" già utilizzato. Rinominazione annullata.") $formObject Object $newObjectName Text
If$newObjectName$formObjectname
IfThisisObjectNameUsedInFormThiseditorform $newObjectName
ALERT$newObjectName
ABORT // abort further processing
Else
$formObject. :=name$newObjectName
End if
End if

Il controllo di un nome di oggetto esistente viene effettuato con alcuni altri metodi: isObjectNameUsedInForm, isObjectNameUsedInPage, e isObjectNameUsedInListbox. Sono inclusi nell’esempio finale disponibile su Github. Esso contiene anche un modulo che si può usare per testare la macro:

blank

Utilizzare le macro Form nel lavoro quotidiano

Se l’implementazione di una macro Form è specifica per un singolo progetto, allora ha assolutamente senso aggiungerla direttamente a quel progetto. Ma macro come questa possono essere utili in qualsiasi progetto contenente moduli. Si può naturalmente copiare la classe in ogni progetto e aggiungere la definizione della macro a ogni file formMacros.json, ma è più semplice creare un componente.

Un componente macro Form non è altro che un progetto 4D con un file formMacros.json e le classi in esso definite. L’unica differenza è che si costruisce un componente e lo si colloca nella cartella components appropriata del progetto, oppure lo si colloca nella cartella components dell’applicazione 4D per renderlo disponibile in tutti i progetti per impostazione predefinita.

Se volete solo usare la macro e non vi interessa l’implementazione: l’esempio su GitHub include il componente compilato nella cartella Build.

Michael Höhne
Michael ha iniziato a programmare in BASIC a 15 anni e ha proseguito con il codice macchina puro, l'Assembler, il Pascal, il C, JAVA, C# e infine il 4D. Utilizza linguaggi orientati agli oggetti fin dai primi anni '90 ed è molto felice di vedere il 4D andare in quella direzione. Avendo lavorato in diverse aziende, tra cui Microsoft dal 1998 al 2001, Michael si è sempre impegnato a fondo nelle tecnologie Microsoft e ha ottenuto il premio MVP per Microsoft dynamics CRM per quattro volte (dal 2007 al 2010). Dopo aver lasciato Microsoft, ha trascorso anni a lavorare come freelance e ha avviato la propria azienda, Stunnware. Michael ha iniziato a sviluppare con 4D nel 2018. Oggi è a capo del team di sviluppo di Monaco di Baviera presso knk Business Software AG ed è uno sviluppatore 4D a tempo pieno.