hostující autor Michael Höhne, vývojář 4D (Mnichov, Německo)
Ve 4D v18 R5 je funkce, která byla možná přehlédnuta, nebo se jí alespoň zatím nedostalo příliš pozornosti: Formulářová makra. Abych byl upřímný, ani já jsem jim donedávna nevěnoval mnoho času. V tomto příspěvku na blogu vám ukážu makro, které ušetří spoustu času při používání konvencí pro pojmenování sloupců polí seznamu, záhlaví sloupců a zápatí. Můžete si ho snadno změnit podle svých potřeb. Na Githubu je k dispozici také speciální repozitář.
Kontext nejprve …
Makra používáme při každodenní práci, abychom si usnadnili vývoj, a je to opravdu skvělá funkce. Stejně jako mnoho jiných společností máme i my zásady kódování. Jsou nezbytné při práci ve větších týmech, abychom si vzájemně lépe porozuměli v kódu. Jazyk 4D se poměrně dlouho neměnil a nezměnily se ani naše směrnice. Pak přišla ORDA, třídy a nové syntaxe pro deklarace proměnných a metod! Nastal čas začlenit tyto nové prvky jazyka a provést celkovou revizi našich interních specifikací. Součástí této revize byly názvy objektů formulářů (i když s novými věcmi zcela nesouvisely). Mluvili jsme o zaškrtávacích polích, rádiových tlačítkách, polích a nakonec o polích se seznamem. Nebudu se rozepisovat o našich stylech pojmenování. Důležité je, že pole seznamu nemá jediný název objektu. Má názvy pro samotný seznam, pro jednotlivé sloupce a pro záhlaví a zápatí jednotlivých sloupců. Jednoduchý box seznamu s 5 sloupci má 16 názvů objektů. Pokud chcete na pole se seznamem aplikovat konvence pro pojmenování, můžete se ocitnout ve zdlouhavém procesu. Nebylo by hezké jej zautomatizovat?
Názvy objektů pro pole seznamu obsahující firmy by mohly být následující:
- seznamFirmy pro samotný seznam,
- listCompaniesCol1, listCompaniesCol2, … pro názvy sloupců,
- listCompaniesCol1Header, listCompaniesCol2Header, …, pro záhlaví sloupců,
- listCompaniesCol1Footer, listCompaniesCol2Footer, …, pro zápatí sloupců.
To je jen jeden z možných způsobů, jak to udělat. Pokud se zeptáte vývojářů na jejich preference v pojmenování, nejspíš se dočkáte mnoha různých názorů. Může však existovat podobný vzorec jako u výše uvedených názvů: všechny názvy sloupců, záhlaví a zápatí vycházejí z názvu pole seznamu. Tyto názvy lze přiřadit pomocí makra Formulář!
Rychlý start
Makra formuláře jsou k dispozici prostřednictvím kontextové nabídky návrháře formuláře:
Pokud jste dosud makra Formuláře nepoužívali, pak je pravděpodobné, že vaše kontextová nabídka nebude nabídku Makra vůbec obsahovat:
V takovém případě je třeba nejprve vytvořit soubor formMacros.json a umístit jej do složky Sources vašeho projektu:
Soubor formMacros.json definuje názvy položek nabídky a tříd implementujících kód. Soubor, který používám v tomto příkladu, je velmi jednoduchý:
{ "macros": { "Rename Listbox columns": { "class": "RenameListboxColumns" } } }
Říká programu 4D, aby do nabídky Makra (zobrazené v kontextové nabídce návrháře formuláře) přidal položku nabídky s názvem „Přejmenovat sloupce Listboxu“. Po kliknutí na tuto položku nabídky se zavolá metoda onInvoke třídy s názvem „RenameListboxColumns“ (o tom více za chvíli). Soubor formMacros.json se načte jednou při načtení projektu. Změny obsahu se do uživatelského rozhraní promítnou až po opětovném načtení projektu. Pokud jste soubor formMacros.json vytvořili právě teď, zavřete projekt a znovu jej otevřete, aby se v návrháři formulářů zobrazila nabídka Makra. Podrobné informace o makrech formuláře naleznete zde.
Makra formuláře jsou třídy
Implementace makra Form se nachází uvnitř třídy. Vlastnost „class“ v definici makra („class“: „RenameListboxColumns“) určuje jeho název. Aby naše makro něco dělalo, musíme tuto třídu vytvořit:
Chcete-li zjistit, zda funguje, přidejte do něj následující kód:
// 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)
Když v nabídce Makra vyberete možnost „Přejmenovat sloupce Listboxu“, mělo by se zobrazit upozornění:
Jedná se o základní kontrolu, zda je vše správně nastaveno. Chcete-li ukázat možné úskalí, změňte kód na:
// 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!
Znovu zvolte nabídku „Přejmenovat sloupce Listboxu“:
4D načte definici třídy pouze jednou. Implementaci metod třídy můžete měnit, ale nové metody nebo změny parametrů metod budou k dispozici až po opětovném načtení projektu. To je poněkud nepohodlné, ale zvyknete si na to. Po opětovném načtení projektu bude kód fungovat bez problémů.
Přidávání funkcí
Nyní, když víte, jak nastavit makro Formulář, přidejme nějakou funkčnost! Zobrazení zprávy Hello World je pěkné, ale dávalo by smysl, aby makro s názvem „Přejmenovat sloupce Listboxu“ dělalo víc. Například přejmenování sloupců.
Metoda onInvoke předává objekt s názvem $editor. Tento objekt obsahuje informace o formuláři, se kterým právě pracujete. currentSelection ($editor.editor.currentSelection) obsahuje názvy všech vybraných objektů . Pokud jste žádný nevybrali, bude prázdný.
currentPage ($editor.editor.currentPage ) obsahuje všechny objekty , které se nacházejí na aktuální stránce formuláře. form ($editor.editor.form) obsahuje celý formulář. Tyto objekty jsou jednoduše částmi deklarace JSON formulářů. Pokud chcete mít přehled o strukturách objektů, jednoduše otevřete soubor form.4DForm, na kterém pracujete, v textovém editoru.
Protože chceme přejmenovat názvy objektů sloupců pole seznamu, záhlaví sloupců a zápatí, bude hlavní logika aplikace následující:
- Projděte vybrané objekty ve smyčce. Pro každé nalezené pole seznamu proveďte následující kroky:
- Projděte smyčkou sloupce pole seznamu a vypočítejte názvy objektů pro každý sloupec, záhlaví sloupce a zápatí na základě určitého vzoru.
- Pokud je jeden z vypočítaných názvů objektů ve formuláři již použit, přeruší se proces přejmenování a uživateli se zobrazí chybové hlášení.
- V opačném případě objekt přejmenujte.
Začněme prvním tématem:
- Projděte smyčkou vybrané objekty. Pro každé nalezené pole seznamu proveďte kroky popsané dříve:
// 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) .
Tento kód odpovídá větě (projít ve smyčce vybrané objekty, zkontrolovat seznamy a přejmenovat jejich sloupce). Jak ale identifikujeme pole seznamu? Vložme do kódu bod přerušení a prozkoumejme to:
Každý objekt má vlastnost type. Pro pole seznamu ji nastavíme na hodnotu „listbox“. To je totéž, co vidíte při otevření souboru form.4dform v textovém editoru:
// Check if the form object is a listbox
Function isListbox($formObject: Object)->$isListbox: Boolean
$isListbox :=($formObject.type="listbox")
Celkem jednoduché! Samozřejmě by se tento jednořádkový příkaz dal místo deklarace nové metody přímo zahrnout do onInvoke, ale po zhruba 30 letech objektově orientovaného vývoje jsem si zvykl vytvářet malé metody. Pomáhá to psát snadno pochopitelný a snadno udržovatelný kód.
Nyní, když víme, jak identifikovat pole seznamu, udělejme další krok:
- Projděme smyčkou sloupce pole seznamu a vypočítáme názvy objektů pro každý sloupec, záhlaví a zápatí sloupce na základě určitého vzoru.
// 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 . ( . ; . +"Zápatí") setObjectName$colfooter $colname
This . ( . ; . +"Header") := +1setObjectName$colheader $colname
$index$index
End for each
Přejmenování objektu by nemělo vést k duplicitním názvům objektů.
- Pokud je jeden z vypočítaných názvů objektů ve formuláři již použit, přerušíme proces přejmenování a zobrazíme uživateli chybové hlášení.
- V opačném případě objekt přejmenujte.
// 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( : ; : ) ( # . ) ( . ( . . ; )) ("Object name " +" already used. Renaming canceled.") $formObject Object $newObjectName Text
If$newObjectName$formObjectname
IfThisisObjectNameUsedInFormThiseditorform $newObjectName
ALERT$newObjectName
ABORT // abort further processing
Else
$formObject. :=name$newObjectName
End if
End if
Kontrola existujícího názvu objektu se provádí pomocí několika dalších metod: isObjectNameUsedInForm, isObjectNameUsedInPage, a isObjectNameUsedInListbox. Jsou obsaženy ve finální ukázce dostupné na Githubu. Obsahuje také formulář, který můžete použít k otestování makra:
Použití formulářových maker při každodenní práci
Pokud je implementace makra formuláře specifická pro jeden projekt, pak je zcela logické přidat ho přímo do tohoto projektu. Makra, jako je toto, však mohou být užitečná v jakémkoli projektu obsahujícím formuláře. Třídu můžete samozřejmě zkopírovat do každého projektu a definici makra přidat do každého souboru formMacros.json, ale jednodušší je místo toho vytvořit komponentu.
Komponenta makra formuláře není nic jiného než projekt 4D se souborem formMacros.json a třídami definovanými v něm. Jediný rozdíl spočívá v tom, že komponentu vytvoříte a umístíte ji do příslušné složky komponent svého projektu nebo ji umístíte do složky komponent aplikace 4D, aby byla standardně k dispozici ve všech projektech.
Pokud chcete pouze používat makro a nezajímá vás implementace: ukázka na GitHubu obsahuje zkompilovanou komponentu ve složce Build.