Naviga: |
Ho trovato 76 faq.
Categoria | Argomento | Commenti | ||||||||||||||||||||||
Codice |
Controllo Codice Fiscale
Questo metodo ritorna Vero se il codice fiscale passato è scritto correttamente, utilizzando il carattere di controllo finale. La procedura è un po' condensata: per l'algoritmo di controllo completo potete trovare il dettaglio sul sito del Ministero delle Finanze. `Metodo Controllo_CodiceFiscale `controlla il checksum del codice fiscale `Nexus srl 4-6-90 C_LONGINT($i;$n_l;$car_l;$cod_l) C_STRING(16;$cf_s;$1) C_STRING(43;$mysndcod_s) $cf_s:=$1 If (Length($cf_s)#16) $0:=False Else $n_l:=0 For ($i;2;14;2) $car_l:=Ascii($cf_s[[$i]]) Case of : (($car_l>=48) & ($car_l<=57)) $cod_l:=$car_l-48 : (($car_l>=65) & ($car_l<=90)) $cod_l:=$car_l-65 Else $cod_l:=0 End case $n_l:=$n_l+$cod_l End for $mysndcod_s:="BAFHJNPRTVUMBERTOBAFHJNPRTVCESULDGIMOQKWZYX" For ($i;1;15;2) $car_l:=Ascii($cf_s[[$i]])-47 $cod_l:=Ascii($mysndcod_s[[$car_l]])-65 $n_l:=$n_l+$cod_l End for $0:=((65+$n_l-(Int($n_l/26)*26))=Ascii($cf_s[[16]])) End if |
3 | ||||||||||||||||||||||
Info |
JSON e i caratteri da filtrare
Nelle stringhe JSON i caratteri da filtrare sono: virgolette (quote) -> \" barra a destra (slash) -> \/ barra a sinistra (backslash) -> \\ backspace -> \b formfeed -> \f nuova linea (new line, char(10) ) -> \n a capo (return, char(13) ) -> \r tabulatore (tab, char(9) ) -> \t tutti i caratteri da 0 a 31 esclusi quelli sopra devono diventare \x00-\x1F un qualsiasi carattere unicode -> \u+4 cifre esadecimale // web_jsonEncode $risultato:=$1 $risultato:=Replace string($risultato;"\\";"\\\\") $risultato:=Replace string($risultato;char(double quote);"\\\"") $risultato:=Replace string($risultato;"/";"\\/") $risultato:=Replace string($risultato;Char(Backspace);"\\b") $risultato:=Replace string($risultato;Char(FF ASCII code);"\\f") $risultato:=Replace string($risultato;Char(Line feed);"\\n") $risultato:=Replace string($risultato;Char(Carriage return);"\\r") $risultato:=Replace string($risultato;Char(Tab);"\\t") $0:=$risultato |
1 | ||||||||||||||||||||||
Tecniche |
Duplicazione RECORD con SUBRECORD
Le nuove versioni di 4D non duplicano piu' i subrecord all'interno del record ed il campo id_added_by_converter non e' editabile, ne avevo necessita' per cui ho fatto questa routine (spero esista un metodo piu' semplice) Occorre preventivamente creare un set del record da duplicare ed un set del record duplicato (ricordarsi di cancellarli al termine) poi : DuplicaSubrecords (->[TABLE];->[TABLE]Subrecord;->[TABLE_Subrecord];->[TABLE_Subrecord]id_added_by_converter) // DUPLICAZIONE SUBRECORDS $p_TABLErecord:=$1 // Puntatore alla Tabella RECORD $p_TABLEsubrecord:=$2 // Puntatore al campo SUBRECORD DEL RECORD $p_TABLENewsubrecord:=$3 // Puntatore alla Tabella NEW SUBRECORD $p_Id:=$4 // Puntatore al campo id_added_by_converter $NumeroTABLE:=Table($p_TABLENewsubrecord) USE SET("OLD") // Richiamo il record originale QUERY($p_TABLENewsubrecord->;$p_Id->=Get subrecord key($p_TABLEsubrecord->)) $NumeroSubrecords:=Records in selection($p_TABLENewsubrecord->) If ($NumeroSubrecords>0) USE SET("NEW") // Richiamo il record copia For ($i;1;$NumeroSubrecords) CREATE SUBRECORD($p_TABLEsubrecord->) // Creo l'aggancio al record End for SAVE RECORD($p_TABLErecord->) USE SET("OLD") $NumeroCampi:=Get last field number($p_TABLENewsubrecord) ARRAY POINTER($p_ElementoCampo;$NumeroSubrecords*$NumeroCampi) For ($i;1;$NumeroSubrecords) $P_RECORD:=($i-1)*$NumeroCampi For ($k;1;$NumeroCampi) $P_Vettore:=$P_RECORD+$k // Calcolo l'elemento del vettore $p_ElementoCampo{$P_Vettore}:=Get pointer("$var_"+String($k)) // Associo il puntatore $p_Campo:=Field($NumeroTABLE;$k) // Puntatore al campo da prelevare $p_ElementoCampo{$P_Vettore}->:=$p_Campo-> // Momorizzo il valore del campo sulla variabile End for NEXT RECORD($p_TABLENewsubrecord->) End for USE SET("NEW") QUERY($p_TABLENewsubrecord->;$p_Id->=Get subrecord key($p_TABLEsubrecord->)) $NumeroSubrecords:=Records in selection($p_TABLENewsubrecord->) ON ERR CALL("ErrorIdSubrecord") // Filtra Errore su assegnazione campo id_added_by_converter (Metodo ErrorIdSubrecord VUOTO) For ($i;1;$NumeroSubrecords) $P_RECORD:=($i-1)*$NumeroCampi For ($k;1;$NumeroCampi) $P_Vettore:=$P_RECORD+$k // Calcolo l'elemento del vettore $p_Campo:=Field($NumeroTABLE;$k) // Puntatore al campo da assegnare $p_Campo->:=$p_ElementoCampo{$P_Vettore}-> // Assegno il valore dalla variabile al campo End for SAVE RECORD($p_TABLENewsubrecord->) NEXT RECORD($p_TABLENewsubrecord->) End for UNLOAD RECORD($p_TABLENewsubrecord->) ON ERR CALL("") SAVE RECORD($p_TABLErecord->) // Forse non serve End if |
2 | ||||||||||||||||||||||
Info |
Limitare il numero di caratteri in una variabile alfanumerica
Una delle prime FAQ pubblicate su Sviluppo4D riguardava la limitazione del numero di caratteri inseribili in un campo Alpha. Eccone una versione aggiornata: Case of : (Form event=On After Edit) If (Length(Get edited text)>=vLength) $textvariable:=Substring(Get edited text;1;vLength) End if End case A vLength può essere sostituita la lunghezza del campo, nei casi in cui è possibile. A $textvariable potrebbe essere sostituito Self->, ma in questo caso il metodo non funziona ad esempio sugli elementi degli array di una listbox. |
1 | ||||||||||||||||||||||
Codice |
Come creare una plist per Mac OS X o IOS
Il formato XML plist è lo standard con cui sono scritte ad esempio le preferenze dei vari programmi su Mac OS X. Il formato è letto nativamente dalle applicazioni scritte in XCode, come ad esempio programmi per iPhone e iPad. L'esempio successivo mostra come creare una plist per ad esempio inviare dei dati strutturati ad un applicativo su iOS in modo semplice e veloce: infatti un xml generico andrebbe ogni volta interpretato, mentre la plist può essere letta direttamente come un NSDictionary. ` ---------------------------------------------------- ` User name (OS): Umberto Migliore ` Date and time: 08-02-11, 12:22:51 ` ---------------------------------------------------- ` Method: nx_crea_plist ` Description: `mostra come creare un documento plist: ` `<?xml version="1.0" encoding="UTF-8" standalone="no" ?> `<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> `<plist version="1.0"> ` <dict> ` <key>Author</key> ` <string>William Shakespeare</string> ` <key>Title</key> ` <string>Macbeth</string> ` <key>Lines</key> ` <array> ` <string>It is a tale told by an idiot,</string> ` <string>Full of sound and fury, signifying nothing.</string> ` </array> ` <key>Birthdate</key> ` <integer>1564</integer> ` </dict> `</plist> ` ` Parameters ` ---------------------------------------------------- C_TEXT($autore;$titolo) C_LONGINT($annonascita) ARRAY TEXT($citazione;0) `=== preparo i dati $autore:="William Shakespeare" $titolo:="Macbeth" $annonascita:=1564 APPEND TO ARRAY($citazione;"It is a tale told by an idiot,") APPEND TO ARRAY($citazione;"Full of sound and fury, signifying nothing.") `=== creo la plist $xml_ref:=DOM Create XML Ref("plist";"";"version";"1.0") `=== dict principale che contiene tutto $dict:=DOM Create XML element($xml_ref;"dict") $key:=DOM Create XML element($dict;"key") DOM SET XML ELEMENT VALUE($key;"Author") $value:=DOM Create XML element($dict;"string") DOM SET XML ELEMENT VALUE($value;$autore) $key:=DOM Create XML element($dict;"key") DOM SET XML ELEMENT VALUE($key;"Title") $value:=DOM Create XML element($dict;"string") DOM SET XML ELEMENT VALUE($value;$titolo) $key:=DOM Create XML element($dict;"key") DOM SET XML ELEMENT VALUE($key;"Lines") $array:=DOM Create XML element($dict;"array") For ($riga;1;Size of array($citazione)) $value:=DOM Create XML element($array;"string") DOM SET XML ELEMENT VALUE($value;$citazione{$riga}) End for $key:=DOM Create XML element($dict;"key") DOM SET XML ELEMENT VALUE($key;"Birthdate") $value:=DOM Create XML element($dict;"integer") DOM SET XML ELEMENT VALUE($value;$annonascita) `=== chiude l'xml, aggiunge lo header e ritorna un testo DOM EXPORT TO VAR($xml_ref;$testo) DOM CLOSE XML($xml_ref) $header:="<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" $testo:=Insert string($testo;$header;Position("<plist";$testo)) ALERT($testo) ` $0:=$testo |
1 | ||||||||||||||||||||||
Codice |
Ruotare un'immagine usando SVG
Questo codice è un esempio di utilizzo del componente incluso in 4d per gestire i comandi SVG; lo scopo del metodo è di ruotare di 90 gradi un'immagine, ad esempio per raddrizzare una foto. // ---------------------------------------------------- // User name (OS): Umberto Migliore // Date and time: 14-02-11, 11:41:14 // ---------------------------------------------------- // Method: nx_svgRuotaQuartoDestra // Description // Ruota un immagine di un quarto di giro a destra // // Parameters // ---------------------------------------------------- C_PICTURE($immagine;$1;$0) $immagine:=$1 PICTURE PROPERTIES($immagine;$larga;$alta) $maggiore:=Choose($larga>$alta;$larga;$alta) $svg:=SVG_New ($alta;$larga) $img:=SVG_New_embedded_image ($svg;$immagine;0;0) SVG_SET_TRANSFORM_ROTATE ($svg;90;$maggiore/2;$maggiore/2) If ($larga>$alta) SVG_SET_TRANSFORM_TRANSLATE ($svg;0;$larga-$alta) End if $immagine:=SVG_Export_to_picture ($svg;0) SVG_CLEAR ($svg) $0:=$immagine |
1 | ||||||||||||||||||||||
Codice |
Data e ora in formato XML
Il formato XML di data e ora è il seguente AAAA-MM-GGTHH:MM:SS. Il vantaggio di questa stringa è che è ordinabile, contiene la coppia dei dati e quindi è più leggibile del timestamp (che rimane però più efficiente e consuma meno spazio su disco e in memoria come indice). Ecco alcuni trucchi per convertire una data in questo formato e viceversa (non documentati, mi sembra) in 4d 2004.3: Date("2006-01-24T00:00:00") -> ritorna effettivamente la data 24 gen 2006: Importante funziona solo se la stringa è lunga 19 caratteri e la data è seguita dal separatore "T". String(current date;8) -> ritorna la data nel formato XML completa di separatore = "2006-01-24T00:00:00" Per avere data e ora si può usare questa semplice riga: Replace string(String(Current date;8);"00:00:00";String(Current time;1)) |
1 | ||||||||||||||||||||||
Info |
Sintassi 4D SQL : INNER JOIN
Una inner join crea una griglia di dati combinando i valori delle due tabelle di partenza (A and B) basandosi su una certa regola di confronto: la query compara ogni riga della tabella A con ciascuna riga della tabella B cercando di soddisfare la regola di confronto definita. Esempio, date queste due tabelle di dati: Tabella Aziende
Tabella Contatti
Begin SQL SELECT Cognome,Aziende.Ragione_Sociale FROM Contatti INNER JOIN Aziende ON Contatti.ID_Azienda=Aziende.ID_Azienda INTO :ArrCognome,:ArrRagSociale; End SQL Risultato:
|
1 | ||||||||||||||||||||||
Codice |
Modificare la cella di una listbox con un solo clic
Per modificare l'elemento di una list box è necessario cliccarci due volte: il primo clic seleziona l'elemento, il secondo lo rende modificabile. Per fare in modo che un clic renda direttamente modificabile l'elemento si può uasre il seguente codice: Case of : (Form event=On Clicked ) ` mi asssicuro che non stia facendo una selezione mutipla If (Not(Shift down | Windows Ctrl down)) LISTBOX GET CELL POSITION(*;"ListBox";col;row;colVar_p) EDIT ITEM(colVar_p->;row) End if End case |
1 | ||||||||||||||||||||||
Info |
Nomi di variabili riservati
I seguenti nomi di variabili sono riservati a 4D: C1, C2, C3, C4, C5, ecc. (usate nei report) OK Document Error KeyCode Modifiers MouseDown MouseProc MouseX MouseY FldDelimit RecDelimit Non devono dunque essere usate se non nel contesto cui si riferiscono: ad esempio Document contiene il percorso del documento dopo aver usato Open document, Create document o Append document ed è stato scelto un file mostrando la dialog di sistema per l'apertura o il salvataggio di un file. |
1 | ||||||||||||||||||||||
Comandi |
[v11 SQL] Il comando SET QUERY AND LOCK
Il nuovo comando SET QUERY AND LOCK, che prende come parametro semplicemente True o False, permette di richiedere il blocco dei record risultanti da una query. Ciò garantisce che i risultati di una certa ricerca non possano essere modificato da un altro processo che non sia quello attuale. Il comando può essere usato solo all'interno di una transazione (altrimenti restituisce errore), e i record restano bloccati finché la transazione viene terminata: a quel punto i record vengono comunque rilasciati. Basta comunque chiamare SET QUERY AND LOCK(False) per rilasciarli. Ecco un esempio di cancellazione controllata da SET QUERY AND LOCK: START TRANSACTION SET QUERY AND LOCK(True)`così mi assicuro che i record trovati siano locked per gli altri QUERY([Clients];[Clients]Category=“C”) DELETE SELECTION([Clients]) SET QUERY AND LOCK(False) VALIDATE TRANSACTION |
1 | ||||||||||||||||||||||
Codice |
Metodo EliminaSpazi con Match Regex
Versione del metodo che elimina gli spazi dall'inizio e dalla fine di una stringa usando il comando Match Regex e due semplici regular espressions. C_TEXT($miaStringa;$1) C_TEXT($0;$risultato) C_TEXT($pattern) C_LONGINT($inizio;$dove;$lunga) C_BOOLEAN($trovato) $miaStringa:=$1 $inizio:=1 $foundFlag:=False `pattern regex per gli spazi all'inizio `^ -- indica l'inizio da dove cercare `\s+ -- search for one or more white spaces $pattern:="^\\s+" $trovato:=Match regex($pattern;$miaStringa;$inizio;$dove;$lunga) If ($trovato) $miaStringa:=Substring($miaStringa;$lunga+1) End if `pattern regex per gli spazi alla fine della stringa `$ -- indica la fine dove cercare $pattern:="\\s+$" $trovato:=Match regex($pattern;$miaStringa;$inizio;$dove;$lunga) If ($trovato) $miaStringa:=Substring($miaStringa;$inizio;$dove-1) End if $0:=$miaStringa |
1 | ||||||||||||||||||||||
Info |
[v11 SQL] Dove si trovano i manuali?
Dalla versione v11 i manuali non vengono più installati con le applicazioni. Questo è l'indirizzo dove trovare i manuali di 4d in inglese: http://www.4d.com/support/documentation.html Per chi vuole consultare la guida online, l'indirizzo è: http://www.4d.com/docs/4DDOCUS.HTM Per configurare il percorso dell'help richiamabile con il tasto F1 nelle preferenze va scritto questo: http://www.4d.com/docs/ |
2 | ||||||||||||||||||||||
Tecniche |
Accedere ad un database 4D
"io ho la necessità di collegarmi ad un database 4d (che gira su piattaforma Mac) da un server MSSQL per estrarre e pubblicare alcuni dati. Potete spiegarmi la procedura per poter effettuare questa operazione?" Risponde Umberto Migliore: Ci sono diverse possibilità:
Diciamo che dipende dal tipo di informazioni che si vogliono passare, con che frequenza e con che controllo di validità o se servono eventuali elaborazioni a monte. |
8 | ||||||||||||||||||||||
Codice |
Conversione da esadecimale a decimale
Passando come parametro una stringa in forma esadecimale al seguente metodo, questo restituisce il valore decimale relativo: C_TEXT($CifraEsadecimale_t;$tutteLeCifre_t;$1;$NumEsadecimale_t) C_LONGINT($0;$posizione_l) $0:=0 $tutteLeCifre_t:="0123456789ABCDEF" $NumEsadecimale_t:=$1 While (Length($NumEsadecimale_t)>0) $CifraEsadecimale_t:=Substring($NumEsadecimale_t;0;1) $NumEsadecimale_t:=Substring($NumEsadecimale_t;2;Length($NumEsadecimale_t)) $0:=$0*16 $posizione_l:=Position($CifraEsadecimale_t;$tutteLeCifre_t)-1 $0:=$0+$posizione_l End while |
2 | ||||||||||||||||||||||
Info |
[v11 SQL] Modifiche al comando QUERY BY FORMULA
Con la v11 SQL i comandi QUERY BY FORMULA e QUERY SELECTION BY FORMULA richiedono obbligatoriamente come parametro la tabella su cui eseguire la query. Come già detto, per migliorare le prestazioni questi comandi vengono eseguiti sul Server quando vengono eseguiti da un Client. Inoltre è stato implementato un sistema di ottimizzazione delle QUERY BY FORMULA per migliorarne ulteriormente le prestazioni. |
1 | ||||||||||||||||||||||
Codice |
Come usare le transazioni nelle maschere di inserimento V2
Un altro schema per l'uso delle transazioni nell'inserimento o nella modifica di un record: Metodo del Form di inserimento Case of : (Form Event=On Load) START TRANSACTION .... : (Form Event=On Validate) VALIDATE TRANSACTION .... : (Form Event=On Unload) If (In transaction) CANCEL TRANSACTION End if End case Da ricordare che il form event On Unload di default non è attivo per il form e dunque è da attivare manualmente. |
1 | ||||||||||||||||||||||
Tecniche |
Lanciare una stored in 4d 2004 *
Nella versione 11 è possibile impostare un flag per cui un metodo verrà lanciato in automatico sul server (dove in alcune condizioni le cose sono molto più veloci); il processo resterà in attesa del metodo e ne userà il risultato. Per ottenere la stessa cosa in 2004 dobbiamo fare in modo che il client attenda la fine del processo sul server per leggere la risposta e la stored invece invece alla fine dell'esecuzione deve prima di chiudersi aspettare che il client abbia la risposta. Ecco un metodo che si può usare come base di lavoro: === SUL CLIENT: C_BLOB(blob_risposta) $id:=Execute on server("metodo_suserver";128*1024;"metodo") nexus_stored("attendi";$id) ` ... qui posso usare la risposta === SUL SERVER: nexus_stored("start") ` ... qui va il tuo codice che scrive la risposta in un blob, ad esempio nexus_stored("stop") === ECCO IL METODO BASE: ` Method nexus_stored ` Nexus srl, www.nexusonline.it Case of : ($1="start") ` === startup del processo If (Application type=4D Server ) C_BOOLEAN(stored_finito;client_letto) stored_finito:=False client_letto:=False C_BLOB(blob_risposta) SET BLOB SIZE(blob_risposta;0) End if : ($1="stop") ` === chiusura processo If (Application type=4D Server ) client_letto:=False stored_finito:=True $start:=Milliseconds While (Not(client_letto) & ((Milliseconds-$start)<30000)) DELAY PROCESS(Current process;1) End while End if : ($1="attendi") ` === legge la risposta dalla stored e la chiude C_BOOLEAN(stored_finito;processo_finito;client_letto) C_TEXT(currentProgressStatus) $pid:=$2 processo_finito:=False Repeat DELAY PROCESS(Current process;10) GET PROCESS VARIABLE($pid;stored_finito;processo_finito) Until (processo_finito) GET PROCESS VARIABLE($pid; blob_risposta; blob_risposta) client_letto:=True SET PROCESS VARIABLE($pid;client_letto;client_letto) End case |
1 | ||||||||||||||||||||||
File |
Metodo Benchmark v1.2.1*
Contiene una struttura dove propongo una base di benchmark delle versioni di 4D e delle piattaforme su cui viene lanciato. In questo momento il codice è abbastanza approssimativo e non pesa allo stesso modo le varie parti del test (Export e Import sono sicuramente più significative delle altre funzioni in questo modo), inoltre testa solo il db engine del 4d mono, quindi create record, indexing, query, sort. `Method Benchmark `version 1.2.2 - 5 feb 2009 DEFAULT TABLE([Table]) If (Records in table>0) ALERT("You should launch this one on a new db") ALL RECORDS DELETE SELECTION FLUSH BUFFERS Else $quantity:=Num(Request("How many record?";String(1000))) If (ok=1) $start:=Tickcount $firstStart:=$start `create record For ($i;1;$quantity) CREATE RECORD [Table]First:=String($i) For ($j;1;10) `tre lettere [Table]Second:=[Table]Second+Char((Random%(122-97+1))+97) End for [Table]Numeric:=Random*Random SAVE RECORD End for FLUSH BUFFERS $benchmark_create:=Tickcount-$start $start:=Tickcount For ($i;1;$quantity) MESSAGE(String($i)+" on "+String($quantity)) CREATE RECORD [Table]First:=String($i) For ($j;1;10) [Table]Second:=[Table]Second+Char((Random%(122-97+1))+97) End for [Table]Numeric:=Random*Random SAVE RECORD End for FLUSH BUFFERS $benchmark_createWithDialog:=Tickcount-$start $start:=Tickcount ALL RECORDS([Table]) EXPORT TEXT([Table];"testexport.txt") $benchmark_export:=Tickcount-$start $start:=Tickcount IMPORT TEXT([Table];"testexport.txt") FLUSH BUFFERS $benchmark_import:=Tickcount-$start $start:=Tickcount SET INDEX([Table]First;True) $benchmark_index:=Tickcount-$start $start:=Tickcount QUERY([Table];[Table]First>"4") $benchmark_queryMedium:=Tickcount-$start $start:=Tickcount QUERY([Table];[Table]First<"9") $benchmark_queryLarge:=Tickcount-$start $start:=Tickcount QUERY([Table];[Table]First<"51";*) QUERY([Table]; & ;[Table]Second>"M") $benchmark_queryDouble:=Tickcount-$start $start:=Tickcount ORDER BY([Table];[Table]First;>) $benchmark_orderSingle:=Tickcount-$start $start:=Tickcount ORDER BY([Table];[Table]Second;>;[Table]First;<) $benchmark_orderDouble:=Tickcount-$start $benchmark_global:=Tickcount-$firstStart If (Compiled application) $compiled:=" Comp" Else $compiled:=" Inter" End if $result:="GLOBAL mm:ss:tt ["+String($quantity)+$compiled+"] " $result:=$result+Time string($benchmark_global/60)+", "+String($benchmark_global)+"tick"+Char(13)+Char(Line feed ) ALERT($result) $result:=$result+"create "+Time string($benchmark_create/60)+", "+String($benchmark_create)+"tick"+Char(13)+Char(Line feed ) $result:=$result+"withDialog "+Time string($benchmark_createWithDialog/60)+", "+String($benchmark_createWithDialog)+"tick"+Char(13)+Char(Line feed ) $result:=$result+"export "+Time string($benchmark_export/60)+", "+String($benchmark_export)+"tick"+Char(13)+Char(Line feed ) $result:=$result+"import "+Time string($benchmark_import/60)+", "+String($benchmark_import)+"tick"+Char(13)+Char(Line feed ) $result:=$result+"index "+Time string($benchmark_index/60)+", "+String($benchmark_index)+"tick"+Char(13)+Char(Line feed ) $result:=$result+"qryMedium "+Time string($benchmark_queryMedium/60)+", "+String($benchmark_queryMedium)+"tick"+Char(13)+Char(Line feed ) $result:=$result+"qryLarge "+Time string($benchmark_queryLarge/60)+", "+String($benchmark_queryLarge)+"tick"+Char(13)+Char(Line feed ) $result:=$result+"qryDouble "+Time string($benchmark_queryDouble/60)+", "+String($benchmark_queryDouble)+"tick"+Char(13)+Char(Line feed ) $result:=$result+"orderSingle "+Time string($benchmark_orderSingle/60)+", "+String($benchmark_orderSingle)+"tick"+Char(13)+Char(Line feed ) $result:=$result+"orderDouble "+Time string($benchmark_orderDouble/60)+", "+String($benchmark_orderDouble)+"tick"+Char(13)+Char(Line feed ) SET TEXT TO CLIPBOARD($result) C_BLOB($BLOB) TEXT TO BLOB($result;$BLOB;3) $vhDocRef:=Create document("";"txt") ` Save the document of your choice If (OK=1) ` If a document has been created CLOSE DOCUMENT($vhDocRef) ` We don't need to keep it open BLOB TO DOCUMENT(Document;$BLOB) ` Write the document contents End if End if End if |
1 | ||||||||||||||||||||||
Tecniche |
Importare un campo boolean da un file di testo
Facendo un import di dati from file con un campo booleano ho provato sia con true (prima lettera minuscola) che con 1 ma alla fine ho scoperto che era sufficiente scrivere True con la prima lettera maiuscola. Versione 2004 7. |
1 | ||||||||||||||||||||||
Codice |
Generazione automatica del file Sitemap.xml
Se avete un sito dinamico, dove non tutti i link sono facilmente raggiungibili dai motori di ricerca, è utile comunicare agli stessi l'elenco degli indirizzi disponibili con un protocollo chiamato sitemap. L'indicazione dell'esistenza della sitemap viene comunicata al motore di ricerca o tramite una loro pagina dedicata (come Google) oppure più genericamente con una riga nel file robots.txt (vedi ad esempio la faq Generazione automatica del file Robots.txt dove è descritto il file robots di Sviluppo4d.it). Clicca qui per vedere il risultato. `metodo web_sitemap $eol:="\r\n" $txt:="" $txt:=$txt+"<?xml version='1.0' encoding='UTF-8'?>"+$eol $txt:=$txt+"<urlset xmlns=\"http://www.google.com/schemas/sitemap/0.84\" " $txt:=$txt+"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " $txt:=$txt+"xsi:schemaLocation=\"http://www.google.com/schemas/sitemap/0.84 " $txt:=$txt+"http://www.google.com/schemas/sitemap/0.84/sitemap.xsd\">"+$eol `preparo la parte iniziale e finale del singolo url $s:="<url><loc>http://www.sviluppo4d.it" `qua va il nome del sito corrente $e:="</loc></url>"+$eol `prima elenchiamo gli indirizzi fissi $txt:=$txt+$s+""+$e`indirizzo base del sito $txt:=$txt+$s+wb_xmlEncode ("/Users")+$e`indirizzo fisso su sviluppo4d.it `poi costruiamo l'elenco degli indirizzi dinamici ALL RECORDS([News]) While (Not(End selection([News]))) $txt:=$txt+$s+"/Detail_News_Display?id="+String([News]id)+"&title="+ wb_xmlEncode( wb_urlEncode ([News]Title))+$e NEXT RECORD([News]) End while ALL RECORDS([Faq]) While (Not(End selection([Faq]))) $txt:=$txt+$s+"/Detail_FAQ_Display?id="+String([Faq]id)+"&title="+ wb_xmlEncode( wb_urlEncode([Faq]Title))+$e NEXT RECORD([Faq]) End while `chiudiamo il tag principale $txt:=$txt+"</urlset>" SEND HTML TEXT($txt) |
1 | ||||||||||||||||||||||
Codice |
Calcolo del numero della settimana (2)
Un po' di tempo fa avevo letto un discussione sul calcolo del numero della settimana; mi è capitato di leggere la definizione dell'inizio anno in base alla quale l'anno inizia dal Lunedì della settimana che contiene il 4 gennaio ed ecco qui l'algoritmo corretto xData:=Date(Request("Data";String(Current date))) ` ---------------------------------------------------- ` User name (OS): llarosa ` Date and time: 12/01/09, 13:09:35 ` ---------------------------------------------------- ` Method: Calcolo numero settimana ` Description Ritorna la settimana dell'anno usando ISO 8601 standard ` ( l'anno parte dal Lunedi della settimana che contiene il 4 Gennaio) ` ` Parameters ` ---------------------------------------------------- ` calcolo il 4 di gennaio che giorno è -2 perchè la day number conta come primo giorno la domenica Jan04DOW:=Day number(Date("04-01-"+String(Year of(xData))))-2 ` avendo fatto -2 la domenica diventa -1 e la riporto a 6 Jan04DOW:=(Num(Jan04DOW=-1)*6)+(Num(Jan04DOW#-1)*Jan04DOW) ` calcolo la data del primo lunedi dell'anno FirstMonday:=Date("04-01-"+String(Year of(xData)))-Jan04DOW ` se la data è inferiore al primo lunedi dell'anno allora appartengono all'ultima settimana dell'anno ` prima quindi calcolo il primo lunedi dell'anno precedente If (xData<FirstMonday) ` come già descritto ma riferito all'anno precedente Jan04DOW:=Day number(Date("04-01-"+String(Year of(xData)-1)))-2 Jan04DOW:=(Num(Jan04DOW=-1)*6)+(Num(Jan04DOW#-1)*Jan04DOW) FirstMonday:=Date("04-01-"+String(Year of(xData)-1))-Jan04DOW End if xWeek:=(Int((xData-FirstMonday)/7))+1 ` calcolo della settimana End if ALERT(String(xWeek)) |
3 | ||||||||||||||||||||||
Info |
[v11 SQL] Passaggio da subtable a tabelle
Nella nota precedente sull'argomento e' stata intrapresa la strada di creare una nuova tabella e trasportarvi i dati della vecchia subtable assegnandogli la relazione nuova. Secondo me molto difficile da realizzare in quanto bisgna crearsi una pocedura che converta tutte le vecchie subtable in tablelle e poi eventualmente cancelli quelle vecchie inutilizzate. Io credo di aver trovato un sistema più veloce. Ho notato che il centenuto del campo in relazione non è altro che il numero del record della tabella in relazione + 1 Eliminate la relazione di tipo subtable (non più ricreabile), i campi ora assumono valore di longint. Ora con una query potrete ottenere i record correlati tipo $recnum:=Record number([Tabella_principale])+1 query([Tabella_relazione];[Tabella_relazione]id_added_by_converter=recnum) Oppure Ricreare la relazione tra i due campi e nel campo dell'archivio principale inserire il valore del numero del record +1 |
1 | ||||||||||||||||||||||
Info |
Alternativa al comando SEND HTTP REDIRECT
Il comando Send Http Redirect in pratica dice al browser che la pagina cercata è stata "temporaneamente" spostato su un altro indirizzo: il browser in modo trasparente all'utente e anche abbastanza velocemente va a cercare il nuovo indirizzo. Il codice seguente simula la chiamata Send Http Redirect con codice 4d: `Metodo web_sendHttpRedirect C_TEXT($1; nuovo_url) $nuovo_url:=$1 ARRAY TEXT($atHeaders;3) ARRAY TEXT($atValues;3) $atHeaders{1}:="X-VERSION" $atValues{1}:="HTTP/1.0" $atHeaders{2}:="X-STATUS" $atValues{2}:="302 Moved Temporarily" $atHeaders{3}:="Location" $atValues{3}:=$nuovo_url SET HTTP HEADER($atHeaders;$atValues) SEND HTML TEXT($nuovo_url) |
1 | ||||||||||||||||||||||
Info |
Le parentesi graffe sotto Win senza codice ASCII *
Programmando sotto Windows, per aprire e chiudere le parentesi graffe, solitamente premo il tasto ALT a sinistra della barra spaziatrice e scrivo sul tastierino numerico in sequenza le cifre 123125. Risulta comunque scomodo sui portatili, dove l'accesso ai NumPad è solitamente condizionato o dall'utilizzo di una "Function key" o dall'attivazione dell'emulazione NumPad sulla tastiera tradizionale. Recentemente, usando un compilatore Java (linguaggio di programmazione che fa largo uso di graffe), ho scoperto che esiste un altro modo per ottenere lo stesso risultato: premere il tasto AltGr a destra della barra spaziatrice, il maiuscolo e i due tasti indicanti le parentesi quadre: anche così si ottiene {} Ecco un elenco completo.
|
7 | ||||||||||||||||||||||
Info |
[v11 SQL] Quando il BLOB non passa il testo alla variabile
Sto ancora guardando se sia un bug o un problema del mio codice, intanto, per sicurezza, pubblico il workaround. Mi capita, lavorando con file di testo Unicode, che il comando BLOB TO TEXT eseguito dopo il DOCUMENT TO BLOB mi restituisca un testo vuoto. Per evitare questo problema, ho deciso di agire differentemente: in una offscreen area di 4DWrite apro il file; da qui trasferisco il testo nella variabile 4D che veniva lasciata vuota dal BLOB TO TEXT. |
3 | ||||||||||||||||||||||
Novizi |
Scorciatoie da tastiera *
Ecco alcune scorciatoie utilizzabili da tastiera: - Chiusura di tutte le finestre di design (eccetto la struttura): Alt+Clik su uno qualsiasi dei bottoni di chiusura. - Chiusura di tutte le finestre di design passando alla modalità User o Custom: Shift mantre si cambia modalità. - Aprire il metodo selezionato: Ctrl+p. - Rinominare gli oggetti solo selezionabili: Ctrl+Clic sul nome. - Copiare il testo selezionato in un posto specifico degli appunti: Ctrl+Shift+un numero da 1 a 9. - Incollare il testo da un posto specifico degli appunti:Ctrl+un numero da 1 a 9. - Selezionare tutti gli oggetti di uno stesso tipo in un form: Ctrl(Command su Mac)+clik su uno degli oggetti da selezionare. - Selezionare/deselezionare tutti gli eventi relativi ad un oggetto: Ctrl(Command su Mac)+clik su un evento. - Creare un subrecord: Ctrl(Command su Mac)+/ (questa impostazione è modificabile usando 4D Customizer Plus). |
4 | ||||||||||||||||||||||
Novita' |
[v11 - Conferenza] SQL injection
Una delle maggiori novità della versione 11 di 4D è l'uso dell'SQL. E' però necessario fare attenzione ad gli inserimenti all'interno dell'ambiente web per creare stringhe SQL. Facciamo il seguente esempio. Supponiamo di avere: SELECT * FROM Contact WHERE Name = :vName dove vName è una variabile proveniente dalla pagina web. Supponiamo che lo smaliziato utente web abbia scritto nella variabile vName Pippo; DELETE * FROM Contact Ci ritroveremmo la tabella totalmente svuotata. |
1 | ||||||||||||||||||||||
Plugin |
4D Chart: CT Chart arrays
CT Chart arrays crea un grafico a partire dai dati memorizzati in alcuni array. La sintassi è: CT Chart arrays (area; type; size; categoryArray; seriesArray; valuesArray) dove "area" è l'area 4D Chart, "type" è il tipo di grafico, "size" è la dimensione iniziale del grafico, "categoryArray", "seriesArray", e "valuesArray" sono gli array contenenti x, y e z del nostro grafico. I tipi di grafico passabili in "type" sono: 1 per il grafico di tipo Area 2 per il grafico di tipo Column 3 per il grafico di tipo Picture 4 per il grafico di tipo Line 5 per il grafico di tipo Scatter 6 per il grafico di tipo Pie 7 per il grafico di tipo Polar 8 per il grafico di tipo 2D XY 100 per il grafico di tipo 3D Column 101 per il grafico di tipo 3D Line 102 per il grafico di tipo 3D Area 103 per il grafico di tipo 3D Surface 104 per il grafico di tipo 3D Triangle 105 per il grafico di tipo 3D Spike A "size" possono essere assegnati i valori 1 = Variabile 2 = Relativa alla finestra (Auto-Variable) 3 = Relativa al grafico (Auto-Document) L'array "categoryArray" è l'array delle X L'array "seriesArray" è l'array delle serie. In un grafico bidimensionale è mostrato nell'asse X, nei tridimensionali è la Y L'array "valuesArray" è l'array contenente i valori. |
1 | ||||||||||||||||||||||
Codice |
Numeri da cifre a lettere
Prima di tutto complimenti per il sito, non solo perché è davvero bello ma perché si vede che c'è chi ci lavora, quindi complimenti a chi lo fa. Mando un frammento di codice che ritengo interessante anche se forse non hamolte occasioni d'impiego; è un method che converte un valore numerico nella corrispondente stringa descrittiva in lettere, esempio 8519 = "ottomilacinquecentodiciannove". Non ho trovato nulla di già fatto per 4D (in italiano). La conversione avviene nel formato usuale per valori in euro con decimali, come si usa per gli assegni, per esempio "trecentoventi/23centesimi"; è modificabile e si puo facilmente omettere o modificare la parte decimale. E' abbastanza compatto, contrariamente a quanto io stesso avevo supposto accingendomi a scriverlo. Uso: passare un valore di tipo reale e torna un tipo testo. Accetta valori da 1 a 999.999.999, genera un messaggio di errore se si passa un valore fuori range. C_REAL($1;$valore) C_TEXT($0;$decimale;$stringa) ARRAY INTEGER($base;8) ARRAY TEXT($descrizione;3) C_INTEGER($X;$gruppo;$valoreDecine) ARRAY TEXT($nome_unità;9) $nome_unità{0}:="" $nome_unità{1}:="uno" $nome_unità{2}:="due" $nome_unità{3}:="tre" $nome_unità{4}:="quattro" $nome_unità{5}:="cinque" $nome_unità{6}:="sei" $nome_unità{7}:="sette" $nome_unità{8}:="otto" $nome_unità{9}:="nove" ARRAY TEXT($nome_10_20;9) $nome_10_20{0}:="" $nome_10_20{1}:="undici" $nome_10_20{2}:="dodici" $nome_10_20{3}:="tredici" $nome_10_20{4}:="quattordici" $nome_10_20{5}:="quindici" $nome_10_20{6}:="sedici" $nome_10_20{7}:="diciassette" $nome_10_20{8}:="diciotto" $nome_10_20{9}:="diciannove" ARRAY TEXT($nome_decine;10) $nome_decine{0}:="" $nome_decine{1}:="dieci" $nome_decine{2}:="venti" $nome_decine{3}:="trenta" $nome_decine{4}:="quaranta" $nome_decine{5}:="cinquanta" $nome_decine{6}:="sessanta" $nome_decine{7}:="settanta" $nome_decine{8}:="ottanta" $nome_decine{9}:="novanta" $nome_decine{10}:="cento" $decimale:=Replace string(String(Dec($1));"0,";"") $decimale:=$decimale+("0"*Num(Length($decimale)=1)) If ($decimale="00") `è uno zero non lettera o $decimale:="zero" End if $valore:=Int($1) If ($valore=0) | ($valore>=(10^9)) ` valori accettati per la parte intera da 1 a 999.999.999 $0:="### ERRORE valore fuori range" Else For ($X;8;0;-1) ` calcola le basi per gli esponenti da 0 a 8 - esempio 825 = 8*(10^2) + 2*(10^1) + 5*(10^0) $base{$X}:=Int($valore/(10^$X)) $valore:=$valore-($base{$X}*(10^$X)) End for $gruppo:=3 `elabora separatamente milioni, migliaia e unità, nell'ordine (si potrebbe anche procedere per ordine inverso, non cambia) For ($X;8;0;-3) If ($base{$X}=1) $descrizione{$gruppo}:="cento" Else $descrizione{$gruppo}:=$nome_unità{$base{$X}}+("cento"*Num($base{$X}>0)) End if $valoreDecine:=$base{$X-1}*10+$base{$X-2} If ($valoreDecine=1) & ($base{$X}=0) $descrizione{$gruppo}:=$descrizione{$gruppo}+("unmilione"*Num($gruppo=3))+("mille"*Num($gruppo=2))+("uno"*Num($gruppo=1)) Else If ($valoreDecine>10) & ($valoreDecine<20) ` se >10 e <20 usa i nomi unidici, dodici, ecc $descrizione{$gruppo}:=$descrizione{$gruppo}+$nome_10_20{($valoreDecine-10)*Num(($base{$X-1})>0)} Else `altrimenti usa i nomi delle decine + i nomi delle unità If ($base{$X-2}=1) | ($base{$X-2}=8) ` se nome unità inizia per vocale omette l'ultima vocale del nome delle decine (ventuno e non ventiuno) $stringa:=Substring($nome_decine{$base{$X-1}};1;Length($nome_decine{$base{$X-1}})-1) Else $stringa:=$nome_decine{$base{$X-1}} End if $descrizione{$gruppo}:=$descrizione{$gruppo}+$stringa+$nome_unità{$base{$X-2}} End if $descrizione{$gruppo}:=$descrizione{$gruppo}+(("milioni"*Num($gruppo=3))*Num($descrizione{$gruppo}#"")) $descrizione{$gruppo}:=$descrizione{$gruppo}+(("mila"*Num($gruppo=2)*Num($descrizione{$gruppo}#""))) End if $gruppo:=$gruppo-1 `elabora il gruppo successivo End for $0:=$descrizione{3}+$descrizione{2}+$descrizione{1}+" e "+$decimale+" centesimi" `concatena i nomi dei 3 gruppi: milioni, migliaia, unità + i decimali End if |
1 | ||||||||||||||||||||||
Tecniche |
Backup degli Utenti in un documento su disco
Già dalla versione 2004 è possibile fare un backup o trasferire gli utenti creati dall'Amministratore con i comandi USERS TO BLOB e BLOB TO USERS. Ecco i due metodi da usare: `Metodo Utenti_Registra C_BLOB($utenti_blb) USERS TO BLOB($utenti_blb) $doc:=Create document("") If (ok=1) CLOSE DOCUMENT($doc) BLOB TO DOCUMENT(Document;$utenti_blb) SHOW ON DISK(Document) End if `Metodo Utenti_Carica C_BLOB($utenti_blb) $doc:=Select document("";"*";"Seleziona il file di backup degli utenti";0) If (ok=1) DOCUMENT TO BLOB(Document;$utenti_blb) BLOB TO USERS($utenti_blb) End if |
1 | ||||||||||||||||||||||
Novita' |
[v11 - Conferenza] Le "Nested transaction"
Con la v11 SQL è possibile utilizzare le transazioni annidate. Il seguente codice è ammesso: START TRANSACTION CREATE RECORD([Tabella1]) START TRANSACTION CREATE RECORD([Tabella2]) SAVE RECORD([Tabella2]) VALIDATE TRANSACTION [...] CANCEL TRANSACTION Alla fine l'ultimo Cancel annulla anche la creazione del record in Tabella2. |
1 | ||||||||||||||||||||||
Info |
[v11 SQL] Da dove posso scaricare 4d ?
La versione di 4D v11 SQL è scaricabile principalmente tramite un installer di piccole dimensioni che scarica dai siti americano o francese l'ultima versione disponibile di quello che si seleziona. Questa è la modalità consigliata e dovrebbe essere più sicura sia come aggiornamento che per velocità (alcune componenti interne ripetute sono scaricate una volta sola). Gli Online installer si trovano qui: http://www.4d.com/products/downloads/download-v11.html Da notare che l'installer tiene in locale quello che è già stato scaricato.. quindi la sua dimensione dovrebbe automaticamente crescere. Alle successive installazioni dovrebbe scaricare solo le componenti eventualmente aggiornate nel frattempo. Per chi invece volesse installare 4d su più macchine ottimizzando quindi il download, esiste la possibilità di scaricare i file completi, da qui: http://www.4d.com/products/downloads/download-v11-FTP.html I file completi sono circa 580MB nella versione Windows multilingua, e 180MB nella versione Inglese per Mac. |
1 | ||||||||||||||||||||||
Codice |
Contare le parole di un testo
Ecco un piccolo metodo per contare il numero di parole presenti in un testo passato come parametro. In maniera banale si contano gli spazi non consecutivi, inserendo inoltre le eccezioni che servono (tipo presenza di trattini). C_LONGINT($numeroparole;$posizione) C_TEXT($1) $numeroparole:=0 If (Length($1)>0) For ($posizione;1;(Length($1)-1)) If (($1[[$posizione]]=Char(32)) & ($1[[$posizione+1]]#Char(32)) & ($1[[$posizione+1]]#"-")) $numeroparole:=$numeroparole+1 End if End for $numeroparole:=$numeroparole+1 End if $0:=$numeroparole |
2 | ||||||||||||||||||||||
Info |
Impedire la connessione ODBC
Se si vuole impedire l'accesso via ODBC ad un particolare database 4th Dimension, ad esempio perché ci sono più server attivi, ma solo alcuni devono essere visibili via ODBC, è possibile negare questo tipo di connessione. Per fare ciò bisogna deselezionare la voce "Allow 4D Open Connections" nelle database properties in questo modo: - aprire il database via 4D Client; - da Design aprire le proprietà del database; - nella pagina "Data control and access" deselezionare "Allow 4D Open connection". La modifica avrà effetto a partire dal successivo riavvio di 4D Server. |
1 | ||||||||||||||||||||||
Bug |
[Risolto] Installer 2004.3 dopo l'installazione della 2004.1
Grazie ad una news pubblicata da 4DToday qualche settimana fa, ho potuto installare 4D 2004.3 su una macchina dove erano stati installati tutti i 4D 2004 precedenti (compresa la versione 2004.1), risolvendo un problema legato a InstallShield. All'inizio dell'installazione della 2004.3, infatti, l'installer segnala un errore 6001. Per risolvere "manualmente" questo problema è sufficiente rimuovere la DLL nel percorso: C:\Programmi\File comuni\InstallShield\Professional\RunTime\0701\Intel32\setup.dll La cartella potrebbe essere nascosta, e quindi accessibile solo o digitandone il percorso o facendo visualizzare al sistema anche cartelle e file nascosti. |
3 | ||||||||||||||||||||||
Comandi |
Esportare dati con EXPORT TEXT *
Il comandi EXPORT TEXT ({table; }document) permette di esportare dati da una tabella a partire dalla selezione corrente (basta dunque eseguire precedentemente una query per esportare solo ciò che serve). L'esportazione viene eseguita utilizzando l'OUTPUT FORM e i campi vengono inseriti nell'ordine in cui si trovano nel form. Gli oggetti non campi (tipo i pulsanti) non vengono considerati. Per ogni record esportato viene generato un evento On Load: così è possibile esportare anche variabili, impostandone i valori in questo evento. Il nome del documento può essere quello di un documento nuovo o esistente. Se già presente, il documento viene automaticamente sovrascritto senza preavviso (se si vuole evitare ciò è bene usare prima il comando Test path name sul nome del documento da creare). Se si passa una stringa vuota come nome del documento viene visualizzata la finestra standard di salvataggio file: se si preme Salva la variabile di sistema OK prende il valore 1. Di default, il delimitatore di campo è la tabulazione (ASCII 9 o Tab) e quello dei record il return (ASCII 13 o CR). E' comunque possibile modificarli cambiando i valori (numerici) delle variabili FldDelimit e RecDelimit. |
2 | ||||||||||||||||||||||
Tecniche |
Deselezionare gli elementi di una listbox **
Le list box "ricordano" la riga selezionata, il che significa che visualizzando uan listbox già visualizzata potremmo trovare una riga già selezionata. Per evitare ciò, se arrEsempio è uno degli array usati dalla listbox ListBox, basta scrivere: SELECT LISTBOX ROW (ListBox; Size of array(arrEsempio)+1) |
7 | ||||||||||||||||||||||
Tecniche |
Metodo di indirizzamento delle stampe [1]
Sottotitolo: [Bug] [Risolto] 2003.6 e 2003.7 OSX 10.3 e 10.4 non imposta la stampante richiesta, non preleva correttamente la carta Ho finalmente avuto il tempo di affrontare questo argomento che nel mio ambiente di lavoro mi creava problemi da quando sono passato alla v 2003. Qui da noi ogni giorno 10 client stampano parecchio materiale, saltando dalle etichette adesive da prelevare dai vassoi, al fogli standard nei cassetti, ai cartellini a colori per il self-service, alle etichette sempre a colori dei prodotti, utilizzando 3 stampati di rete postscript in TCP/IP, alcune stampanti inkjet USB e una Inkjet A3 condivisa. Tutti gli utenti erano costretti a impostare manualmente tutti i parametri per ogni stampa eseguita. Ho esaminato le informazioni che mi è stato possibile trovare in ambito internazionale, sia note tecniche sia messaggi postati ai diversi NUG, testando le soluzioni proposte (alcune delle quali abbastanza astruse, come quella di creare diverse copie dei documenti PPD e di rinominarli al volo da method per costringere l’OS ad usare la configurazione voluta...). Ho trovato una soluzione che finalmente funziona bene e che utilizza i comandi standard, soluzione basata sulle funzioni di salvataggio e recupero dei parametri di stampa in BLOB fornite dal plug-in ACI_Pack. Ciò implica il salvataggio del setup in una table ma a mio parere ne vale la pena. La soluzione è testata con tutte le funzioni di stampa, compresa PRINT FORM, ma non con i QuickReport che non uso. Creazione e salvataggio impostazioni di stampa, è importante la corretta successione dei comandi: 1) eventuale impostazione del formato con PAGE SETUP, se necessario; 2) ottenimento di tutti i parametri di stampa con PRINT SETTINGS; istruendo l’utente a impostare tutti i parametri con attenzione, anche il numero delle copie 3) trasferimento del setup in una variabile BLOB con AP Print settings to BLOB; 4) salvataggio del nome della stampante selezionata; 5) salvataggio del BLOB con i parametri. Esempio, assumendo di avere creato una table [ParametersTable] dove registrare i parametri di stampa C_BLOB($mioBlob) PAGE SETUP ([myTable];"PageSetupForm") PRINT SETTINGS If (OK=1) $error:=AP Print settings to BLOB ($mioBlob) If ($error#1) ALERT ("Errore generando il BLOB dei Parametri di stampa.") Else CREATE RECORD ([ParametersTable]) [ParametersTable]PrinterName:=Get current printer [ParametersTable]ParametersBLOB:=$mioBlob SAVE RECORD ([ParametersTable]) End if End if Nota: è indispensabile trasferire i parametri in una variabile BLOB e poi assegnarla al campo BLOB, non usare la funzione AP Print settings to BLOB con un campo quale argomento della funzione perché poi il BLOB può generare errori. |
1 | ||||||||||||||||||||||
Tecniche |
Eseguire più 4DServer sulla stessa macchina *
È possibile far girare più di una applicazione 4DServer sulla stessa macchina. L'unico accorgimento che bisogna prendere è quello di "customizzare" ognuna delle sessioni. 4DServer pubblica i database sempre sulla stessa porta TCP/IP, e risulta dunque necessario modificare questo parametro per ognuno dei server da attivare. La procedura da seguire inizia con l'individuazione del file tcp.opt nel cartella di sistema 4D; copiare questo file in ognuna delle cartelle dei 4DServer che vogliamo attivare; aprire ognuno dei file (al limite tranne uno, il 19813 standard) col Customizer e modificare il valore della porta con un numero vicino a quello visualizzato e comunque diverso da ognuno degli altri numeri assegnati. A questo punto, lanciando 4DClient, basterà inserire come indirizzo del server xxx.zzz.yyy.aaa virgola numero della porta assegnata in precedenza. |
2 | ||||||||||||||||||||||
Tecniche |
Spostare o copiare una cartella
Come chiesto da Michele Bertoli sul forum 4th Dimension non esiste in maniera nativa un comando 4D che permetta di copiare o spostare una cartella. Le possibilità a questo punto sono - creare la cartella (se serve) con CREATE FOLDER e usare un ciclo di MOVE DOCUMENT o COPY DOCUMENT per spostare i file - usare un file batch che esegua lo spostamento via linea comando, ad esempio: SET ENVIRONMENT VARIABLE("_4D_OPTION_HIDE_CONSOLE";"true") LAUNCH EXTERNAL PROCESS("mycommand.bat") |
1 | ||||||||||||||||||||||
Bug |
[risolto] 4D Engine 2003.7 con Mac OS 10.4.4
Ho aggiornato il sistema operativo del Mac dal 10.3.9 al 10.4.4 e mi sono accorto che non è più possibile creare una applicazione inserendo il 4D Engine versione 2003.7 (resta in grigio chiaro e quindi non selezionabile). Testato il problema su altre tre macchine semore Mac con system 10.4.4 o 10.4.3 identico problema. Unica soluzione trovata: riformattare la macchina e tornare al 10.3.9 sigh..! :( |
2 | ||||||||||||||||||||||
Tecniche |
Merge di due file dati
Franz chiede: Qualche esperto mi saprebbe dire come unire due files di dati in un unico file (subrecords compresi) in modo da avere un unico archivio dati ? Grazie ! Risposta: Usando le due procedure dalla Faq Rapido Trasferimento Dati l'operazione è molto semplice, posto di avere due base dati con la stessa struttura. Quindi, abbiamo le due base dati A e B e vogliamo trasferire tutto da B accodandolo ad A, incluso di subfile, immagini e Blob. 1. Inseriamo nella struttura le due procedure, DB_Esporta e DB_Importa 2. Teniamo la stessa struttura e le due base dati nella stessa cartella 3. Apri la base dati B ed eseguiamo DB_Esporta (crea vari file di passaggio) 4. Apri la base dati A ed esegui DB_Importa (trova i file e li legge) |
1 | ||||||||||||||||||||||
Plugin |
4D Open e i Network Component
Dalla versione di 4D 2003, i componenti non-TCP/IP non sono più usati, per cui il comando OP Load Network Component è obsoleto. L'ID del TCP/IP è 29 su Mac OS e 2 su Windows. Quindi quando viene richiesto un componente in un comando di 4D, bisogna usare direttamente la costante, come nell'esempio: PLATFORM PROPERTIES($sistema_l) If($sistema_l<3) netCompID:=29 `sono su Mac Else netCompID:=2 `sono su Windows End if $error:=OP Select 4D Server (netCompID;$NomeServer;$IDServer;True) |
1 | ||||||||||||||||||||||
Tecniche |
Scelta della chiave primaria
Un punto critico nell'ideare lo schema concettuale di un database è la scelta degli attributi caratteristici dei set di entità che sono in definitiva le tabelle. Un attributo o un insieme di attributi i cui valori identifichino in modo univoco ogni entità del set (record) è chiamato chiave. In linea di principio ogni tabella dovrebbe avere una chiave, in modo che ogni record sia distinguibile dall'altro. Anche se il mondo reale offre a volte delle chiavi naturali, in molti casi è preferibile usare un dato a parte che non possa cambiare per nessun motivo: i programmatori 4D hanno a disposizione per tale fine la funzione Sequence number che genera un numero univoco per ogni record creato per ogni tabella. D'altro canto l'uso di Sequence number ha degli svantaggi da considerare, dovuti proprio alla propria unicità e al legame diretto con la struttura. Per esempio: - in caso di danneggiamento del file dati, quando l'unica soluzione è esportare i dati e ricrearli in un nuovo file; - in caso di esportazione/importazione di dati per il passaggio ad una nuova versione (vedi la faq Rapido Trasferimento Dati); - unione dei dati provenienti da strutture distinte, anche se uguali. Per ovviare a questi inconvenienti è meglio usare dei contatori creati in proprio. Ecco un esempio in cui la tabella [MieiContatori] ha un campo per ogni contatore che voglio tenere: C_POINTER($1;$PuntaAlCampo) C_LONGINT($0) $PuntaAlCampo:= $1 READ WRITE([MieiContatori]) If (Records in table([MieiContatori])=0) CREATE RECORD([MieiContatori]) SAVE RECORD([MieiContatori]) End if ALL RECORDS([MieiContatori]) While (Locked([MieiContatori])) ` controllo se è bloccato DELAY PROCESS(Current process;10) LOAD RECORD([MieiContatori]) End while $PuntaAlCampo-> := $PuntaAlCampo->+1 $0 := $PuntaAlCampo-> SAVE RECORD([MieiContatori]) UNLOAD RECORD([MieiContatori]) READ ONLY([MieiContatori]) |
2 | ||||||||||||||||||||||
Codice |
Calcolo del checksum di un codice a barre EAN13 *
EAN13 è uno dei tipi di barcode più usati (il suo equivalente negli Stati Uniti è il codice UPC-A,che è un sottoinsieme di EAN13, ma dal 2005 i negozi americani devono accettare anche EAN13, eliminando di fatto la differenziazione). Il tredicesimo carattere di un codice EAN13 è il codice di controllo del codice a barre, che viene calcolato utilizzando questo sistema: - Si sommano le cifre del codice di posto pari - Si aggiunge la somma delle cifre di posto dispari, ma moltiplicata per tre. - Il checksum sarà il numero da aggiungere a questa somma per ottenere il primo multiplo di 10 immediatamente superiore. Esprimiamo l'algoritmo di formato 4th Dimension: $check:=0 For ($i;12;1;-1) If (($i/2)#($i\2)) $check:=$check+(Num($String_to_encode[[$i]])) Else $check:=$check+(Num($String_to_encode[[$i]])*3) End if End for $check_S:=String($check) $check:=10-Num(Substring($check_s;Length($check_s))) Fonte: 4D Knowledgebase |
2 | ||||||||||||||||||||||
Tecniche |
Teoria della normalizzazione: dipendenze funzionali *
Cos’è una dipendenza funzionale? Analizziamo il seguente esempio: [CAP] CAP Città Provincia Abbreviazione_nome_regione Nome_Regione Il CAP è un codice univoco di 5 caratteri. Cosa lo rende una chiave? Il fatto che esso determina tutti gli altri campi. Poiché per ogni CAP esistono una singola Città, una singola Provincia, ecc., questi campi sono in dipendenza funzionale rispetto al campo CAP. Osserviamo poi gli ultimi due campi: l’Abbreviazione determina esattamente la Regione, cioè la regione è in dipendenza funzionale rispetto all’Abbreviazione, che ne fa dunque le veci di una chiave. Ma allora, se Abbreviazione_nome_regione è una chiave, questo campo deve appartenere ad un’altra tabella. Ecco, la Terza Forma Normale (3NF) ci dice proprio che dobbiamo allora creare una tabella [Regioni] che avrà come campi Abbreviazione_nome_regione (chiave primaria) e Nome_Regione Consulta da questo link l’indice delle faq sulla normalizzazione |
2 | ||||||||||||||||||||||
Tecniche |
Creare un'immagine lampeggiante *
Per creare un immagine lampeggiante in una maschera, segui questi passi:: 1. Crea un nuova aimmagine nella Picture library. 2. Imposta l'immagine a 2 colonne e 1 riga 3. Incolla l'immagine nel secondo frame, lasciando il primo vuoto. 4. Trascina l'immagine così creata su un form per craere un picture button, chiamato ad esempio PulsanteImmagine. 5. Aggiungi il seguente codice nel metodo del form: If (Form event=On Load) Set Timer(tickCount) `60esimi di secondo, da impostare secondo la velocità desiderata End if If (Form event=On Timer ) If (PulsanteImmagine=0) PulsanteImmagine:=PulsanteImmagine +1 Else PulsanteImmagine:= PulsanteImmagine -1 End if End if |
1 | ||||||||||||||||||||||
Tecniche |
Teoria della normalizzazione: la chiave primaria
Il concetto di “primary key” è fondamentale nella teoria dei database. Il concetto è semplice: ogni record deve avere qualcosa che lo identifichi univocamente. La chiave primaria di una tabella serve inoltre come punto di partenza per la gestione delle relazioni con le altre tabelle: per esempio una fattura è un relazione con un unico e ben determinato cliente, come un impiegato è assegnato ad un unico e ben determinato ufficio. Una chiave primaria deve avere un valore per ogni record. La chiave primaria può essere formata da un campo o dalla combinazione di più campi. Questo dato dei database relazionali ha bisogno di una discussione a parte per quanto riguarda 4th Dimension: se molti sistemi di sviluppo per database usano esplicitamente il concetto di chiave primaria formata da più campi, ciò non avviene in 4D. In realtà è quasi banale bypassare questo limite aggiungendo alla tabella un campo che memorizzi la concatenazione dei campi che compongono la chiave primaria. Una chiave del genere può essere molto facilmente gestita utilizzando i trigger. Una chiave primaria deve essere unica, obbligatoria e immodificabile: un classico errore è quello di attribuire il valore di chiave primaria a campi “volatili”. Ad esempio, per la tabella: [Clienti] Nome Indirizzo il campo Nome sembrerebbe un buon candidato come chiave primaria: sbagliato! Cosa succede se Nome cambia, ad esempio per correggere un semplice errore di inserimento? Dovremo cambiare tutti i record delle fatture di quel cliente. Risulta molto più corretto usare un valore “esterno” ai dati reali, come Sequence number, o qualsiasi altro sistema che generi comunque dei valori da chiave primaria. Per completezza sull’argomento diamo anche la definizione di superchiave, che non è altro che un insieme di campi per i quali la tabella non contiene due record con valori identici per tali campi (non è altro che il superinsieme di una chiave). Inoltre in uno schema relazionale possono esserci più chiavi (ma solo una di esse verrà definita “principale”). Consulta da questo link l’indice delle faq sulla normalizzazione |
1 | ||||||||||||||||||||||
Comandi |
Come usare il Sequence Number
La funzione Sequence Number ritorna un numero progressivo automatico per ogni tabella ed è usato per creare il codice identificativo (o chiave primaria) del singolo record. Parte da 1 alla creazione del database ed è incrementata da 1 per ogni record salvato. La funzione però aveva alcuni limiti per cui era sconsigliata: in pratica poiché non era possibile modificarne il valore corrente diventava difficile, ad esempio, spostare i dati da un database all'altro o ripartire da un certo numero. Finalmente dalla 2004.1 è disponibile un modo accedere al valore usato dal Sequence Number: 1. Get Database Parameter ( Tabella ; Table Sequence Number ) -> Longint Legge il valore corrente del prossimo numero che sarà assegnato dalla Sequence Number per la Tabella passata come primo parametro 2. SET DATABASE PARAMETER ( Tabella ; Table Sequence Number ; Longint ) Imposta il prossimo numero progressivo che sarà generato dalla Sequence Number pe la Tabella. |
1 | ||||||||||||||||||||||
Info |
4th Dimension e Mac OS 10.4 - Tiger *
La prima versione di 4D di comprovata compatibilità col nuovo sistema operativo di casa Apple, Tiger, sarà la 2004.2. Per quel che riguarda le altre versioni al momento non si hanno notizie ulteriori. |
1 | ||||||||||||||||||||||
Comandi |
SET TABLE TITLES e SET FIELD TITLES *
Il comando SET TABLE TITLES permette di nascondere, riordinare o rinominare le tabelle presenti nel database quando questo elenco appare nelle dialog di 4th Dimension, come ad esempio il Query Editor o Quick Report. La sintassi è: SET TABLE TITLES (tableTitles; tableNumbers) dove tableTitles è l'array contenente i nuovi nomi e tableNumbers le attuali posizioni nella struttura (table number). Gli array devono essere sincronizzati. Per non far comparire una tabella basta non includerne titolo e numero negli array. Quindi, ad esempio supponiamo di avere tre tabelle A, B e C, create in questo ordine, e di volerle far apparire come X, Y e Z. Inoltre non vogliamo che la tabella B sia visibile. Infine, vogliamo far apparire le tabelle nell'ordine Z e X. Tutto ciò si fa semplicemente inserendo Z e X nell'array dei nomi e 3 e 1 nell'array delle posizioni. SET TABLE TITLES non modifica la struttura, ma è valido per le semplici sessioni: quindi ad esempio, più 4D Client possono vedere lo stesso database simultaneamente in modo differente. SET TABLE TITLES non ha il potere di modificare l'attributo Invisible attribuito ad una tabella nella struttura: così, una tabella invisibile continuerà ad esserlo, anche se inserita negli array passsati al comando. Il comando SET FIELD TITLES è molto simile, semplicemente applica le stesse considerazioni di SET TABLE TITLES ai campi di una tabella. |
2 | ||||||||||||||||||||||
Plugin |
QPix: un'introduzione *
Ci sono fondamentalmente due possibilità per gestire le immagini in 4D. La prima è quella di usare i comandi del linguaggio standard, la seconda di usare un plug-in esterno. QPix è il plug-in della Escape per il trattamento delle immagini nei database 4th Dimension. Utilizzando la tecnologia di QuickTime, QPix permette, ad esempio: - di acquisire informazioni su un'immagine; - caricarla da un file per visualizzarla in un'area QPix oppure in una variabile o in un campo; - filtrarla e comprimerla; - crearne una thumbnail di qualità normale o alta; - acquisirla da una fonte TWAIN, creando volendo anche dei TIFF multipagina; - esportarla su file in uno dei formati supportati da QuickTime. |
1 | ||||||||||||||||||||||
Plugin |
Backup di 4d Monoutenza *
4dBackup è un plugin forinito con 4d che di solito si usa in versione client-server. E' possibile però usarlo anche in monoutenza, ma o lo si esegue in ambiente User o occorre comandarlo da procedura. Ecco un esempio di utilizzo: C_INTEGER ($Progress_i;$Fill_i) If (BK Begin full backup = 0) If (BK Start copy = 0) Repeat BK GET PROGRESS ($Progress_i; $Fill_i) MESSAGE ("Backup in corso: " + String ($Progress_i) + "%") Until (BK Get state # 4) End if BK END BACKUP End if |
1 | ||||||||||||||||||||||
Info |
Le icone identificative dei campi
Le icone che si trovano accanto ai campi delle tabelle nella Structure window sono rintracciabili usando i numeri di pict a partire da 150, ad esempio: - 150 restituisce l'icona del campo di tipo string; - 151 restituisce l'icona del campo di tipo real; - 152 restituisce l'icona del campo di tipo text; - 158 restituisce l'icona del campo di tipo int; - 159 restituisce l'icona del campo di tipo longint. |
1 | ||||||||||||||||||||||
Macro |
Metodo dei pulsanti *
Scrivendo un metodo per gli oggetti è possibile selezionare gli eventi nelle proprietà e scrivere il codice per gestire solo un particolare evento. Questo purtroppo non è molto leggibile, perche, ad esempio, in fase di debug potresti non sapere se e quale evento è selezionato quando tracci il codice. E' quindi buona norma gestire gli eventi con il solito Case, anche per gestire il clic su un pulsante, che è l'evento più normale. Per facilitare il compito di scrivere sempre la stessa cosa, ecco una macro che lo fa per conto nostro. Case of :(Form event=On clicked) End case Basta incollare questo codice XML nel file Macros.xml file, che si trova nella corrente cartella 4D di sistema, all'interno dei tag A questo punto è possibile usare all'interno del metodo la macro usando il menu contestuale (click-destro su windows o control-click su mac) e scegliendo la macro "OnClicked" dal menu "Insert Macro" |
1 | ||||||||||||||||||||||
Info |
Personalizzazione del Database Structure *
E' possibile modificare lo sfondo standard della finestra del database structure con una immagine personalizzata. IMPORTANTE: LA MODIFICA E' DEFINITIVA, nel senso che non è possibile ritornare all'immagine di sfondo standard di 4D (quella con gli ingranaggi, per intenderci). Per effettuare la modifica: - mettere negli appunti l'immagine che si vuole come sfondo; - cliccare su un punto vuoto (senza tabelle o relazioni) della finestra Database structure; - incollare l'immagine. |
1 | ||||||||||||||||||||||
Novizi |
Jumpstart 4D: ovvero un manuale completo di 4th Dimension
Uno degli aspetti più difficoltosi in cui un utente si imbatte iniziando a programmare con 4D è la vastità di informazioni dove attingere, dove per informazioni intendiamo ovviamente i manuali. Da quale parto? Cosa mi serve? E se non trovo ciò che mi serve? Se le varie faq di introduzione a 4D sono troppo piccole, o se gli articoli di 4D sul passaggio da FileMaker Pro a 4th Dimension non vi hanno risolto il problema, un'altra strada da seguire potrebbe essere Jumpstart 4D, il manuale scritto da Steve Hussey che porta il programmatore ad avere una conoscenza di base ma completa del prodotto, partendo dalla struttura, passando poi agli ambienti User e Custom, password, compilazione e distribuzione del prodotto. Il tutto aiutato dalla costruzione guidata di un piccolo database di gestione fatture. Le informazioni potete trovarle su 4D Press. Jumpstart 4D è acquistabile per $29 in versione cartacea su Amazon o su 4D Store, oppure si può scaricare gratuitamente il PDF dal sito ftp di 4d. |
1 | ||||||||||||||||||||||
Comandi |
Il comando Get indexed string
Utilizzando una sintassi del tipo: Get indexed string (resID; strID{; resFile}) dove: - resID è il numero della risorsa; - strID è il numero della stringa; - resFile è il numero identificativo del resource file da usare, altrimenti, se omesso, tutti i file aperti; il comando permette di ottenere la stringa contenuta nella risorsa lista di stringhe resID in posizione strID. Per ottenere tutte le stringhe di una risorsa di questo tipo si usa invece il comando STRING LIST TO ARRAY. |
1 | ||||||||||||||||||||||
Novizi |
Prima introduzione a 4d: FILE E CAMPI *
Prima cosa creare file e campi, nella terminologia di 4D si usano i termini inglesi Table(s) e Field(s). E qui non ci sono problemi, i campi hanno il loro type (tipo, cioe' se alfa, numerico, ecc.) che e' autoesplicativo. Non esistono campi "calcolati" perche' in 4D ci sono funzioni molto piu' potenti che vedremo in seguito. L'unica nota particolare e' che Tables e Fields non si possono piu' cancellare. Se crei un Table (un file) che poi non ti serve lo lasci dove si trova e basta, semmai lo utilizzerai in seguito se servira'; se non aggiungi records non occupa nemmeno memoria dati. Se in un Table crei un campo che non ti serve, e' bene usare qualche accortezza per evitare di trovarselo tra i piedi: primo dagli un nome che ricordi che e' inutile (per esempio "spurio") poi impostalo come invisibile cosi' non compare inutilmente in giro e poi imposta il type come booleano che e' il type che occupa meno memoria (in RAM e su disco). Nota che i nomi di Tables e Fields si possono cambiare quando si vuole. |
1 | ||||||||||||||||||||||
Codice |
Riconoscere un anno bisestile *
Ecco un piccolo frammento di codice che prende in input un numero e restituisce True se l'anno rappresentato dal numero è bisestile: C_BOOLEAN($0) C_LONGINT($1;$anno_l) $anno_l:=$1 $0:=True Case of : (Dec($anno_l/400)=0) `è bisestile, come il 2000 : (Dec($anno_l/100)=0) `non è bisestile, come il 1900 $0:=False : (Dec($anno_l/4)=0) `è un anno bisestile Else $0:=False End case |
1 | ||||||||||||||||||||||
Codice |
Calcolo del numero della settimana *
Seguendo le regole dell'Iso 8601: - il primo giorno della settimana è Lunedì - una settimana è contata nellanno in cui stanno la maggior parte dei giorni - E possibile avere anche anni con 53 settimane Propongo una soluzione, da testare: $d:=Date("04-01-"+String(Year of(Current date))) $0:=Int((Current date-(1+$d-Day number($d)+(7*Num(Day number($d)>4))))/7)+1 Si sarebbe potuto scrivere su più righe per essere più chiari, o in una riga sola per essere più concisi... |
1 | ||||||||||||||||||||||
Info |
Help in linea di 4D [4] : 4D Help Html
Un Help in linea molto completo è quello in versione HTML consultabile con un browser. Questo tipo di Help si richiama premendo il tasto funzione F1 dopo aver selezionato un comando 4D (su Windows non dovrete aver installato 4d.HLP). Viene aperto il vostro browser e mostrata una pagina con la sintassi e tutte le informazioni utili sul comando scelto. Da questa finestra utilizzando i vari link è possibile consultare tutti i comandi di 4D, in pratica il Language Reference, e tutte informazioni di maggior utilità sui vari programmi e Plugin che fanno parte delle soluzioni 4th Dimension. Tutto ciò è contenuto nella cartella Documentation (di 54,9 Mb): i file si possono scaricare dall' ftp di 4D.com (versione Macintosh o Windows) oppure copiare dal CD di installazione. Copiata la cartella sul disco (magari nella stessa folder dove avete messo l'applicativo), per poter richiamare in maniera veloce questo Help come sopra spiegato bisogna specificare a 4D dove si trovano i documenti HTML dal menu: 4th Dimension | Preferences | Design mode | Documentation qui scegliere Local folder e sfogliare il percorso fino alla vostra cartella Documentation. |
1 | ||||||||||||||||||||||
Tecniche |
Mettere una formula nel subtotal di Quick Report *
Anticipo che il titolo non è proprio veritiero, nel senso che quanto scritto è possibile solo passando poi da excel. L'esempio è avere un report che riporti le vendite di quest'anno paragonate alle vendite dell'anno passato calcolando il delta. Nel nostro report avremo una colonna con le vendite1 una colonna con le vendite 2 e una colonna calcolata 100-(vendite1*100)/vendite2). Se volessimo avere un break per regione non esiste sistema per poter calcolare il delta nel subtotal. Il sistema che ho trovato si basa sul fatto che se scriviamo nel subtotal all'interno della cella della terza colonna una formula che non sia una delle sue, quick report riporta pari pari la scritta. In excel esiste la funzione "R1C1 reference style" che deve essere settata, fatto questo nella nostra cella possiamo mettere "=100-((RC1*100)/RC2)" senza apici. Se questo report lo esportiamo come HTML e lo apriamo con Excel avrete il risultato anche nel subtotal. Uso html per il mantenimento della grafica. |
1 | ||||||||||||||||||||||
Tecniche |
Cambiare dinamicamente gli Help Messages *
Forse non tutti sanno che è possibile modificare il contenuto degli Help Messages (le micro finestre gialle che forniscono info sugli oggetti dei forms posizionando il cursore su di essi) in modo dinamico e sensibile al contenuto o al contesto. Basta applicare la già nota tecnica illustrata nell'articolo "Displaying variables and field values in Text objects" presente nell'elenco 4D Tech Tips della home: - dedicare una variabile Text a questo scopo, per esempio vTxt_OKbuttonHelp - nella finestra di definizione dell'oggetto aprire il tab all'ultima posizione dove si impostano gli help messages - nel campo "Help message" inserire in nome della nostra variabile tra i caratteri "<" e ">" così < vTxt_OKbuttonHelp > l'help mostrerà ora il contenuto della variabile che può essere definito da codice, per esempio: If (MyField # "") ENABLE BUTTON(vBt_OK) vTxt_OKbuttonHelp:="Conferma la scheda e registra le modifiche" Else DISABLE BUTTON(vBt_OK) vTxt_OKbuttonHelp:="Conferma la scheda, non attivo perchè mancano dei dati" End if |
1 | ||||||||||||||||||||||
Codice |
Chiudere i processi correttamente uscendo da 4D *
Il metodo On Exit Database viene eseguito all'uscita del database. Questo metodo viene eseguito da 4D quando viene eseguita un'istruzione QUIT 4D o quando viene scelta la voce di chiusura applicazione da menu. Se il metodo On Exit Database è vuoto, l'applicazione verrà chiusa immediatamente (senza tenere conto quindi delle operazioni attualmente in esecuzione), altrimenti, se contiene del codice, 4D attende per chiudersi che il metodo venga portato a termine: possiamo sfruttare questa attesa per far sì che i processi attivi vengano chiusi con cognizione. Intanto, all'apertura del database impostare la variabile booleana <>StoChiudendo_b impostandola a False. A questo punto nell'On Exit Database la impostiamo a True e "risvegliamo" ogni processo: <>StoChiudendo_b:=True For ($i;1;Count tasks) RESUME PROCESS($i) CALL PROCESS($i) End for Così facendo il programma sa che 4D sta per chiudersi: ragion per cui si dovrebbe programmare ogni metodo che usa dei cicli e che vogliamo sia chiuso correttamente in maniera tale da controllare lo stato di "chiusura" di 4D guardando il valore della variabile <>StoChiudendo_b. Per quel che riguarda invece i metodi dei form, visto come abbiamo scritto il metodo di chiusura, viene generato un evento On Outside Call che possiamo gestire: Case of : (Form event=On Outside Call) If (<>StoChiudendo_b) CANCEL ` o qualsiasi altra istruzione sia necessaria End if End case |
1 | ||||||||||||||||||||||
Codice |
Aumentare la casualità del comando Random
Il comando Random restituisce un un numero a caso tra 0 e 32.767. Può capitare che il numero casuale che cerchiamo sia oltre questo limite. Inoltre il tipico uso che viene fatto del comando è quello di restituire un numero compreso in un certo intervallo. Ecco quindi un semplice metodo per aumentare le potenzialità del comando Random: C_LONGINT($minimo_l;$massimo_l;$1;$2) $minimo_l:=$1 $massimo_l:=$2 C_LONGINT($aCaso_l;$0) If ($minimo_l=$massimo_l) $aCaso_l:=(Random*Random) Else $aCaso_l:=((Random*Random)%($massimo_l-$minimo_l+1))+$minimo_l End if $0:=$aCaso_l |
1 | ||||||||||||||||||||||
Web |
Servire le pagine web inesistenti con 4D
La parte web di 4D permette di servire o pagine fisiche o pagine generate da codice. Se non è possibile soddisfare la richiesta, 4D invia un mesaggio standard di pagina non trovata al browser. È però possibile modificare questa pagina aggiungendo una risorsa alla struttura nella maniera che segue: - aprire 4D su Mac con un editor di risorse; - copiare la risorsa Html numero 45 nella struttura; - copiare il contenuto della risorsa in un editor html o un editor di testo per effettuare le modifiche; - copiare di nuovo l'HTML modificato nella risorsa. A questo punto la pagina servita per le pagine non trovate sarà quella da noi modificata. |
1 | ||||||||||||||||||||||
Info |
Help in linea di 4D [1] : Explorer Help *
All'interno della finestra di method editor, dopo aver terminato di scrivere un comando di 4D, l' Explorer Help visualizza la sintassi del comando nella parte alta della finestra. Perché questo funzioni deve essere installato un file, che fornisce le informazioni di aiuto, il suo nome è "4D Help" su Macintosh e "4D Help.RSR" su Windows. Questo file di help non va confuso con il Menu di Help, che utilizza un altro file chiamato 4D.HLP. "4D Help" per l'Explorer Help può essere comodamente scaricato dal sito ftp di 4D.com da questo indirizzo ed installato nella seguente cartella di sistema: Macintosh = Library:Application Support:4D Windows = C:\Document and Settings\All Users\Application Data\4D Dopo l'installazione l'Explorer Help è fruibile su quel computer sia se utilizzate un 4D Client oppure una versione Desktop. |
1 | ||||||||||||||||||||||
Info |
4th Dimension, MS Access e FileMaker Pro [5] Inserimento nei campi **
Controllo dell'inserimento nei campi I filtri di inserimento controllano i caratteri che è consentito digitare in un campo (o in una variabile) da parte dell'utente. Per esempio se voglio controllare l'inserimento di un codice fiscale posso mettere un filtro del tipo "˜A######&9##˜A#&9##˜A#&9###˜A#". Dei tre sistemi solo Access e 4D possiedono questa caratteristica, non FileMaker. Inoltre in FileMaker non è possibile controllare un evento del tipo "on data change" che permetta di eseguire del codice all'uscita da un campo a controllare i dati appena inseriti o modificati. Consulta da questo link l’indice delle faq su 4th Dimension, MS Access e FileMaker Pro |
2 | ||||||||||||||||||||||
Info |
4th Dimension, MS Access e FileMaker Pro [4] La sicurezza *
La sicurezza Sul versante sicurezza i tre sistemi risultano abbastanza differenti. In FileMakerPro non esiste una combinazione utente - password come gli altri sistemi, ma supporta solo password. Inoltre le password sono definite a livello dei file, il che significa che per cambiare una password è necessario aprire tutte le tabelle. Il modello di sicurezza di Access è abbastanza flessibile: possono essere definiti utenti, gruppi di utenti, e i privilegi possono essere assegnati ai singoli utenti o ai gruppi. Anche 4D permette la creazione di utenti con password e gruppi di utenti e la gestione dei privilegi. Una differenza assai significativa sta nella possibilità di usare una protezione SSL nella comunicazione tra 4D Server e 4D Client: ciò comporta ovviamente una maggiore sicurezza delle comunicazioni, impedendo di fatto un loro intercettamento e/o alterazione. Consulta da questo link l’indice delle faq su 4th Dimension, MS Access e FileMaker Pro |
1 | ||||||||||||||||||||||
Info |
4th Dimension, MS Access e FileMaker Pro [3] I form *
I form Se da un lato tutti e tre i prodotti consentono una facile creazione di un form grazie ai wizard, d'altro canto il tipo di oggetti e la possibilità di personalizzarli risulta ben differente. 4D, ad esempio, possiede oggetti per i form che non sono presenti in Access o in FileMaker, come popup menu grafici o gerarchici, liste gerarchiche, splitter, matrici di pulsanti. FileMaker non possiede inoltre i Tab Control, utili ad esempio per gestire form multipagina. FileMaker Pro 7 ha finalmente apportato delle cospicue migliorie nella personalizzazione dei form: a differenza delle versioni precedenti, infatti, risulta possibile indicare dimensione e coordinate delle finestre, nonché aprire più fineste della stessa tabella contemporaneamente, ognuna con una selezione differente. Continuano però a mancare, ad esempio, i tips al passaggio del mouse su un pulsante. In Access, a differenza di 4D o FileMaker, un form non appartiene ad una tabella specifica: ciò significa che il form non sa, in partenza, quale è l'origine da cui prendere i dati. 4th Dimension permette una notevole personalizzazione dell'interfaccia, ad esempio: - controllo su posizione, tipo e dimensione delle finestre; - più form per la stessa tabella aperti contemporaneamente; - visibilità controllabile degli oggetti; - form multipagina; - tips su tutti gli oggetti del form; - stili personalizzati che controllano l'aspetto dell'applicazione a seconda del sistema operativo usato, e non solo windows-mac ma anche per le diverse versioni sulla stessa piattaforma; - personalizzazione della corrispondenza fra combinazioni su tastiera e voci di menu, pulsanti, azioni. Consulta da questo link l’indice delle faq su 4th Dimension, MS Access e FileMaker Pro |
1 | ||||||||||||||||||||||
Info |
4th Dimension, MS Access e FileMaker Pro [2] Creazione della struttura *
Creazione della struttura Il primo passo passo da compiere nella progettazione di un database è la creazione della struttura, intesa come definizione di tabelle, campi e relazioni. In Access la struttura viene creata attraverso un'interfaccia tipo foglio di calcolo, in cui ogni riga rappresenta un campo (colonna) della tabella. Per ogni campo possono essere definiti molti attributi. La definizione delle relazioni dovrà essere impostata in una finestra a parte. Anche in FileMaker definizione della struttura e definizione delle relazioni avvengono in finestre separate: con la versione 7 è stato abbandonato il sistema ad elenco per passare ad una più moderna ed intuitiva visualizzazione grafica (nonché simile a quella degli altri due sistemi). Rispetto ad Access (e anche a 4D), FileMaker introduce un nuovo tipo di campo, il "campo calcolato", croce e delizia dei programmatori FMP. I campi calcolati vengono definiti usando un editor specifico e vengono trattati alla stessa stregua dei campi "standard": FileMaker si occupa di effettuare il calcolo quando ritiene necessario; se da un lato questo tipo di approccio può sembrare conveniente, esso in realtà nasconde dei problemi. Intanto, visto che il programmatore non ha controllo sull'esecuzione dei calcoli, le prestazioni possono abbassarsi irrimediabilmente. Inoltre, malgrado la versione 7 permetta di creare un file di dati separato dal file contenente script e layout, non risulta un'operazione semplice trasferire nel file della struttura i campi calcolati. In 4th Dimension la creazione di tabelle, campi e relazioni avviene contemporaneamente nell'unica finestra "Database structure". Cliccando sul titolo di una tabella si inseriscono i dati relativi alla tabella, cliccando su un campo si personalizzano i dati del campo, eseguendo un trascinamento da un campo ad un altro si crea una relazione molti a uno dal campo di partenza a quello di destinazione del trascinamento, cliccando sulla linea che definisce una relazione si impostano le proprietà della relazione. Consulta da questo link l’indice delle faq su 4th Dimension, MS Access e FileMaker Pro |
1 | ||||||||||||||||||||||
Info |
4th Dimension, MS Access e FileMaker Pro [1] NOMENCLATURA *
Con questa faq iniziamo a trattare alcuni degli argomenti che possono aiutare gli sviluppatori che vengono da un altro sistema di sviluppo. Premesso che ogni strumento di programmazione ha i propri pregi e i propri difetti, l'obiettivo che ci possiamo prefiggere è quello di aiutare chi conosce già MS Access o FileMaker Pro e desideri passare a 4th Dimension, sfruttando in una certa misura le conoscenze già acquisite sulle altre piattaforme, trovando e analizzando sia i punti comuni che le sostanziali differenze. Le informazioni saranno ovviamente più precise su 4D, perché è l'ambiente che conosciamo meglio e su cui siamo ovviamente più aggiornati: è possibile dunque ad esempio che alcune caratteristiche di FileMakerPro 7 non siano citate completamente e/o correttamente. Dopo questa necessaria introduzione passiamo all'argomento vero e proprio della faq. NOMENCLATURA: ognuno dei tre sistemi di sviluppo definisce in maniera propria le componenti standard di un database: vediamo di uniformare il linguaggio. - Tabelle: solo in FileMaker assumono una definizione diversa, cioè File. - Campi: solo in Access assumono una definizione diversa, cioè Colonne. - Maschere: i termini maschera, form, layout sono variamente utilizzati. - Automazione: 4D usa degli oggetti chiamati metodi; Access usa macro e script Visual Basic; FileMaker calcoli automatici e script. - Struttura: una finestra di relazioni è presente in tutte le piattafome; la struttura di un database 4th Dimension visualizza e permette l'inserimento di tabelle e campi. - Lista di records: ognuno dei tre sistemi ha il suo modo di chiamare la lista di records: ad esempio se per 4D è il layout di output, per Access è la visualizzazione per foglio di calcolo. - Ricerche: per costruire le query Access usa un editor, FileMaker effettua la ricerca da form, 4D esegue entrambi i tipi di ricerca con Query by example (che permette la ricerca sul form di inserimento dei dati) e Query editor (un editor visuale che permette la costruzione di una query) - Selezione di records: ognuna delle tre piattaforme permette di gestire l'insieme dei record attualmente scelti. Consulta da questo link l’indice delle faq su 4th Dimension, MS Access e FileMaker Pro |
1 | ||||||||||||||||||||||
Info |
Uso delle risorse di 4D Client * con metodo aggiorna - signature
Usando 4D in versione client - server, sulla macchina client vengono creati dei file locali (che evitano traffico ridondante sulla rete). Se 4D Client va in crash o ha dei comportamenti inaspettati, il primo tentativo da fare è sicuramente quello di cancellare questi file temporanei, in modo da costringere 4D Client, al prossimo avvio, a ricrearli. Per effettuare la cancellazione manualmente bisogna chiudere 4D Client, quindi cercare una cartella sul disco che si chiama come la struttura che stiamo usando e cancellarla. Alcuni dei posti dove cercare questa cartella possono essere: HD:System Folder:Application Support: (OS9) /Library/Application Support/4D/ (OSX) C:\WINDOWS\4D\ (WIN) Un'altra strada percorribile per ottenere lo stesso risultato è quella di modificare il valore della risorsa "4D4D" nella struttura: in questo caso sarà il server a forzare l'aggiornamento, poiché il valore di questa risorsa deve essere identico fra Server e Client, e 4D Server effettua questo controllo ad ogni connessione. La modifica del valore presente in questa risorsa si può effettuare aprendo la struttura con 4D Customizer Plus e cliccando sull'icona "Update". |
1 | ||||||||||||||||||||||
Info |
Usare 4D Client come fosse l'Engine**
Da un colloquio avuto da poco con Anna Cernuschi di Italsoftware sono venuto a conoscenza di una caratteristica di 4D Server che volentieri condivido. Se i vostri clienti si lamentano perché perché aprire un programma in versione server è troppo lungo (apri il client, scegli l'applicazione corretta, inserisci utente e password), potete creare un file di "scorciatoia" che eviti alcuni o tutti questi passaggi. Aprite l'applicazione dal client e, dal design, andate nella finestra password. Selezionando un utente, si abiliteranno due voci di menu che permettono il salvataggio dell'utente con o senza password. Scegliamo ad esempio di salvare l'utente con password: dalla maschera standard di salvataggio diamo un nome e una posizione al file. Il file creato è di tipo client connection: aprendolo con 4D Client l'utente farà accesso al programma senza dover eseguire la trafila precedentemente descritta, come se avesse l'eseguibile o la struttura in locale sulla sua macchina. |
3 |
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