Naviga: |
Ho trovato 18 faq.
Categoria | Argomento | Commenti |
Stile |
Uso dell'undescore nei nomi degli oggetti 4D
Capita ovviamente (ed è difficile supporre il contrario) che i nomi dei campi diventino più leggibili inserendo uno spazio che separi due parole. Diventa in tal caso preferibile utilizzare come separazione un "underscore" [ _ ]; questo approccio è consigliabile perché in tal modo, facendo doppio clic sul campo nel method editor, esso risulterà direttamente e interamente selezionato. Quindi, invece di [Anagrafica]Data di nascita sarà preferibile [Anagrafica]Data_di_nascita Inoltre ciò garantirà una migliore compatibilità con chiamate Sql, dove lo spazio non è ammesso fra i nomi dei campi. |
|
Stile |
La prima tabella della struttura
Una caratteristica che gli sviluppatori ereditano dai vecchi progetti, anche se non sarebbe più necessaria, è la presenza di una tabella "inutile" (per comodità solitamente la prima) dove viene inserito un unico record. Questa tabella viene solitamente utilizzata per mostrare form non legati ad una tabella specifica. Il motivo era dato dall'impossibilità di poter utilizzare le dialog per effettuare degli inserimenti. Si eseguiva dunque un ADD RECORD (seguito alla fine da un CANCEL) su quella tabella usando come form di input un form qualsiasi della tabella fittizia. Uso il passato perché con le versioni più recenti di 4D il comando DIALOG permette l'inserimento dei dati nei form. |
|
Stile |
Non mostrare valori quando un campo numerico vale zero
Quando si mostrano dei numeri in una maschera di output o in un report è possibile "nascondere" i campi che contengono semplicemente uno zero. Possiamo sfruttare infatti la possibilità di scrivere un formato del tipo "valore_positivo;valore_negativo;zero" per i numeri. Ad esempio, un formato possibile potrebbe essere: "###.##0 ;###.##0-;" I formati possono essere inseriti o direttamente nel campo o nel report, oppure creati e memorizzati nelle Database Properties. |
|
Stile |
I nomi dei semafori
Il nome di un semaforo è una semplice stringa: per evitare di creare semafori non voluti oppure di non cancellare semafori creati è buona prassi attribuire il nome del semaforo ad una variabile e poi utilizzare quest'ultima nei comandi successivi. Ad esempio: $SemaphoreName:="IlSemaforo" If (Not(Semaphore($SemaphoreName)) ` quel che vuoi CLEAR SEMAPHORE($SemaphoreName) End if |
|
Stile |
Uso di @ nei comandi Object Properties
I comandi della categoria Object Properties (FONT, FONT SIZE, FONT STYLE, ENABLE BUTTON, DISABLE BUTTON, BUTTON TEXT, SET CHOICE LIST, SET ENTERABLE, SET VISIBLE, SET FORMAT, SET FILTER, SET COLOR, SET RGB COLORS, GET OBJECT RECT, MOVE OBJECT, BEST OBJECT SIZE, Get alignment, SET ALIGNMENT) agiscono sulle proprietà degli oggetti presenti in un form durante la sua visualizzazione in modalità User o Custom (le proprietà impostate vengono ovviamente perse alla chiusura del form). Questi comandi accettano come parametro sia il nome dell'oggetto che il nome relativo (sia che esso rappresenti un campo o una variabile), con una sintassi del tipo: COMANDO({*;} oggetto{ ; parametri specifici del comando}) Se viene usato il parametro *, questo indica che in "oggetto" viene specificato l'object name (e non la corrispondente variabile). Essendo questo una stringa, posso utilizzare "@" nel nome per selezionare gruppi di oggetti. Quindi: "IlMioPulsanteBtn" indicherà il pulsante con quel nome. "@Btn" indicherà tutti gli oggetti il cui nome finisce per "Btn" |
|
Stile |
Uso della ricorsione e metodi ricorsivi
Uno dei sistemi di programmazione più affascinanti è sicuramente dato dall'uso della ricorsione: lo scopo è fondamentalmente quello di scrivere meno codice possibile, facendo in modo che operazioni identiche siano ripetute in cascata sempre dallo stesso metodo: facciamo un esempio. Supponiamo di voler scrivere un metodo che conti il numero di file presenti in una cartella e nelle sue sottocartelle. Usando la ricorsione non faremo altro che chiamare il metodo di conteggio dei file sulla cartella madre e su tutte le sottocartelle in essa contenute. Ecco il codice: C_STRING(255;$1) ARRAY TEXT($FolderList;0) ARRAY TEXT($DocumentList;0) C_LONGINT($piattaforma;$i) C_LONGINT($0;$count) ` ottengo l'elenco di file e cartelle FOLDER LIST($1;$FolderList) DOCUMENT LIST($1;$DocumentList) $count:=Size of array($DocumentList) If (Size of array($FolderList)>0) For ($i;1;Size of array($FolderList)) PLATFORM PROPERTIES($piattaforma) ` richiamo il metodo di conta su ogni `sottocartella della cartella corrente If ($piattaforma#3) $count:=$count+ContaFile($1+$FolderList{$i}+":") `RICORSIONE Else $count:=$count+ContaFile($1+$FolderList{$i}+"\\")`RICORSIONE End if End for End if $0:=$count Il metodo chiamante sarà: $count:=ContaFile(Select folder("Scegli la cartella da contare")) |
|
Stile |
Accedere ad un array da metodi o processi diversi
In 4th Dimension non è possibile passare un array come parametro ad un metodo o ad un processo in maniera diretta. Esistono comunque due modi per superare questo ostacolo: 1) il più semplice è quello di passare come parametro al metodo chiamato un puntatore all'array. Questo sistema funziona solo con array processo o interprocesso. Ad esempio: ` Method1 Method2 (->MyArray) ` Method2 C_POINTER($1) Questo metodo è molto usato anche perché i cambiamenti apportati dal Method2 sono condivisi dal Method1. 2) il metodo più affascinante è invece sicuramente quallo di riversare l'array in un blob. Questo approccio risulta molto utile soprattutto nelle chiamate fra processi diversi con array non interprocesso, e più in generale quando comunque non risulta necessario che gli array dei due metodi siano "lo stesso array", a differenza del caso precedente. Ovviamente, nella comunicazione tra processi diversi, il passaggio di un puntatore ad un array locale o di processo come parametro non funzionerebbe. Vediamo un esempio di questo uso: ` Method1: VARIABLE TO BLOB (MyArray;vBlob) $id_l:=New process ("Method2";32000;"ProcessName";vBlob) Il Method2 inizierà così: ` Method2 C_BLOB($1) ARRAY LONGINT(MyArray;0) BLOB TO VARIABLE ($1; MyArray) |
|
Stile |
Usare il nome del metodo come nome del processo
Esistono molti vantaggi nell'usare il nome del metodo che lancia un processo come nome del processo stesso, cioé con una sintassi del tipo: $id_l:=New process("P_Calcola";32000;"P_Calcola") Eccone alcuni: - conosco sempre l'id del processo senza usare variabili interprocesso, e quindi è valido scrivere: If (Current process=Process number("P_Calcola")) `quello che serve End if - nel Runtime explorer so perfettamente quale metodo fa partire un certo processo: hanno lo stesso nome! - e, molto interessante, per far partire un processo non ho bisogno di scrivere due metodi separati, ma uno solo: Case of : (Current process#Process number("P_Calcola")) $id_l:=New process("P_Calcola";32000;"P_Calcola") : (Current process=Process number("P_Calcola")) `quello che deve fare End case Ancora maggiori diventano i vantaggi se a tutto questo si associa anche l'uso di Current method name Fonte: 4D Today, John Baughman |
|
Stile |
Campi booleani nei Quick report
Stampando un report di una tabella con un camp Booleano, Quick Report visualizza il valore del campo come True o False. Ecco una funzione per rendere il report più leggibile. Mettiamo il caso che nel campo booleano si segni se una fattura è pagata o meno e questo campo si chiami [Fatture]Pagata_b. Per fare in modo che vengano stampate o esportate le voci "Pagata" e "Non pagata", invece del campo inserirò una colonna nel report in cui scriverò la formula: (Num([Fatture]Pagata_b)*"Pagata")+(Num(Not([Fatture]Pagata_b))*"Non pagata") Questo mostrerà dei valori più comprensibili; ovviamente la stessa formula può essere utile anche nelle liste e in genere nei layout di visualizzazione. |
|
Stile |
Dove metto i campi calcolati di FileMaker?
Una domanda che ci viene posta da chi, leggendo le faq su FileMaker, vuole cercare di avvicinarsi a 4th Dimension è: "Dove metto i campi calcolati di FileMaker in 4D?". Risposta: come detto, il 4D non esistono i campi calcolati, il che significa che intanto nella struttra 4D creo semplicemente un campo del tipo corretto. A questo punto il campo creato lo posso modificare, ad esempio, in questi posti: - nel metodo del form di input controllo il verificarsi dell'evento "On Data Change" su qualsiasi dei campi mostrati, cioè If (Form event=On Data change) `fai i calcoli che facevi con FM End if Dunque tutte le volte che verrà modificato un dato nel form verrà eseguito questo codice; - nel metodo del form di input controllo il verificarsi dell'evento "On Validate", che equivale al caso precedente con l'unica differenza che il codice viene eseguito solo quando salvo il record cliccando sul tasto che esegue l'azione ACCEPT; - nel metodo dello specifico oggetto, campo, variabile, pulsante, etc controllo il verificarsi dell'evento "On Data Change", che equivale anch'esso al primo caso, solo che il codice viene eseguito solo quando viene modificato il contenuto dell'oggetto stesso; - nel metodo (trigger) della tabella, che è il modo più semplice e complesso allo stesso tempo; tanto per non entrare nel dettaglio, si può dire che qualsiasi cosa succeda sulla tabella in questione in qualsiasi parte del database, 4D esegue il codice del trigger sul record della tabella su cui sto agendo. Però è facile scrivere un trigger che influisca pesantemente sulle performance dell'intera applicazione: per chi si affaccia e 4D è perciò preferibile iniziare con gli altri sistemi, cioè fare i calcoli solo nelle maschere in cui l'utente interviene sui dati o nelle procedure chiamate da menu nel momento in cui l'utente ha bisogno di dati calcolati. |
|
Stile |
Assegnare un valore di default ad un campo testo
Nella finestra "Property list" è possibile assegnare un valore di default ad un campo. Il problema è che il numero di caratteri utilizzabile è 29. Se vengono inseriti più di 29 caratteri, 4D li tronca. La maniera più semplica di aggirare questo ostacolo è di agire via codice: basta inserire il form di input il seguente codice: Case of :(Form event=On Load) If (Is new record([Tabella])) [Tabella]Campo:="il valore che gli voglio assegnare, anche più lungo di 29 caratteri" End if End case Fonte: 4D Tech Tip Knowledge Base, 4DToday |
|
Stile |
Cancellazioni da un array
Il comando DELETE ELEMENT permette di cancellare l'elemento di un array. Per usare questo comando all'interno di un ciclo For bisogna fare attenzione, perchè cancellando un elemento ovviamente diminuisce la dimensione dell'array e cambia anche la posizione degli elementi successivi. Prendiamo come esempio la necessità di cancellare da un array i valori duplicati. Un approccio potrebbe essere: C_TEXT($valore) C_LONGINT($size_L;$i) If (Size of array(MioArray)>0) $size_L:=Size of array(MioArray) SORT ARRAY(MioArray) $valore:=MioArray{1} For ($i;2;$size_L) If ($valore=MioArray{$i}) MioArray{$i}:="" Else $valore:=MioArray{$i} End if End for SORT ARRAY(MioArray) For ($i;1;$size_L) If ((MioArray{1})="") DELETE ELEMENT(MioArray;1) End if End for End if Ma così ho dovuto scorrere due volte il mio array: per scorrerlo solo una volta devo effettuare le cancellazioni durante il primo ciclo, ma con qualche piccolo accorgimento. Infatti, senza usare la variabile $valore e con un solo ciclo for ma che scorra l'array al contrario possiamo ottenere lo stesso risultato: C_LONGINT($size_L;$i) If (Size of array(MioArray)>0) $size_L:=Size of array(MioArray) SORT ARRAY(MioArray) For ($i;$size_L;2;-1) If (MioArray{$i}=MioArray{$i-1}) DELETE ELEMENT(MioArray;$i) End if End for End if |
|
Stile |
Generazione date
La maniera più semplice di ottenere una data avendo tre variabili numeriche che contengono giorno, mese e anno? Ovviamente: $data_d:=Date(String($giorno_L)+"/"+String($mese_L)+"/"+String($anno_L)) Tanto semplice quanto pericolosa! Infatti, se invece del formato DD/MM/YY sul computer ospite ne viene impostato, anche temporaneamente, un altro (ad esempio MM/DD/YY), otteniamo risultati imprevedibili. Per aggirare il problema si può usare un sistema differente: $data_d:=Add to date(!01/01/1900!; $anno_L-1900; $mese_L-1; $giorno_L-1) |
|
Stile |
Ottenere un carattere da una stringa
La maniera più intuitiva per ottenere l'i-esimo (iesimo_L) carattere della stringa MiaStringa_S è usare l'istruzione standard: Substring(MiaStringa_S;iesimo_L;1) Risulta però di certo più facilmente leggibile la sintassi: MiaStringa_S[[iesimo_L]] che restituisce esattamente lo stesso risultato, ma richiede la certezza che la stringa quel carattere lo contiene: cioè che iesmo_L sia minore o uguale alla Length(MiaStringa_S). |
|
Stile |
Dare un nome alle variabili
Scegliere il nome delle variabili è importante, anche se in certi casi sembra rallentare il processo produttivo. Propongo qui una serie di regole (come base di proposta) per uniformare lo stile dei nomi usati. 1. il nome dovrebbe essere indicativo del contenuto 2. se servono più parole si usa la prima lettera maiuscola per le parole successive alla prima (es. mioSetDiValori) 3. il nome degli indici dei cicli For può essere breve: si usa di solito $i, $j, $k, .. 4. la prima parte o prefisso serve a indicare il componente o il gruppo di metodi all'interno del quale viene usata la variabile. Ad esempio, se ho scritto un gruppo di procedure che servono a gestire il web chiamerò le variabili dentro questo gruppo con il prefisso "web_contatore", "web_user" 5. un seconda modalità di usare il prefisso (specialmente nel passato, prima dei componenti e delle variabili interprocesso) le regole suggerivano di usare una lettera di prefisso per indicare il tipo di variabile: ad esempio: - "bOk" è la variabile legata ad un oggetto di tipo pulsante - "kColoreSfondo" è una variabile usata come costante (non muta il contenuto) - "gNome" è una variabile condivisa da più maschere - "vNome" è una variabile normale all'interno di una maschera o un ciclo di procedure. 6. la parte finale o suffisso può servire ad indicare il tipo di variabile che si sta usando; è spesso usata una lettera o una sigla mnemonica (SanityCheck permette di controllare in automatico che il nome sia coerente con la dichiarazione) Tabella esempio dei suffissi intero_i interoLungo_l reale_r testo_t stringa_s data_d ora_h booleano_b immagine_pic puntatore_ptr blob_blb arrayInteri_ai arrayInteriLunghi_al arrayReale_ar arrayTesti_at arrayStringhe_as arrayDate_ad arrayTime_ah arrayBooleani_ab arrayImmagini_apic arrayPuntatori_aptr |
|
Stile |
Programmazione a Classi [2], esempio di Form Method
Il ciclo degli eventi rimane comunque ben diviso all'interno del Form Method, con il normale Case per la gestione di tutti gli eventi. $evento:=Form event Case of : ($evento =On Load ) C_Movimenti ("Carica Lista") : ($evento =On Printing Footer ) C_Movimenti ("Stampa Piu' Lista") : ($evento =On Outside Call ) C_Movimenti ("Chiamata Esterna") : ($evento =On Header ) C_Movimenti ("Aggiorna Lista") : ($evento =On Display Detail ) C_Movimenti ("Aggiorna Riga Lista") : ($evento =On Printing Detail ) C_Movimenti ("Aggiorna Riga Lista") `evento diverso, stesso metodo di sopra End case |
|
Stile |
Programmazione a Classi [3], passaggio dei parametri
Le chiamate hanno 1 o 2 parametri stringa, il primo per il metodo e il secondo per i parametri con una sintassi del tipo "parametro=valore[,parametro=valore]" Ad esempio: C_Ordine("Crea";"Articolo=H10,Quantita'=1,Descrizione=esempio 2,Pagato=False") AllÍinterno del metodo sara' possibile utilizzare una procedura scritta allo scopo: Case of :($1="Crea") $articolo:= getParametro($2;"Articolo ") $quantita:=Num(getParametro($2;"Quantita'")) $descrizione:= getParametro($2;"Descrizione") $pagato:=( getParametro($2;"Pagato")="true") `booleano ... Casi particolari: Il separatore , (virgola) potrebbe trovarsi all'interno del contenuto della variabile (ad esempio, passando un campo testo); in questo caso occorrera' passare il parametro fra virgolette. Ad esempio: C_Ordine("Crea";"Articolo=H10,Descrizione=\"esempio 2,5\",Pagato=True") Ovviamente per altri casi particolari e per il passaggio di blob o di puntatore array e' consentito di aggiungere un eventuale terzo parametro del tipo necessario. In questo caso pero' necessario ricordarsi sempre di passare un secondo parametro di tipo Text, anche se vuoto. Ad esempio: C_Ordine("Crea Gruppo";"";->Array) |
|
Stile |
Programmazione a Classi [1]
Un'ipotesi di programmazione a classi che so già usata da molti programmatori è la seguente: le procedure che raccolgono un gruppo di funzioni idealmente assimilabili vengono raccolte in un metodo con la seguente struttura. `Classe C_nnnnnnnn `Autore Nexus srl `Creato il 17-7-2003 `Mod. aggiunto il metodo xx `Mod. aggiunto il metodo yy `Mod. corretto il calcolo zz Case of :($1="metodo uno") ... :($1="metodo due") ... :($1="metodo tre") ... Else Alert(Current method name+":metodo "+$1+" non disponibile.") End case La definizione dei nomi dei metodi seguira' queste regola generale: C_{nome tabella} per la gestione delle procedure di input e OUTPUT FORM oppure C_{nome funzione} per le altre gestioni; ad esempio C_Fatturazione. In generale quando una procedura raccoglie un numero di metodi oltre una certa soglia di leggibilita' e' necessario che il case principale richiami ad altre classi piu' specializzate; ad esempio C_Fatturazione potrebbe richiamare i metodi di C_FatturazioneIN e C_FatturazioneOUT. |
Mutuo Facile, iDigitalScout, iDigitalTags e altre app di Nexid srl per iPhone e iPad
Cidroid, distributore italiano lettori barcode per IOS Apple iPhone, iPod, iPad