
Naviga:
|
Ho trovato 712 faq.
| Categoria | Argomento | Commenti | |||||||||||||||||||||
Info |
[v12] Un nuovo metodo per riparare la base dati
La più recente versione di 4D ha introdotto un nuovo metodo per il ripristino di una base dati danneggiata. Oltre alla procedura standard (da usare quando indici o record sono danneggiati) è stato introdotto un "Recover by record headers" che permette il ripristino dei dati quando ad essere danneggiata è tabella degli indirizzamenti dei record, può essere utilizzato questo sistema assai più complesso. Il procedimento è da utilizzare solo quando gli altri metodi non sono andati a buon fine. Al termine del processo non è garantita comunque l'unicità dei record (i record potrebbero comparire due volte) e il mantenimento della proprietà "Never null" dei campi. Infatti se nella tabella è stato deselezionato "Records definitively deleted" potrebbero ricomparire dei record eliminati. Il sistema è diverso dal vecchio "Recover by tags" perché richiede l'intervento dell'operatore in quanto alcuni passi mostrano una finestra di richiesta conferma. |
||||||||||||||||||||||
Info |
Le caratteristiche di 4D che verranno rimosse in futuro
Ecco un elenco delle "Depercated features" che 4D ha segnalato come caratteristiche che verranno rimosse con le prossime versioni. Cosa verrà rimpiazzato / Con cosa / da Quando 4D Chart (plug-in area) / SVG, webarea, PHP / Più avanti 4D Draw / SVG / (Rimosso dalla v11) 4D Open / Synchronization, WebServices, SQL Pass Thru / (Rimosso dalla v11) PICT / Modern formats / Dipende dal Sistema QuickDraw Patterns (form object property) / SVG, picture con “Replicated format” / Presto Mac Resources / Usa “Resources” folder Sistema operativo / (Presto) Old Looks / Usa System looks / Presto Altura Mac2Win / Codice Windows nativo / Presto SubTables / Usa tabelle N->1 / Più avanti Web Contextual Mode / Usa il non-contextual mode / Presto Non Unicode mode / Passa a Unicode / Presto |
||||||||||||||||||||||
Info |
Migliori performance con Windows Server 2003 o 2008
Ecco alcune impostazioni consigliate per l'uso di 4d su Windows Server 2003 e 2008: Windows Processor Scheduling: settato a “Programs” invece di “background processes”. Windows Memory: settato a “Programs” invece di “System Cache”. Windows Page File: settato a “System Managed Size” invece di “Custom Size”. La posizione di queste impostazioni varia da sistema a sistema, ma tipicamente si possono trovare in questo modo: Fai clic su Start, poi Run, e scrivi "sysdm.cpl". Nella finestra System Properties, fai clic sul tab Advanced, e poi clic su Settings sotto Performance. Le raccomandazioni si applicano sia a 4d Monoutenza che Server, sia quando viene lanciato come servizio che in modalità utente. |
||||||||||||||||||||||
Comandi |
Aggiornare la gestione degli Eventi dei form
I seguenti comandi sono stati dichiarati obsoleti e andrebbero sostituiti dalla versione 11 in avanti: Deactivated Activated In Header In Break In Footer Before During After Outside call Quindi i pezzi di codice nei metodi dei form di questo tipo: If(Activated) ORDER BY([Tabella];[Tabella]Campo;>) ` ... End if Deve diventare così: If(Form event=On Activate) ORDER BY([Tabella];[Tabella]Campo;>) ` ... End if Questa è la lista delle costanti del comando Form Event da utilizzare al posto dei vecchi comandi: Command Form Event Deactivated -> On Deactivate Activated -> On Activate In Header -> On Header In Break -> On Printing Break In Footer -> On Printing Footer After -> On Validate I comandi Before e During sono un po' più complessi: Command Form Event Before -> On Load Before -> On Display Detail Before -> On Printing Detail During -> On Clicked During -> On Double Clicked During -> On Losing Focus During -> On Getting Focus During -> On Menu Selected During -> On Data Change During -> On Close Box During -> On Printing Detail During -> On Open Detail During -> On Close Detail Ad esempio a volte si usava la coppia Before e During assieme: (Before & During) -> On Display Detail |
||||||||||||||||||||||
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 | |||||||||||||||||||||
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 |
1 | |||||||||||||||||||||
Info |
[v11 SQL] Le tabelle di sistema di 4D per SQL: _USER_TABLES
In accordo con le specifiche SQL, 4th Dimension contiene delle tabelle di sistema che descrivono la struttura del database:
La prima che andiamo ad analizzare è la _USER_TABLES, che contiene la descrizione delle tabelle del database. I campi che la compongono sono: TABLE_NAME - VARCHAR - Il nome della tabella; TEMPORARY - BOOLEAN - Vero se la tabella è temporanea, altrimenti Falso; TABLE_ID - INT64 - Il numero della tabella; SCHEMA_ID - INT32 - Il numero dello schema; Così, come segnalato da Francesco Pandolfi sul NUG italiano, è possibile controllare se una tabella con un certo nome esiste usando il codice: C_INTEGER($cnt) C_TEXT($tabName) $tabName:=$1 Begin SQL select count(*) from _user_tables where table_name = :$tabName into :$cnt; End SQL If ($cnt>0) `esiste Else `non esiste End if |
||||||||||||||||||||||
Info |
[v11 SQL] Cercare una stringa in tutta la base dati
Ecco di seguito un metodo per cercare un qualsiasi dato fra i campi alfanumerici di un database. Quando ogni dato viene trovato, restituisce un messaggio con tabella e campo in cui si trova il valore. $quanti:=Get last table number For ($i;1;$quanti) If (Is table number valid($i)) For ($j;1;Get last field number($i)) If (Is field number valid($i;$j)) GET FIELD PROPERTIES($i;$j;$fieldType;$fieldLen;$indexed) If (($fieldType=Is Alpha Field ) | ($fieldType=Is Text )) $valoreSt:=$1 $tabellaptr:=Table($i) $campoptr:=Field($i;$j) QUERY($tabellaptr->;$campoptr->=$valoreSt) If (Records in selection($tabellaptr->)>0) ALERT("["+Table name($i)+"]"+Field name($i;$j)) End if End if End if End for End if End for ALERT("Finito") |
||||||||||||||||||||||
Info |
[v11 SQL] Risalire al numero di tabella (o alla sua esistenza)
Col seguente codice si può chiedere a 4D se una tabella esiste: C_TEXT($1) ` Table name C_BOOLEAN($0) C_LONGINT($i) $i:=1 $0:=False While(($i<=Get last table number)&(Not($0))) If (Is table number valid($i)) If (Table name($i)=$1) $0:=True End if End if $i:=$i+1 End while Una variante può permettere di sapere il numero di tabella, se non esiste restituisce -1: C_TEXT($1) ` Table name C_LONGINT($i;$0) $i:=1 $0:=-1 While($i<=Get last table number) If (Is table number valid($i)) If (Table name($i)=$1) $0:=$i $i:=Get last table number+1 End if End if $i:=$i+1 End while |
||||||||||||||||||||||
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 |
Un pulsante con più scorciatoie per la tastiera
Può capitare di dover associare a un pulsante più scorciatoie da tastiera: il caso più classico è un pulsante a cui è associato il pulsante "Carriage return" al quale si vuole associare anche il pulsante "Enter". Ovviamente una possibilità è quella di duplicare varie volte il pulsante (con pulsanti nascosti), e a ogni copia assegnare la scorciatoia desiderata: l'inconveniente è che la modifica del codice di un pulsante costringe a modificare (o duplicare nuovamente) tutti gli altri. Soluzione più agevole è quella di far invece "puntare" tutti i pulsanti copia al pulsante principale. Nell'esempio visto prima, nell'On clicked del metodo del pulsante associato ad "Enter" ci sarà scritto: POST KEY(Carriage return) |
||||||||||||||||||||||
Info |
[v11 SQL] Le query sui campi NULL e Map NULL values to blank values
La particolarità di un campo NULL sta proprio nel suo valore "speciale". Per tale motivo, se viene eseguita una query cercando una stringa vuota, i campi alpha/text contenenti il valore NULL non saranno presi in considerazione: questo significa che per trovare tali record è necessario scrivere del codice aggiuntivo. Per evitare tali problematiche è possibile attivare nelle proprietà del campo l'opzione Map NULL values to blank values; questa, infatti, agisce a un livello molto basso del database, poiché assimila i valori NULL ai valori di default (stringa vuota, data 00/00/00, ecc.) del relativo campo. Questa opzione è sempre attiva in automatico per ogni campo. |
||||||||||||||||||||||
Info |
[v11 SQL] I valori di default per i NULL
Quando si gestiscono dei valori NULL, 4D esegue in automatico delle conversioni quando questi valori vengono usati. Se viene infatti eseguita l'istruzione: miaAlphavar:=[table1]MioAlphafield la variabile miaAlphavar prenderà il valore "". In generale, le conversioni a tali valori di default vengono eseguite secondo questo schema: • Per Alpha e Text: "" • Per Real, Integer e Long Integer: 0 • Per Date: 00/00/00 • Per Time: 00:00:00 • Per Boolean: False • Per Picture: immagine vuota • Per Blob: blob vuoto |
||||||||||||||||||||||
Comandi |
[v11 SQL] I valori NULL nei campi
Con la versione 11 e l'introduzione del motore SQL, anche con 4D è possibile gestire i valori NULL. Un esempio di campo NULL è un booleano che contiene i valori Maschio/Femmina quando si censisce un'anagrafica: finché l'utente non setta il valore corretto il valore del campo è NULL. Per impostare il valore di un campo a NULL si usa il comando SET FIELD VALUE NULL, mentre per sapere se il valore del campo è NULL si usa il comando Is field value Null. |
||||||||||||||||||||||
Plugin |
Quando gli SMTP_Attachment vengono scambiati per virus
Utilizzando due diversi server SMTP di Telecom Italia (un ADSL standard e un Interbusiness) per inviare dei pdf ad un servizio di fax server, su uno dei due capitava che il messaggio consegnato non fosse il pdf inviato, bensì un fax che recitava: "Il file è stato rimosso perché potenzialmente pericoloso". Dopo varie richieste ai tecnici Telecom si è trovata la causa: l'attach veniva inviato come UUEncode utilizzando SMTP_Attachment ( smtp_ID ; fileName ; encodeType ; deleteOption ) dove encodeType valeva 7. Ora, il file veniva codificato al momento dell'esecuzione del comando SMTP_Send. Ciò però comportava che la dimensione comunicata (del file di partenza) e quella reale (del file codificato) risultassero diverse, facendo credere al server SMTP che al file allegato fosse stato agganciato del codice malevolo. La soluzione è stata però agevole: è bastato infatti utilizzare il comando IT_Encode ( fileName ; encodedFile ; encodedMode ) utilizzando come encodedMode sempre 7, UUEncode. A questo punto basta eseguire SMTP_Attachment come prima ma usando come file da allegare encodedFile e come encodeType il valore -7, che per 4D significa che il file allegato è già codificato come UUEncode. Non variando a questo punto la dimensione dell'allegato, il file viene correttamente inviato. |
||||||||||||||||||||||
Tecniche |
Selezioni ordinate con CREATE SELECTION FROM ARRAY
CREATE SELECTION FROM ARRAY permette di creare selezioni ordinate di record. Supponiamo di voler utilizzare dei record in un ordine ben preciso (per esempio i clienti in ordine di fatturato, dove il fatturato deve essere calcolato "al volo"). Una soluzione è popolare un array con i record number dei clienti e il loro fatturato, ordinare i due array secondo quello col fatturato poi usare. Ecco un codice di esempio: SELECTION TO ARRAY([Tabella];$arrayRecordNumer;[Tabella]campoX;$arrayX;Tabella]campoY;$arrayY) ARRAY REAL($arrayFatturato;size of array($arrayRecordNumer)) `... elaboro i campi X e Y per ottenere il fatturato che vado a scrivere nell'iesimo elemento del nuovo array arrayFatturato SORT ARRAY($arrayFatturato;$arrayRecordNumer) CREATE SELECTION FROM ARRAY ([Tabella]; $arrayRecordNumer; "") Con l'ultimo comando creo la selezione ordinata. |
||||||||||||||||||||||
Comandi |
[v11 SQL] Dimensione dei parametri testo in plugin esterni come Stmp_body
Benchè le variabili testo di 4D abbiano superato il limite di 32K ci sono ancora dei comandi che hanno parametri testo che richiedono questo limite. Uno di questi è SMTP_Boby che richiede che il teso passato sia ancora limitato a 32K. Se usate delle righe di codice come le seguenti per creare il corpo della email. $offset:=0 While ($offset<BLOB size(Mail_Blob)) $body:=BLOB to text(Mail_Blob;Text without length ;$offset) $noError:=(ErrCheck ("SMTP_Body";SMTP_Body ($Smtp_id;$body;2))) End while Ricordatevi che lo stesso metodo nella v11 to text deve diventare cosi: $body:=BLOB to text(Mail_Blob;Text without length ;$offset;$maxsize) $offset:=0 $maxsize:=30000 While ($offset<BLOB size(Mail_Blob)) $body:=BLOB to text(Mail_Blob;UTF8 Mac Text without length ;$offset;$maxsize)) $noError:=(ErrCheck ("SMTP_Body";SMTP_Body ($Smtp_id;$body;2))) End while dove $maxsize deve essere inferiore o uguale a 32K |
||||||||||||||||||||||
Info |
Avviare lo spegnimento automatico del PC Windows da 4D
E' possibile spegnere automaticamente il computer utilizzando il comando LAUNCH EXTERNAL PROCESS. Il comando deve essere eseguito nel "On Exit" (se serve distinguere fra versioni monoutente, client o server, e in caso usare "On Server Shutdown") così: LAUNCH EXTERNAL PROCESS("shutdown -s -t 100";$tIn;$tOut) attendendo 100 secondi prima di spegnere la macchina (un tempo ragionevole per pensare che 4D sia uscito). Se si aggiunge il parametro -f: LAUNCH EXTERNAL PROCESS("shutdown -s -t 100 -f";$tIn;$tOut) Windows forzerà la chiusura dei processi. Se mentre il sistema si sta chiudendo ci si ricorda che c'era qualcos'altro da fare, nel database method "On Sturtup" si può inserire: LAUNCH EXTERNAL PROCESS("shutdown -a";$tIn;$tOut) per annullare un precedente spegnimento avviato. |
||||||||||||||||||||||
Info |
[v11 SQL] Display Format e il punto e la virgola
Il formato è la stringa di testo del tipo "###.###,00" con cui puoi modificare la modalità di visualizzazione di un numero (c'è anche per data, ora, booleano) Mentre fino alla versione 2004 nel formato il punto e la virgola rispecchiavano le impostazioni del sistema corrente, nella versione v11 (finalmente!) il punto sta sempre per la posizione dei decimali e la virgola per il separatore delle migliaia. Cioé rende il programma facilmente utilizzabile anche in quegli ambienti dove si usano impostazioni 'americane' pur trovandosi in italia, ad esempio. Questa impostazione è di default per le strutture create con la v11, mentre per quelle convertite dalle versioni precedenti esiste l'opzione Use period and comma as placeholders in numeric formats in Preferenze - Design Compatibility. |
||||||||||||||||||||||
Novita' |
[v11 SQL] Cast dei dati con 4D ODBC Pro
La v11 SQL non consente più il cast in automatico dei dati con i comandi di ODBC. Per essere più chiari, se cerco di importare in un array di tipo stringa dei dati che nella sorgente ODBC sono invece di tipo longint, l'array sarà riempito da stringhe vuote; a differenza della versione 2004, dove il cambio di tipo era automatico ( e peraltro abbastanza pericoloso per l'integrità dei dati, benché comodo per il programmatore! ) |
||||||||||||||||||||||
Info |
[v11 SQL] Il form deve esistere!
Se nella v11SQL viene eseguito il codice OUTPUT FORM([Tabella];"Output") e il form non esiste, 4D restituisce errore, a differenza della versione 2004, dove il form poteva anche non esistere. |
||||||||||||||||||||||
Codice |
[v11 SQL] Esportazione dati
Ecco una versione modificata per la v11 di un metodo di esportazione dati in un file testo. C_TEXT($testo) C_BLOB($blob) $pointertable:=->[LaTabella] For ($j;1;Get last field number($pointertable)) If (Is field number valid(Table($pointertable);$j)) $testo:=$testo+Field name(Table($pointertable);$j)+Char(Tab ) If ($j End if End if End for $testo:=$testo+Char(Carriage return )+Char(Line feed ) TEXT TO BLOB($testo;$blob) ALL RECORDS($pointertable->) ARRAY LONGINT($arrRecNum;0) SELECTION TO ARRAY($pointertable->;$arrRecNum) For ($i;1;Size of array($arrRecNum)) GOTO RECORD($pointertable->;$arrRecNum{$i}) $testo:="" For ($j;1;Get last field number($pointertable)) If (Is field number valid(Table($pointertable);$j)) $pointer:=Field(Table($pointertable);$j) If ((Type($pointer->)=Is Alpha Field ) | ((Type($pointer->)=Is Text ))) $testo:=$testo+$pointer-> Else $testo:=$testo+String($pointer->) End if If ($j<Get last field number($pointertable)) $testo:=$testo+Char(Tab ) End if End if End for $testo:=$testo+Char(Carriage return )+Char(Line feed ) TEXT TO BLOB($testo;$blob;UTF8 text without length ;*) End for BLOB TO DOCUMENT("Export.txt";$blob) |
||||||||||||||||||||||
Info |
Ordinamento dei campi booleani
Sarà pure una cosa scontata, ma ordinando un campo booleano in maniera crescente vengono visualizzati prima i valori "False" e poi i "True" |
||||||||||||||||||||||
Tecniche |
Selezionare un record in una List Box basata su Named Selection
Mettiamo di avere una List Box legata ad una Named Selection : se voglio far in modo che 4D mi selezioni un record in particolare (ad esempio il primo) dopo un ordinamento, devo utilizzare il set dichiarato in Highligth Set e fare questo simpatico giro di set : QUERY([Tabella];[Tabella]campoChiave=[TabellaMadre]chiave) ORDER BY([Tabella];[Tabella]campoOrdinamento;<) COPY NAMED SELECTION([Tabella];"miaLista") 'Set usato per la ListBox $num:=Record number([Tabella]) GOTO RECORD([Tabella];$num) CREATE SET([Tabella];"il_Primo") COPY SET("il_Primo";"selezionati") 'Set dichiarato come highligth set |
||||||||||||||||||||||
Info |
[v12 SQL] Nuove funzionalità in Stampa
Due grosse novità: 1) si può stampare la listbox, anche su più pagine 2) posizionamento per coordinate degli oggetti in fase di stampa La sequenza da fare è: - OPEN PRINTING JOB - seleziono una maschera con OPEN PRINTING FORM - stampo il singolo oggetto con Print Object |
||||||||||||||||||||||
Info |
[v12 SQL] Nuovo Code Editor
Ecco alcune delle novità del nuovo Code Editor:
|
||||||||||||||||||||||
Info |
[v11 SQL] Le opzioni del file 4DLINK
Il file .4DLINK è il nuovo tipo che di file che consente di aprire i database 4D. In linea generale sostituisce il file .PTH che consentiva di aprire un 4D Client con le opzioni utente memorizzate, ma in realtà contiene un numero molto maggiore di opzioni. Il file si trova nella cartella: • Windows Vista: C:\Users\UserName\AppData\Roaming\4D\Favorites v11\ • Windows XP: C:\Documents and Settings\UserName\Application Data\4D\Favorites v11\ • Mac OS: Users/UserName/Library/Preferences/4D/Favorites v11/ dove UserName è il nome dell'utente del sistema. Il file 4DLINK è un file XML che nella sua forma più semplice si presenta così: <?xml version="1.0" encoding="UTF-8"?> <database_shortcut structure_file="file:///C:/mio.4DB" data_file="file:///C:/mio.4DD"/> All'interno del file è possibile inserire tutta una serie di attributi, come ad esempio nome utente e passoword: <?xml version="1.0" encoding="UTF-8" standalone="no" ?> <database_shortcut is_remote="true" password="123" server_database_name="Contabilità" server_path="contabilita.dominio.it" user_name="Steve"/> |
||||||||||||||||||||||
Novita' |
[v12 SQL] XLIFF: dalle applicazioni multilingua alle finestre multilingua
Uno degli aspetti introdotti dalla v11 SQL era stata la possibilità di sviluppare software multilingua grazie all'uso di XLIFF. Con 4D v12 SQL viene data innanzitutto la possibilità di utilizzare una lingua diversa da quella impostata nel sistema operativo; ma soprattutto sarà possibile definire, all'interno di ogni processo, se deve essere utilizzato per quel processo un fie XLIFF differente, senza che ciò intacchi l'impostazione di base della lingua del database intero o degli altri processi attivi. |
||||||||||||||||||||||
Info |
Cos'è il documento .Match ?
Dalla versione 11.5 è presente un documento vicino alla struttura chiamato nome_database.Match . Il nuovo file è creato per collegare i numeri delle tabelle e il loro corrispondente UUID; è richiesto per ripristinare un database danneggiato. Non cancellarlo, è aggiornato ogni volta che c'è una modifica alla struttura. E' ovviamente il caso di aggiungere questo documento alla lista dei file che saranno automaticamente salvati durante il backup automatico. |
||||||||||||||||||||||
Info |
[v12 SQL] PHP Execute
La novità che ha richiesto il maggior tempo di sviluppo nella v12 SQL è la possibilità di utilizzare php all'interno di 4D col comando il cui nome provvisorio è PHP Execute. 4D integra (a momento) il motore PHP versione 5.3, ma è possibile anche utilizzare anche un interprete PHP esterno. Molte delle librerie standard sono già incluse e già utilizzabili (l'elenco delle librerie built-in sarà descritto sul manuale). Questo permette di passare da sistemi MAMP (Mac, Apache, MySQL e PHP) o WAMP (Windows, Apache, MySQL e PHP) a sistemi M4DP o W4D, in cui 4D evita l'installazione e manutenzione di tre componenti. |
||||||||||||||||||||||
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 | |||||||||||||||||||||
Novita' |
[v12 SQL] Listbox gerarchiche
Le listbox ottengono una nuova funzionalità: quando alcune colonne hanno dei valori ripetuti è possibile scegliere una visualizzazione gerarchica, dove è possibile espandere e collassare le righe raggruppate sotto le stesse voci. |
||||||||||||||||||||||
Novita' |
[v12 SQL] Oggetti dinamici nei form
Con la v12 SQL sarà possible costruire dinamicamente i form. Dinamiche saranno anche le variabili: sarà possibile infatti avere variabili solo col nome la cui visibilità e utilizzo diventa non il processo chiamante bensì il form in quanto tale. Uno dei comandi più potenti presentati è il comando di Duplicazione degli Oggetti, che dà la possibilità di aggiungere in fase di utilizzo campi ed etichette. Ovviamente il linguaggio di programmazione mette a disposizione tutti gli strumenti per poter interagire con questo tipo di oggetti, tramite puntatori: sarà possibile ad esempio cambiare il testo delle etichette.. come dire che sono dinamici anche gli oggetti statici! |
||||||||||||||||||||||
Novita' |
[v12 SQL] Rich text: il testo con formattazione
Con 4D v12 SQL sarà possibile avere un oggetto testo formattato. Può essere personalizzata dimensione, forma, colore e quant'altro. Il testo è formattabile se si attiva un apposito check nelle proprietà dell'oggetto che lo visualizza a video. Due nuovi comandi del linguaggio permettono inoltre di ottenere il testo nella versione con i tag html che esplicita gli stili oppure lo stesso testo nella versione pulita dagli stili. |
||||||||||||||||||||||
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] Il Record number in un trigger
Quando viene eseguito il trigger per l'evento On saving new record, se si usa il comando Record number la v11 SQL restituisce il record number assegnato al record, a differenza della 2004 che restituiva come record number "-3". |
||||||||||||||||||||||
Plugin |
Ottenere il proprio indirizzo IP con due schede di rete installate
Abbiamo già visto in una precedente faq come ottenere il proprio indirizzo ip. Non è detto però che questo metodo funzioni quando sulla macchina sono installate due schede di rete (tipo ethernet e wireless). Un interessante approccio al problema è stato proposto da Jeffrey Kain della Orchard Software Corporation; la sua soluzione è: $Err:=NET_Resolve (Current machine;$ip) Il comando è fra quelli disponibili nel plugin gratuito 4d Internet Commands. |
||||||||||||||||||||||
Web |
Dichiarazione delle variabili per i metodi web services
Quando si decide di rendere fruibile un metodo via web service server è bene creare manualmente il metodo COMPILER_WEB. Questo metodo (che a differenza degli altri metodi COMPILER non viene creato automaticamente) si occupa in sostanza di dichiarare le variabili che vengono passate come parametro al metodo chiamato dal client web service. Ciò risulta obbligatorio quando il parametro passato come SOAP input è un array: in tal caso infatti nel metodo COMPILER_WEB l'array viene dichiarato con dimensione 0, ma nel metodo chiamato come web service l'array avrà la dimensione corretta in funzione degli elementi che aveva sul client web. |
||||||||||||||||||||||
Plugin |
Impostare i parametri di stampa in 4D Write
Per impostare i parametri di stampa in 4D Write si utilizza la funzione WR SET PRINT OPTION. Gli unici comandi del linguaggio standard che vengono utilizzati in fase di stampa da 4DWrite sono PRINT OPTION VALUES, per conoscere i parametri da passare a WR SET PRINT OPTION in alcune circostanze specifiche (wr paper option, wr paper source option) e SET CURRENT PRINTER per impostare la stampante da usare. Per conoscere il valore delle impostazioni di stampa di 4D Write si usa la funzione WR GET PRINT OPTION. |
||||||||||||||||||||||
Info |
[v11 SQL] Oggetti come espressioni
Una delle funzioni della v11 che facilmente può sfuggire è il fatto che agli oggetti oltre ad assegnare una variabile è possibile assegnare un'espressione. Cosa significa? Ad esempio, in una lista l'oggetto potrebbe al posto della variabile contenere [tabella]cognome+" "+[tabella]nome per andare a sostituire i due campi relativi. Oppure, sempre in una lista l'oggetto potrebbe essere un termometro e si può scrivere qualcosa del genere [tabella]quantità/vTotale". Per cose più complesse, del tipo in funzione di un valore numerico cambiare una descrizione, si può accoppiare con il comando Choose, anch'esso probabilmente sfuggito ai più; esempio: Choose(Day number([tabella]giorno);"Dom";"Lun";"Mar";"Mer";"Gio";"Ven";"Sab"). |
||||||||||||||||||||||
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 | |||||||||||||||||||||
Novita' |
[v11 SQL] Il comando Find in field
Il comando Find in field della v11 SQL sostituisce il Find index key delle versioni precedenti. Il comando permette di trovare il numero di record che contengono un certo valore da cercare senza modificare la selezioni corrente. La differenza più sostanziale, oltre al nome, sta nel fatto che il comando adesso accetta anche campi non indicizzati per la ricerca. |
||||||||||||||||||||||
Novita' |
[v11 SQL] Modifiche al comando QUERY WITH ARRAY
Rispetto alle versioni precedenti, con la v11 SQL non è più necessario che il campo su cui eseguire il comando sia indicizzato. |
||||||||||||||||||||||
Info |
Tagliare un testo in più righe e metterlo in array
Se ho un testo molto lungo e voglio tagliarlo su più righe di massimo 80 caratteri, ma tagliate dove c'è un separatore tipo spazio o punteggiatura, si può usare questo codice: $Pat_T:="(?:[^\\p{C}]{1,72})(?:$|\\p{Z})" ARRAY TEXT($Fold_aT;0) $Start_L:=1 $FoundAt_L:=0 $Length_L:=0 $Bool_B:=Match regex($Pat_T;$Buf_T;$Start_L;$FoundAt_L;$Length_L) While ($Bool_B) APPEND TO ARRAY($Fold_aT;Substring($Buf_T;$FoundAt_L;$Length_L)) $Start_L:=$FoundAt_L+$Length_L $Bool_B:=Match regex($Pat_T;$Buf_T;$Start_L;$FoundAt_L;$Length_L) End while cfr Use Match regex to fold or split text into strings of a maximum length |
||||||||||||||||||||||
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 | |||||||||||||||||||||
Info |
[v11 SQL] Problema nell'aggiornamento dei campi Picture
Prima della disponibilità dei campi di tipo Blob era usuale registrare nel campo Picture anche dati che non fossero immagini. Però registrando delle immagini 4D accodava 6 byte con la posizione e la modalità di visualizzazione dell'immagine: durante l'aggiornamento della base dati alla v11, 4D elimina questi 6 byte in fondo ai dati registrati nei campi Picture. Nel caso in cui non si tratta di immagini questo costituisce sicuramente un problema: per risolverlo basta cambiare il tipo del campo da Picture a Blob. |
||||||||||||||||||||||
Codice |
Come usare le transazioni nelle maschere di inserimento
Schema di base per l'utilizzo delle transazioni nella creazione o modifica di un record. Metodo del Form di inserimento Case of : (Form Event=On Load) START TRANSACTION .... Pulsante Annulla Case of : (Form Event=On Clicked) CANCEL TRANSACTION CANCEL End case Pulsante Conferma Case of : (Form Event=On Clicked) ... If ($hoFattoTuttiIControlli) SAVE RECORD VALIDATE TRANSACTION Else CANCEL TRANSACTION End if CANCEL End case |
||||||||||||||||||||||
Info |
[v11 SQL] Usare più CALL WEB SERVICE in un'unica sessione
Dalla versione v11 è stato aggiunto un ulteriore parametro al comando CALL WEB SERVICE; la sintassi adesso è: CALL WEB SERVICE (accessURL; soapAction; methodName; namespace{; complexType{; *}}) L'* finale può essere usato per ottimizzare le chiamate. Quando viene passato, il comando non chiude la connessione usata dal processo alla fine dell'esecuzione. In questo modo la successiva chiamata CALL WEB SERVICE riutilizzera la stessa connessione, finché verrà usato l'* finale. Il meccanismo accelererà in modo notevole le sequenze di chiamata allo stesso server, soprattutto via Internet, sempre che il Web Server chiamato abbia attivo il "keep-alive". Se il server non ha l'opzione attiva o se si raggiunge il limite massimo di chiamate nella connessione, 4d si occuperà automaticamente di riaprire una nuova connessione quando serve. |
||||||||||||||||||||||
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 | |||||||||||||||||||||
Info |
Come generare il file Catalog.xml
Come già citato, il file Catalog.xml permette di mantenere durante la conversione da 2004 a v11 gli stessi codic identificativi usati nella base dati. Il file è generato automaticamente durante la conversione e andrebbe salvato per poter riutilizzare.. Nel caso si fosse perso, per rigenerarlo basta: - Andare in Design nella struttura già convertita in v11 - Scegliere dal menù File il comando "Export Structure to xml" - Rinominare il file così creato in Catalog.xml Per utilizzarlo basta metterlo allo stesso livello della struttura in 2004 da convertire. |
||||||||||||||||||||||
Tecniche |
Diamo una mano al compilatore
Il compilatore di 4D in certi casi ha bisogno di un aiuto per essere guidato nei meandri delle varie opzioni di alcuni comandi. Vediamo un esempio: Il comando Table può ricevere come parametro sia un puntatore che un numero, restituendo rispettivamente o un numero o un puntatore: ciò significa che se uso SET FIELD RELATION (Table($x)....) in modo interprete funziona, ma quando si prova a compilare restituisce errore, perché il compilatore non sa a priori cosa restituisce Table($x). Come risolvere? Basterà usare una variabile ben dichiarata e tutto scorre liscio: $tabella_l:=Table(->[MiaTabella]) SET FIELD RELATION ($tabella_l;.....) |
||||||||||||||||||||||
Comandi |
Modificare lo stato di una relazione: SET FIELD RELATION
Per modificare lo stato di una relazione è assai utile il comando SET FIELD RELATION, soprattutto quando una relazione non è definita automatica da struttura e invece si vuole che lo diventi temporaneamente. La sintassi del comando è: SET FIELD RELATION (manyTable | manyField; one; many) dove - manyTable è la tabella e in questo caso la modifica varrà per tutte le relazioni che partono dalla tabella; - oppure manyField è il campo da cui parte la relazione; - one e many prendono il valore delle seguenti costanti per definire le relazioni uno e molti: Do not modify (0) non modifica nulla; Structure configuration (1) prende per la relazione il valore stabilito nella struttura; Manual (2) rende la relazione manuale; Automatic (3) la rende automatica. Un esempio: SET AUTOMATIC RELATIONS(False;False) `Reset delle relazioni `Solo le relazioni definite adesso verranno usate SET FIELD RELATION([Invoices]Cust_IDt;Automatic;Automatic) SET FIELD RELATION([Invoice_Row]Invoice_ID;Automatic;Automatic) QR REPORT([Invoices];Char(1);True;True;True) |
||||||||||||||||||||||
Codice |
PDO_4D: il codice PHP per l'inserimento di dati
Ecco di seguito un esempio di codice per PDO_4D che consente l'uso di PHP per l'inserimento di dati, con creazione della tabella. <?php $dsn = '4D:host=localhost;charset=UTF-8'; $user = 'test'; $pass = 'test'; // Connection to the 4D SQL server $db = new PDO_4D($dsn, $user, $pass); try { $db->exec('CREATE TABLE test(id varCHAR(1) NOT NULL, val VARCHAR(10))'); } catch (PDOException $e) { die("Errore 4D : " . $e->getMessage()); } $db->exec("INSERT INTO test VALUES('A', 'A')"); $db->exec("INSERT INTO test VALUES('B', 'A')"); $db->exec("INSERT INTO test VALUES('C', 'C')"); $stmt = $db->prepare('SELECT id, val from test'); $stmt->execute(); print_r($stmt->fetchAll()); unset($stmt); unset($db); ?> L'ouput risultante sarà: Array ( [0] => Array ( [ID] => A [0] => A [VAL] => B [1] => B ) [1] => Array ( [ID] => C [0] => C [VAL] => D [1] => D ) [2] => Array ( [ID] => E [0] => E [VAL] => F [1] => F ) ) |
||||||||||||||||||||||
Info |
Esportazione Descrizione Struttura
Esporta in un file di testo con la descrizione della struttura corrente; include il numero di record, le relazioni con indicazioni se automatiche Molti a Uno o Uno a Molti. C_LONGINT($TabellaNumero;$tabella;$campo;$lunghezza;$tipo) $cr:=Char(Carriage return ) $doc:=Create document("") If (ok=1) GET TABLE TITLES($Tabelle_nomi;$Tabelle_numeri) SORT ARRAY($Tabelle_nomi;$Tabelle_numeri) For ($tabella;1;Size of array($Tabelle_nomi)) $TabellaNome:=$Tabelle_nomi{$tabella} $TabellaNumero:=$Tabelle_numeri{$tabella} SEND PACKET($doc;$cr+"TABLE "+$TabellaNome+" ("+String(Records in table(Table($TabellaNumero)->))+")"+$cr) For ($campo;1;Count fields($TabellaNumero)) GET FIELD PROPERTIES($TabellaNumero;$campo;$tipo;$lunghezza) Case of : (($tipo=Is LongInt ) | ($tipo=Is Integer )) $tipo:="Long" : ($tipo=Is Real ) $tipo:="Real" : ($tipo=Is Alpha Field ) $tipo:="Alfa "+String($lunghezza) : ($tipo=Is Text ) $tipo:="Text" : ($tipo=Is Boolean ) $tipo:="Bool" : ($tipo=Is Date ) $tipo:="Date" : ($tipo=Is Time ) $tipo:="Time" : ($tipo=Is Picture ) $tipo:="Pict" Else $tipo:="blob "+String($tipo) End case GET RELATION PROPERTIES($TabellaNumero;$campo;$oneT;$oneF;$cf;$autoOne;$autoMany) If ($oneT=0) $relazione:="" Else $relazione:="-> ["+Table name($oneT)+"]"+Field name($oneT;$oneF)+(Num($autoOne)*"A1")+" "+(Num($autoOne)*"AM") End if SEND PACKET($doc;Char(Tab )+$tipo+Char(Tab )+Field name($TabellaNumero;$campo)+Char(Tab )+$relazione+$cr) End for End for CLOSE DOCUMENT($doc) ALERT("finito") End if |
||||||||||||||||||||||
Info |
[v11 SQL] Il comando Select Rgb Color
Usa questo comando per mostrare la finestra standard del sistema operativo di scelta del colore. Un primo parametro serve a preimpostare un colore nella finestra (il default è il nero), mentre il secondo permette di indicare una stringa come titolo (il default è "Colors") |
||||||||||||||||||||||
Comandi |
[v11 SQL] Il comando TRUNCATE TABLE
Il comando TRUNCATE TABLE, ereditato evidentemente dall'SQL Truncate (Table), permette la cancellazione di tutti i record di una tabella in una singola operazione. Rispetto alla consueta coppia di ALL RECORDS / DELETE SELECTION questo comando è molto più veloce, non esegue i trigger né controlla le relazioni per eventuali integrità referenziali, non aggiorna neanche il LockedSet se trova dei record bloccati. Semplicemente ritorna ok = 1 se ha avuto effetto, altrimenti si interrompe con ok = 0. Utile ad esempio per ripulire velocemente una tabella temporanea. |
||||||||||||||||||||||
Comandi |
[v11 SQL] Il comando Transform Picture
Rispetto alle versioni precedenti, adesso oltre agli operatori (+,/,*..) è possibile modificare un'immagine con il comando Transform Picture. TRANSFORM PICTURE($immagine;Scale;$larghezza;$altezza) I parametri $larghezza e $altezza sono il decimale del fattore di scala, ad esempio per dimezzare al 50% si usa lo 0,5 TRANSFORM PICTURE($immagine;Translate;$oriz;$vert) I parametri sono numero anche negativo di pixel di spostamento. TRANSFORM PICTURE($immagine;Flip horizontally) Per ottenere un'immagine speculare orizzontalmente. TRANSFORM PICTURE($immagine;Flip vertically) Per ottenere un'immagine speculare verticalmente. TRANSFORM PICTURE($immagine;Reset) Per annullare tutte le modifiche di sopra. Invece, non sono annullabili le seguenti opzioni: TRANSFORM PICTURE($immagine;Fade to grey scale) Trasforma l'immagine in scala di grigi. TRANSFORM PICTURE($immagine;Crop;$x;$y;$larg;$alt;) Ritaglia l'immagine partendo dalle coordinate x e y per un certo numero di pixel di larghezze e altezza |
||||||||||||||||||||||
Comandi |
[v11 SQL] Il comando Get 4D Folder e i nuovi parametri
Al comando Get 4D Folder, già presentato in una una precedente faq, accetta nuovi parametri molto utili per identificare alcune cartelle di lavoro. Ecco l'elenco completo ad oggi:
|
||||||||||||||||||||||
Info |
4d avviato come servizio su Windows Vista e Windows Server 2008
A partire da Windows Vista e quindi su tutte le versioni successive di Windows (ad esempio Windows Server 2008) non è possibile interagire con un applicativo lanciato in modalità servizio (cfr. Service Changes for Windows Vista ) La soluzione (da 4d v11 in poi) è lanciare il Client sulla stessa macchina e usare la finestra di Amministrazione per controllare il server. Oppure per non usare 4d come servizio è possibile fare in modo che sia lanciato all'avvio in modalità normale seguendo queste istruzioni: 1. impostare il login automatico di un utente 2. creare un file autostart.4DLink <?xml version="1.0" encoding="UTF-8"?><database_shortcut structure_file="file:///C:/4D/miaApp.4DB" data_file="file:///C:/4D/miaApp.4DD"/>3. creare un file .bat che lanci il 4d Server e il relativo .4DLink "C:\4D v11 SQL Release 4 Custom\4D Server\4D Server.exe" "C:\autostart.4Dlink" |
||||||||||||||||||||||
Plugin |
[v11 SQL] Modifiche apportate a WR Get text di 4D Write
|
||||||||||||||||||||||
Codice |
Confrontare il contenuto di due dischi o due cartelle
Avendo la necessità di controllare se una copia di sicurezza di un disco fosse andata a buon fine, ho scritto questo metodo ricorsivo che confronta il contenuto di due differenti percorsi. È scritto con la v11SQL. Ecco il metodo ConfrontoDischi: If (Count parameters=0) $percorso1:=Select folder("Percorso 1") If (OK=1) $percorso2:=Select folder("Percorso 2") If (OK=1) ARRAY TEXT(arrFile1;0) ARRAY TEXT(arrFile2;0) ConfrontoDischi (->arrFile1;$percorso1) ConfrontoDischi (->arrFile2;$percorso2) For ($i;Size of array(arrFile1);1;-1) arrFile1{$i}:=Delete string(arrFile1{$i};1;Length($percorso1)) End for For ($i;Size of array(arrFile2);1;-1) arrFile2{$i}:=Delete string(arrFile2{$i};1;Length($percorso2)) End for For ($i;Size of array(arrFile1);1;-1) $find:=Find in array(arrFile2;arrFile1{$i}) If ($find>0) DELETE FROM ARRAY(arrFile1;$i) DELETE FROM ARRAY(arrFile2;$find) End if End for End if End if Else $percorso:=$2 ARRAY STRING(255;$arrNomiFile;0) DOCUMENT LIST($percorso;$arrNomiFile) For ($i;1;Size of array($arrNomiFile)) APPEND TO ARRAY($1->;$percorso+$arrNomiFile{$i}) End for ARRAY STRING(255;$arrNomiFile;0) FOLDER LIST($percorso;$arrNomiFile) For ($i;1;Size of array($arrNomiFile)) ConfrontoDischi ($1;$percorso+$arrNomiFile{$i}+"\\") End for End if |
||||||||||||||||||||||
Codice |
Esportazione dati in formato testo
Ecco un metodo per esportare i dati di una tabella "Tabella" in formato solo testo, con conversione del set di caratteri in formato Windows: $vhDocRef:=Open Document("") If (ok=1) $tableptr:=->[Tabella] $tablenum:=Table($tableptr->) `prima creo la testata con i nomi dei campi For ($j;1;Count fields($tableptr)) GET FIELD PROPERTIES($tablenum;$j;$fieldType;$fieldLength;$indexed;$unique;$invisible) $nome:=Field name($tablenum;$j) If ($invisible=False) SEND PACKET($vhDocRef;Mac to Win($nome)) SEND PACKET($vhDocRef;Char(Tab)) End if End for SEND PACKET($vhDocRef;Char(Carriage return)) `seleziono tutti i record ALL RECORDS($tableptr->) ARRAY LONGINT($arrRecNum;0) SELECTION TO ARRAY($tableptr->;$arrRecNum) `esporto tutto, tranne i campi Invisibili For ($i;1;Size of array($arrRecNum)) GOTO RECORD($tableptr->;$arrRecNum{$i}) $rigadaesportare:="" For ($j;1;Count fields($tableptr)) GET FIELD PROPERTIES($tablenum;$j;$fieldType;$fieldLength;$indexed;$unique;$invisible) If ($invisible=False) $pointer:=Field($tablenum;$j) $testodaesportare:="" Case of : (($fieldType=Is Alpha Field ) | ($fieldType=Is Text )) $testodaesportare:=$pointer-> $testodaesportare:=Replace string($testodaesportare; Char(Carriage return);" ") : ($fieldType=Is Boolean ) If ($pointer->) $testodaesportare:="Vero" Else $testodaesportare:="Falso" End if Else $testodaesportare:=String($pointer->) End case $rigadaesportare:=$rigadaesportare+Mac to Win($testodaesportare)+Char(Tab) End if End for SEND PACKET($vhDocRef;$rigadaesportare;Char(Carriage return)) End for CLOSE DOCUMENT($vhDocRef) End if |
||||||||||||||||||||||
Info |
[v11 SQL] Scambio dati fra applicazioni 4d
Con l'ultima versione di 4D non è più disponibile 4d Open, molto utilizzato per scambiare i dati fra diversi server 4d. Le opzioni disponibili oggi sono:
In linea generale il consiglio di 4d è di usare nell'ordine Sincronizzazione -> SQL, XML, SOAP Divisione di operatività -> SOAP, SQL, XML Applicazioni distribuite -> SQL, SOAP, XML Per maggiori informazioni, potete scaricare la White Paper 4D Data Exchange v11 nella sezione delle Brochure 4D |
||||||||||||||||||||||
Info |
Messaggio "PR4D Resource Damaged"
Quando si danneggia un indice della struttura 4d v11.x mostra una finestra con un messaggio "PR4D resource damaged and no previous version available!". Gli indici della struttura sono conservati nel file .4dIndy, quindi per risolvere il rpoblema basta eliminare il file e farglielo ricostruire al prossimo riavvio di 4d. |
||||||||||||||||||||||
Info |
Vedere un'immagine SVG in tempo reale
Durante la creazione di un'immagine SVG, è molto importante per gli sviluppatori avere la possibilità di vedere velocemente l'immagine che stanno creando. E' possibile salvare l'xml in una variabile o esportarlo in un file esterno (e poi visualizzarla usando ad esempio un browser moderno); oppure 4D mette a disposizione una finestra SGV Viewer dove vedere il risultato al volo. Per vedere questa finestra bisogna chiamare il comando SVGTool_SHOW_IN_VIEWER del componente 4D SVG fornito con 4d SQL v11. |
||||||||||||||||||||||
Plugin |
4D Chart: centrare verticalmente un grafico con CT SET REAL SCALE
Vediamo come centrare un grafico ottenuto tramite CT Chart arrays. Ciclando sull'array dei valori troviamo il massimo valore assoluto nell'array. Sia $max questo massimo. Possiamo quindi scrivere: $intervallo:=$max/2 CT SET REAL SCALE (Area;$Chart;0;0;0;0;-$max;$max;$intervallo;0,1) La variabile $intervallo e il valore 0,1 variano ovviamente in base ai valori che si attendono nel grafico. |
||||||||||||||||||||||
Info |
Il comando Length e il carattere \
Supponiamo di fare il seguente assegnamento: $stringa:="\"a\"" La variabile $stringa ha un comportamento al quale è necessario fare attenzione: se la si usa per fare un confronto o un assegnamento il suo valore sarà «"a"», ma il valore di Length($stringa) è 3 (perché formata da 3 caratteri) e non 5 come si potrebbe supporre. |
||||||||||||||||||||||
Plugin |
Controllare il protocollo di acquisizione di QPix
La funzione QPx_AcqTestProtocol consente la possibilità di utilizzare un certo protocollo di acquisizione fra quelli supportati dal plugin della Escape. L'uso è: $error:=QPx_AcqTestProtocol(acqProtocol) dove acqProtocol può prendere i valori: qpx_AcqTWAINProtocol che ha valore 1 per il protocollo TWAIN qpx_AcqPictureTransferProtocol che ha valore 2 per il PTP (Picture Transfer Protocol identifier) qpx_AcqVideoProtocol che ha valore 4 per l'acquisizione Video. Se il protocollo è supportato viene ritornata la costante qpx_NoErr, altrimenti, in base all'errore, qpx_couldntGetRequiredComponent o qpx_paramErr. |
||||||||||||||||||||||
Plugin |
L'elenco delle periferiche di scansione con QPix
La funzione $err:=QPx_AcqGetDeviceList (acqProtocol;arrListaPeriferiche) permette di conoscere l'elenco delle periferiche utilizzabili col protocollo definito da acqProtocol. I protocolli possibili sono:
|
||||||||||||||||||||||
Info |
[v11 SQL] Metodo generico "On sql authentication"
Dalla versione 11.3 è stato implementato lo schema di sicurezza per l'accesso ai dati da SQL language; l'autenticazione è fatta nel metodo del database "On Sql Authentication" che però richiede necessariamente di eseguire il comando CHANGE CURRENT USER. Il metodo seguente valida nome e password dalla lista degli utenti standard di 4d; in realtà si potrebbe creare un utente generico "utente_sql" e usare quello nel comando successivo. C_TEXT($1;$2;$3) C_BOOLEAN($0) $nomeutente:=$1 $password:=$2 $0:=False GET USER LIST($atListaUtenti;$alListaID) $quale:=Find in array($atListaUtenti;$nomeutente) If ($quale>0) If (Validate password($alListaID{$quale};$password) CHANGE CURRENT USER($nomeutente;$password) $0:=True End if End if |
||||||||||||||||||||||
Novizi |
I quattro stati dei pulsanti nelle picture della tool box
È possibile creare all'interno della picture library delle icone a 4 stati, le icone cioè cambiano in funzione dello stato del pulsante relativo. Dall'alto in basso i quattro stati rappresentati sono:
|
||||||||||||||||||||||
Codice |
Un termometro con incremento corretto
Quando creiamo in un form un termometro, 4D inserisce in automatico i valori di intervallo da 0 a 100. Ecco un metodo per utilizzare questo termometro (vTerm nel nostro caso) con qualsiasi numero (positivo o negativo, intero o decimale) all'interno di un ciclo. $start:=0,65 $end:=0,90 $progress:=0,001 For ($i;$start;$end;$progress) vTerm:=100*($i-$start+$progress)/($end-$start+$progress) DISPLAY RECORD End for dove $start è il valore da cui il ciclo parte, $end è il valore di arrivo del ciclo, $progress è lo step di avanzamento. |
||||||||||||||||||||||
Info |
Autoincremento automatico di un campo numerico
Per i campi numerici interi (Integer, Long Integer e Integer 64 bits) è possibile utilizzare un nuovo (dalla v11.2) flag "Autoincrement" che genera automaticamente un ID unico nei vari record. Il campo non è più modificabile o inseribile né dall'utente né da programma. Il numero è sempre unico, mai riutilizzato, e se generato in una transazione poi annullata viene perso. Da notare che se viene attivato su una tabella che abbia già dei record il numero parte dal numero totale dei record +1; in questo modo prima di applicarlo alla struttura è possibile rinumerare i record precedenti per avere una sequenza corretta. |
||||||||||||||||||||||
Codice |
Il numero di giorno nell'anno
Ecco una semplice formula con la quale calcolare il numero di giorno all'interno dell'anno: $giornodellanno=Current date-Add to date(!00/00/00!;Year of(Current date);1;1)+1 |
||||||||||||||||||||||
Info |
[v11 SQL] Scorciatoia per avere info su oggetti nelle maschere
In ambiente User (che nella v11 è integrato con l'ambiente Design ) premendo control-maiuscolo quando il puntatore si trova su un oggetto campo o variabile, appare un tip con alcune informazioni:
|
||||||||||||||||||||||
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 | |||||||||||||||||||||
Web |
Accedere a un sito su una macchina locale - Apple MacOSX
Dopo l'esempio per Windows, vediamo come modificare il file hosts su Mac per rendere accessibile da rete interna un sito web come se ci trovassimo all'esterno della rete stessa. Individuare il file: /etc/hostse inserire la seguente riga: 192.168.1.1 www.sviluppo4d.itdove l'ip è quello interno del web server. Individuare poi il file: /etc/host.confche si occupa del lookup e che deve contenere la riga: order hosts,bindInfine, nel file: /etc/nsswitch.confinserire la riga: hosts: files nisplus nis dns |
||||||||||||||||||||||
Web |
Accedere a un sito su una macchina locale - Microsoft Windows
Per poter consultare un sito installato all'interno della propria rete come se ci trovassimo all'esterno è necessario modificare il file "hosts" della nostra macchina. Vediamo la soluzione per PC. Individuare il file hosts nei percorsi seguenti: Windows 95/98/Me c:\windows\hosts Windows NT/2000/XP Pro c:\winnt\system32\drivers\etc\hosts Windows XP Home c:\windows\system32\drivers\etc\hosts e inserire la seguente riga: 192.168.1.1 www.sviluppo4d.it dove l'ip è quello interno del web server. |
||||||||||||||||||||||
Info |
Anteprima di stampa in un Quick Report
Per avere l'anteprima di stampa di un rapporto di statistica creato con i comandi di Quick Report, è necessario aggiungere il comando: QR SET DOCUMENT PROPERTY($ID;1;1) dove $ID è l'id dell'area Quick report, i due "1" rappresentano la proprietà "qr printing dialog" e la richiesta di mostrare la dialog stessa |
||||||||||||||||||||||
Codice |
[v11 SQL] Caricare una lista in un array
Il comando LIST TO ARRAY non è più consigliato dalla versione v11, probabilmente nelle versioni successive potrebbe essere reso non disponibile. Ecco un semplice codice che permette di caricare in un array il contenuto di una lista: $lista_hl:=Load list("Posizione_fiscale") ARRAY TEXT(Lista;Count list items($lista_hl)) For ($i; 1; Count list items($lista_hl)) GET LIST ITEM($lista_hl; $i; $rifer_l; $nome_t) Lista{$i}:=$nome_t End for |
||||||||||||||||||||||
Bug |
[Risolto] Crash su Windows Vista all'apertura di 4D
Sembra che su Windows Vista, in alcune circostanze non meglio identificate, 4D 2004.7 vada in crash appena aperto. In questi casi la soluzione è tanto semplice quanto incredibile: basta spostare i software (Runtime/Server/Client e Struttura/Dati) fuori dalla cartella "Programmi" di sistema. |
||||||||||||||||||||||
Info |
4D v11 SQL e Joomla: problemi con Unicode UTF8
Dovendo implementare una comunicazione fra un sito sviluppato con Joomla come CMS e dei dati memorizzati su un database 4D v11 SQL è possibile che i caratteri Unicode inviati da 4D al sito (tipo le lettere con accenti) non vengano visualizzati correttamente, malgrado il database mySQL interfacciato con Joomla sia UTF8 e nell'installazione la scelta della lingua sia stata italiano. Per correggere il problema: - entrare nella cartella "language" presente nella root di installazione di Joomla - all'interno di ogni cartella riferita ad uno specifico linguaggio ("it-IT", "en-GB", ecc.) individuare il file "linguadiinterfaccia.xml", dove linguadiinterfaccia è una stringa identica al nome della cartella che lo contiene. - individuare la riga "winCodePage" e sotituire il set "iso-8859-1" con "UTF-8" A questo punto i caratteri speciali, tipo le lettere accentate, sono visualizzati correttamente. |
||||||||||||||||||||||
Web |
Creare un sito per Apple iPhone - Riconoscere il browser Safari
Se si desidera creare un versione del sito ottimizzato per iPhone è importante intanto riconoscere che il navigante sia su un iPhone. Siccome ogni browser è riconoscibile tramite il suo User Agent (un testo che lo identifica univocamente), se il collegamento avviene tramite iPhone lo User Agent sarà simile (ovviamente cambieranno i numeri di versione nel tempo): Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420.1 (KHTML, like Gecko) Version/3.0 Mobile/4A93 Safari/419.3che è diverso dallo User Agent del Safari installato ad esempio su un Apple MacOSX 10.5 o su un Microsoft Windows XP, e perfino da quello installato su un iPod Touch! Quindi nel codice della On Web Connection si potrà scrivere così, presupponendo di avere la versione delle pagine per iphone in un'apposita cartella: wbUrl:=$1 If ((position("iPhone";wbUrl)>0) | (position("iPod";wbUrl)>0)) percorso_s:="iphone/" Else percorso_s:="" End if `.. qui la gestione normale SEND HTML FILE(percorso_s+"pagina.html") |
||||||||||||||||||||||
Info |
Architettura del sito Sviluppo4d.it
Ecco una breve descrizione su com'è fatto Sviluppo4d.it: Il software è un programma scritto in 4d SQL v11. L'applicazione è una Monoutenza con la licenza Web Application Server; la versione non commerciale ha un costo di 106 Euro, ma questa ci è stata fornita da 4d con l'intercessione di Italsoftware (grazie a Dominique e Massimo!) Le pagine web vengono servite e costruite direttamente da 4D e sono una decina di template in html e cinque include per testata, piede, colonne sinistra e destra e striscia di navigazione. Le pagine robots.txt e sitemap.xml sono interamente dinamiche. L'hardware è un MacMini G4 1.42GHz con Mac OS X. Per un aggiornamento di quale versione di 4d è attiva usate l'url speciale 4dwebtest . |
||||||||||||||||||||||
Codice |
Filtro caratteri da non utilizzare in un URL
`web_urlEncode `prepara una stringa in modo che sia utilizzabile come parte di un Url C_TEXT($0;$1) C_LONGINT($car_n;$ascii_n) C_STRING(31;$car_s;$nuovo_s) $0:="" $1:=Mac to ISO($1) For ($car_n;1;Length($1)) $car_s:=Substring($1;$car_n;1) $ascii_n:=Character code($car_s) Case of : ($ascii_n =32) $nuovo_s:="+" : ($ascii_n >=127) $nuovo_s:="%"+Substring(String($ascii_n;"&$");2) : (Position($car_s;":<>&%= \"")>0) $nuovo_s:="%"+Substring(String($ascii_n;"&$");2) Else $nuovo_s:=Char($ascii_n) End case $0:=$0+$nuovo_s End for |
||||||||||||||||||||||
Info |
Filtro caratteri da non utilizzare in un XML
Nel caso in cui preparate un file in formato XML elaborandolo in formato testo (e quindi non utilizzando i comandi XML 4d) occorre verificare che i testi da utilizzare siano formattati in modo da evitare alcuni caratteri speciali. `metodo web_xmlEncode $stringa:=$1 $risultato:=Replace string($stringa;"&";"&") $risultato:=Replace string($risultato;"'";"'") $risultato:=Replace string($risultato;"\"";""") $risultato:=Replace string($risultato;">";">") $risultato:=Replace string($risultato;"<";"<") $0:=$result |
||||||||||||||||||||||
Codice |
Generazione del file Sitemap.xml con i comandi XML DOM di 4d
Stessa cosa dell'esportazione già citata in formato test (vedi la faq Generazione automatica del file Sitemap.xml), ma scritta utilizzando i comandi Xml. `metodo web_sitemap.xml C_STRING(16;vXML) C_STRING(80;$aNSName1;$aNSName2;$aNSValue1;$aNSValue2) C_TEXT($result) $site:="http://www.sviluppo4d.it" `valori della struttura xml richiesta $Root:="urlset" $xpath_url:="url" $xpath_loc:="loc" $Namespace:="http://www.google.com/schemas/sitemap/0.84" $aNSName1:="xmlns:xsi" $aNSValue1:="http://www.w3.org/2001/XMLSchema-instance" $aNSName2:="xsi:schemaLocation" $aNSValue2:="http://www.google.com/schemas/sitemap/0.84 http://www.google.com/schemas/sitemap/0.84/sitemap.xsd" `creo il documento xml in memoria vXML:=DOM Create XML Ref($Root;$Namespace;$aNSName1;$aNSValue1;$aNSName2;$aNSValue2) `prima elenchiamo gli indirizzi fissi $url:=DOM Create XML element(vXML;$xpath_url) $item:=DOM Create XML element($url;$xpath_loc) DOM SET XML ELEMENT VALUE($item;$site) `indirizzo base del sito $url:=DOM Create XML element(vXML;$xpath_url) $item:=DOM Create XML element($url;$xpath_loc) DOM SET XML ELEMENT VALUE($item;$site+"/Users") `un indirizzo fisso su sviluppo4d.it `poi costruiamo l'elenco degli indirizzi dinamici ALL RECORDS([News]) While (Not(End selection([News]))) $txt:=$site+"/Detail_News_Display?id="+String([News]id)+"&title="+(wb_UrlEncode ([News]Title)) $url:=DOM Create XML element(vXML;$xpath_url) $item:=DOM Create XML element($url;$xpath_loc) DOM SET XML ELEMENT VALUE($item;$txt) NEXT RECORD([News]) End while ALL RECORDS([Faq]) While (Not(End selection([Faq]))) $txt:=$site+"/Detail_FAQ_Display?id="+String([Faq]id)+"&title="+(wb_UrlEncode ([Faq]Title)) $url:=DOM Create XML element(vXML;$xpath_url) $item:=DOM Create XML element($url;$xpath_loc) DOM SET XML ELEMENT VALUE($item;$txt) NEXT RECORD([Faq]) End while `i tag sono chiusi automaticamente, esportiamo il documento xml DOM EXPORT TO VAR(vXML;$result) `adesso lo cancelliamo dalla memoria DOM CLOSE XML(vXML) SEND HTML TEXT($result) |
||||||||||||||||||||||
Info |
Modifica intestazione ListBox
Volendo modificare il titolo di una colonna di una listbox, supponendo che il titolo si chiami "Header1", basta inserire questo codice nel form method: Case of : (Form event=On Load ) BUTTON TEXT(Header1;"ID Telematizzazione accise") BUTTON TEXT(Header2;"Codice Deposito commerciale") End case e così via. |
||||||||||||||||||||||
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 |
Generazione automatica del file Robots.txt
In alcune faq precedenti (Scrivere i robots per i siti dinamici in 4d 1, Scrivere i robots per i siti dinamici in 4d 2 e Scrivere i robots per i siti dinamici in 4d 3) avevamo descritto la metodologia di scrittura del metatag nello header per ovviare al problema della sessione inclusa nei link delle pagine dinamiche. Con la nuova versione di sviluppo4d, adesso aggiornata in v11, quella strategia non è più necessaria. Il metodo seguente si occupa della generazione dinamica del file "robots.txt" che viene richiamato dai motori di ricerca. In questa forma essere facilmente modificato e aggiornato anche da programma. Clicca qui per vedere il risultato. `metodo web_robots.txt $eol:="\r\n" $txt:="" `per tutti i motori di ricerca $txt:=$txt+"User-Agent: *"+$eol `questi link non sono da seguire $txt:=$txt+"Disallow: /Login"+$eol $txt:=$txt+"Disallow: /User.new"+$eol $txt:=$txt+"Disallow: /Comment.add"+$eol $txt:=$txt+"Disallow: /Detail_FAQ_New"+$eol `mentre tutto il resto si $txt:=$txt+"Allow: /"+$eol `e segnalo l'indirizzo della Sitemap $txt:=$txt+"Sitemap: http://www.sviluppo4d.it/sitemap.xml"+$eol SEND HTML TEXT($txt) |
||||||||||||||||||||||
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 | |||||||||||||||||||||
Codice |
Metodo EliminaSpazi *
`Nexus srl 12-5-04 `toglie gli spazi all'inizio e alla fine C_STRING(255;$str_s) C_STRING(1;$spc_s) C_LONGINT($first_l;$last_l) $str_s:=$1 $spc_s:=Char(32) If ($str_s#"") $first_l:=1 $last_l:=Length($str_s) While (($first_l<$last_l) & (Substring($str_s;$first_l;1)=$spc_s)) $first_l:=$first_l+1 End while While (($last_l>=$first_l) & (Substring($str_s;$last_l;1)=$spc_s)) $last_l:=$last_l-1 End while $str_s:=Substring($str_s;$first_l;$last_l-$first_l+1) End if $0:=$str_s Nota: ho dovuto sostituire l'indicizzazione del carattere $str_s[[$last_l]] con il più solido Substring, perché anche se è corretto formalmente nel caso in cui arrivasse a zero l'ultimo carattere (ad esempio, $1 = " ") la condizione del while dà un errore sulla versione v11. |
||||||||||||||||||||||
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 | |||||||||||||||||||||
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. |
||||||||||||||||||||||
Tecniche |
[v11 SQL] Convertire più volte la stessa struttura
Si è visto in faq precedenti le nuove caratteristiche legate a UUID e al file "Catalog.xml". Analizziamo adesso un problema concreto che tali nuove caratteristiche possono portare. - Convertiamo una struttura e la sua base dati a v11 SQL. Ciò crea una UUID per entrambi. - Nella struttura convertita vengono inseriti nuovi dati. - Per motivi di supporto si continua a sviluppare sulla versione 2004 della struttura. - Scegliamo di convertire alla v11 SQL l'ultima versione della struttura 2004. A questa struttura verrà assegnato un nuovo UUID e ciò impedirà l'apertura del file dati precedentemente convertito e modificato. La soluzione per eseguire una nuova conversione è quella di prendere il file "Catalog.xml" creato dalla prima conversione a v11 SQL e posizionarlo allo stesso livello della struttura 2004 PRIMA della conversione. Eseguendo a questo punto la conversione, 4D v11 SQL utilizzerà questo "Catalog.xml" per generare lo UUID per la struttura. Così sarà possibile aprire il file dati precedente. |
||||||||||||||||||||||
Info |
[v11 SQL] A cosa serve UUID
4D v11 SQL ha introdotto la nuova caratteristica dello UUID per il database. Eccone alcune caratteristiche. - Una struttura può aprire più data file, purché tutti abbiano lo stesso UUID della struttura. - Struttura e file dati possono essere convertiti separatamente (in questo ordine). Possiamo cioè convertire noi la struttura alla v11 SQL e inviarla al cliente; questi aprirà la struttura nuova con il file dati che aveva precedentemente (in versione 2004, 2003, ecc.) e anche questo verrà immediatamente alla v11 SQL senza problemi di UUID. - Un file dati non può essere aperto da strutture diverse, dove per diverse è da intendere "che abbiano UUID diversi", non "differenti copie della stessa struttura": infatti queste hanno sempre lo stesso UUID. |
||||||||||||||||||||||
Novita' |
[v11 SQL] Il file Catalog.xml
Convertendo una struttura a 4D v11 SQL Release 3 da una qualsiasi versione precedente, viene creato un file chiamato "Catalog.xml". Questo file si troverà allo stesso livello della struttura e conterrà tutte le informazioni relative agli oggetti presenti nel database, comprese tabelle, campi e relazioni. Contiene inoltre tutte le informazioni relative allo UUID di ogni oggetto. Questo file risulta assolutamente necessario per eseguire conversioni "multiple" della stessa struttura: permette infatti di utilizzare dati precedentemente convertiti alla v11 SQL con strutture convertite alla v11 SQL in momenti successivi. |
||||||||||||||||||||||
Novita' |
[v11 SQL] WEDD e UUID
4D v11 SQL ha introdotto una nuova caratteristica: l'indissolubile collegamento tra struttura e file dati, chiamato UUID (Universally Unique Identifier). Questa caratteristica è decisamente più forte della risorsa WEDD presente nelle versioni precedenti (infatti adesso è stata rimossa). Mentre infatti in precedenza la risorsa WEDD poteva essere aggiunta, la UUID è "obbligatoriamente" inserita all'atto della conversione da una versione precedente alla versione v11 SQL. |
||||||||||||||||||||||
Novita' |
[v11 SQL] Uso di CAST nelle query SQL di 4D
Una prerogativa dell'SQL Engine è la restituzione di errore in caso di uso di tipi differenti per il confronto. Modifichiamo un precedente esempio come se l'anno di ricerca "1960" fosse stato ad esempio precedentemente chiesto all'utente con una REQUEST o fosse stato salvato in una variabile di tipo testo. Partiamo al solito dalla query scritta con il linguaggio standard di 4th Dimension: Ecco la stessa query con BEGIN SQL Con i comandi SQL Con QUERY BY SQL Con EXECUTE IMMEDIATE |
||||||||||||||||||||||
Novita' |
[v11 SQL] Popolare gli array con i risultati di una SELECT
Vogliamo ottenere un insieme dei film catalogati risalenti almeno all'anno 1960 e con questi risultati popolare deli array. Ecco la query 4D: Si noti in particolare l'uso di $MovieYear all'interno della query. A questo punto possiamo mostrare gli array aMovieYear, aTitles, aDirectories, aMedias and aSoldTickets o come scrollable area raggruppate: o come list box Ecco la stessa query usando i comandi SQL Usando QUERY BY SQL: Usando il comando EXECUTE IMMEDIATE di SQL: |
||||||||||||||||||||||
Novita' |
[v11 SQL] La clausola WHERE nelle query 4D. Alcuni esempi di SELECT
Volendo sapere quanti film si trovano nella nostra videoteca che siano stati pubblicati dal 1960 in poi scriveremo: Usando codice SQL, la SELECT diventa: Usando i comandi SQL del linguaggio 4D, avremmo: Usando QUERY BY SQL avremmo: Infine, usando il comando EXECUTE IMMEDIATE all'interno di un blocco SQL avremmo Si noti nella query SQL l'uso di COUNT(*) per il conteggio dei record. |
||||||||||||||||||||||
Info |
Inviare mail HTML con immagini
Per allegare le immagini nelle mail bisogna guardare il protocollo di creazione delle mail ( cfr http://www.faqs.org/rfcs/rfc2557.html ). Non è che sia semplicissimo, ma spiegazioni ed esempi si trovano molto facilmente in internet. Il nocciolo della questione è che le immagini devono essere trasformate in testo e aggiunte alla mail principale. Bisogna ricordare di aggiungere anche una versione in solo testo per chi usa un lettore di mail che non visualizzi l'html. Il problema principale è che le mail in html vengono lette dai lettori di posta anche se non sono formattate bene seguendo gli standard; quindi occorre provarne più tipi (gmail, thunderbird, mail pre e post 10.4, outlook express, entourage.. ) C'è un'alternativa, mandi la mail in html e tieni le immagini su un sito. Il vantaggio in questo caso è che la mail è piccola, lo svantaggio è che le immagini sul sito ci devono stare finché si pensa che l'utente possa riaprire la stessa mail.. quindi dipende molto dal tipo di mail. |
||||||||||||||||||||||
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 | |||||||||||||||||||||
Codice |
Caricare gli indici all'avvio
In certe situazioni può accadere che l'utente chiuda spesso il programma, ad esempio nelle installazioni monoutenza. Alla prima ricerca 4D deve caricare gli indici in cache e quindi la prima ricerca puà risultare lenta in modo anomalo all'utente. Un trucco è caricare gli indici all'avvio del programma in un processo separato: si può lanciare ad esempio una query sui campi più usati. Se c'è abbastanza cache e il database non è molto grande eseguendo il presente metodo si caricano tutti gli indici all'avvio. `Metodo CaricaIndici READ ONLY(*) MESSAGES OFF C_LONGINT($fieldType;$fieldLen) C_BOOLEAN($indexed) C_REAL($valoreNum) C_DATE($valoreData) C_TIME($valoreOra) C_TEXT($valoreSt) C_BOOLEAN($valoreBool) For ($i;1;Count tables) For ($j;1;Count fields($i)) GET FIELD PROPERTIES($i;$j;$fieldType;$fieldLen;$indexed) If ($indexed) $tabellaptr:=Table($i) $campoptr:=Field($i;$j) ALL RECORDS($tabellaptr->) FIRST RECORD($tabellaptr->) Case of : (($fieldType=Is Alpha Field ) | ($fieldType=Is Text )) $valoreSt:=$campoptr-> QUERY($tabellaptr->;$campoptr->=$valoreSt) : (($fieldType=Is Real ) | ($fieldType=Is LongInt ) | ($fieldType=Is Integer )) $valoreNum:=$campoptr-> QUERY($tabellaptr->;$campoptr->=$valoreNum) : ($fieldType=Is Date ) $valoreData:=$campoptr-> QUERY($tabellaptr->;$campoptr->=$valoreData) : ($fieldType=Is Time ) $valoreOra:=$campoptr-> QUERY($tabellaptr->;$campoptr->=$valoreOra) : ($fieldType=Is Boolean ) $valoreBool:=$campoptr-> QUERY($tabellaptr->;$campoptr->=$valoreBool) End case UNLOAD RECORD($tabellaptr->) End if End for End for MESSAGES ON |
||||||||||||||||||||||
Info |
Correggere manualmente il Build 4D Code del Quick Report
Quando importiamo dentro il nostro codice il codice generato in automatico dal "Build 4D Code" del Wizard del Quick report, sono due le modifiche solitamente da apportare - Creare una offscreeen area per $ID con $ID:=QR New offscreen area e aggiungere dopo il QR Run un QR DELETE OFFSCREEN AREA($ID) - Se si sono inserite delle concatenazioni delle stringhe (tipo Codice_fornitore+"_"+Ragione) il codice risultante sarà: QR INSERT COLUMN($ID;1;"[Fornitori]Fornitore+\\\"_\\\"+[Fornitori]Ragione") QR SET INFO COLUMN($ID;1;"Fornitori";"[Fornitori]Fornitore+\\\"_\\\"+[Fornitori]Ragione";0;-152;0;Char(0)) bisogna rimuovere la tripla "\" con una sola, così: QR INSERT COLUMN($ID;1;"[Fornitori]Fornitore+\"_\"+[Fornitori]Ragione") QR SET INFO COLUMN($ID;1;"Fornitori";"[Fornitori]Fornitore+\"_\"+[Fornitori]Ragione";0;-152;0;Char(0)) |
||||||||||||||||||||||
Info |
LAUNCH EXTERNAL PROCESS come Terminale MacOSX o Prompt dei comandi Windows
Abbiamo visto in varie faq l'uso di LAUNCH EXTERNAL PROCESS. Ribadiamo che è utilizzabile non solo per l'esecuzione di applicazioni o file batch, ma per qualsiasi comando (anche con parametri) del Terminale Apple MacOSX o del Prompt dei comandi Windows. Non può però eseguire comandi della shell (tipo il comando echo) Possiamo quindi scrivere direttamente: LAUNCH EXTERNAL PROCESS ("chmod +x /cartella/miofile.ese") per cambiare i permessi ad un file MacOS X. Il comando è di default Sincrono, cioè 4d aspetta che sia eseguito. Se si volesseeseguirlo in modalità asincrona è necessario lanciare prima il comando SET ENVIRONMENT VARIABLE con l'opzione _4D_OPTION_BLOCKING_EXTERNAL_PROCESS. |
||||||||||||||||||||||
Info |
Una nota sui registratori di cassa
Ultimamente ho dovuto analizzare alcuni protocolli per la comunicazioni con i registratori fiscali. Ho provato il protocollo XON-XOFF, uno standard per molte casse. La comunicazione si svolge utilizzando degli stream di testo con dei separatori che indicano il tipo di dato. Un protocollo di questo tipo, proprio perché standard, non gestisce però le caratteristiche proprietarie del singolo registratore. Dovendo in particolare usare i registratori di cassa Kube F della Custom Engineering, ho potuto verificare come utilizzare il protocollo di comunicazione proprietario della cassa fiscale risulta più difficoltoso per la quantità di parametri da gestire, ma consente d'altra parte una gestione completa e accurata della transazione. |
||||||||||||||||||||||
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 | |||||||||||||||||||||
Info |
Pulire la porta seriale
Capita in alcune comunicazioni seriali che il comando SEND PACKET non venga interpretato correttamente o restituisca risposte strane. Una buona idea può essere quella di "pulire" la comunicazione seriale prima del SEND PACKET con un RECEIVE BUFFER. Il codice diventa: RECEIVE BUFFER($buffer) ` pulisci la seriale SEND PACKET($Comando) |
||||||||||||||||||||||
Plugin |
Corrispondenza fra i tipi di dati per DLL Wizard e i tipi 4D
Ecco un elenco sommario delle corrispondenze fra i tipi di dati usati da DLL Wizard e i corrispondenti tipi del linguaggio di 4D. 8-bit: (char, BOOL, BYTE, CHAR, UCHAR, BOOLEAN, CCHAR) E' possibile passare una variabile integer, longint o real ma le più appropriate sono integer e longint. Passando un real viene effettuata la conversione (a scapito della velocità). 16-bit: (short, WORD, UWORD, SHORT, USHORT) E' possibile passare una variabile integer, longint o real ma la più appropriata è integer. Passando un real viene effettuata la conversione (a scapito della velocità). 32-bit: (long, word, int, void*, DWORD, LONG...) E' possibile passare una variabile integer, longint o real, ma la più appropriata è longint. Passando un real viene effettuata la conversione (a a scapito della velocità). string pointers: (char*, LPCSTR, LPSTR, LPCTSTR, LPTSTR...) E' possibile passare una variabile alpha o text. Se si usa alpha attenzione alla lunghezza (se si dichiara una variabile 4D di lunghezza inferiore rispetto al dato ottenuto dalla DLL, la stringa viene troncata). Per stringhe olte gli 80 caratteri è necessario passare un text (col limite dei 32.000 caratteri). I caratteri vengono convertiti in modalità ANSI prima di essere inviati alla DLL e, alla ricezione, riconvertiti in ASCII Macintosh. float values (32 bits): (float) E' possibile passare una variabile integer, longint o real, ma la più appropriata è real. L'uso di altri tipi può comportare sia rallentamenti (per la conversione) che perdita di dati (i real hanno precisione doppia). double values (64 bits): (double, GLdouble) E' possibile passare una variabile integer, longint o real, ma la più appropriata è real. L'uso di altri tipi può comportare rallentamenti. |
||||||||||||||||||||||
Plugin |
I tipi di dati per DLL Wizard
Per chi, come lo scrivente, usa raramente DLL Wizard, ecco un elenco completo dei tipi di dati gestiti (solitamente, usando DLL Wizard, solo i primi due-tre tipi sono visualizzati):
|
||||||||||||||||||||||
Comandi |
Aggiungere un elemento agli array di una listbox: INSERT LISTBOX ROW
Il caso è banale: aggiungere a tutti gli array di una listbox un elemento (possibilmente in fondo) per inserire una nuova riga. Una possibilità è aggiungere un elemento ad ognuno degli array che compongono la listbox. Oppure si può usare INSERT LISTBOX ROW ({*; }object; position) per inserire un elemento in posizione position a tutti gli array della listbox. In ogni caso poi bisogna usare EDIT ITEM per modificare l'elemento inserito. |
||||||||||||||||||||||
Comandi |
Differenza fra EDIT ITEM e GOTO AREA
I comandi EDIT ITEM e GOTO AREA servono per spostarsi su una certa zona di un form. La differenza sta nel tipo di oggetti su cui tali comandi si applicano. EDIT ITEM ({*; }object{; item}) permette di modificare gli elementi di:
item indica l'elemento da modificare, se utilizzabile. In tutti gli altri casi si usa GOTO AREA. |
||||||||||||||||||||||
Novita' |
[v11 SQL] Uso di INSERT
Continuiamo nella presentazione dei comandi SQL parlando di INSERT. La sintassi è assai agevole: INSERT INTO {sql_name | sql_string} [(column_reference, ..., column_reference)] {VALUES({arithmetic_expression |NULL}, ..., {arithmetic_expression |NULL}) |subquery} dove {sql_name | sql_string} denotano in qualche modo la tabella dove eseguire gli inserimenti, >[(column_reference, ..., column_reference)] sono i campi dove verranno inseriti i dati, e i dati possono essere espressioni o anche altre sottoespressioni SQL. Vediamo di esempi: INSERT INTO table1 (SELECT * FROM table2) inserisce in table2 tutti i record di table1 CREATE TABLE ACTOR_FANS (ID INT32, Name VARCHAR); INSERT INTO ACTOR_FANS (ID, Name) VALUES (1, 'Francis'); crea la tabella ACTOR_FANS, definisce i campi e di seguito inserisce i valori nella tabella. |
||||||||||||||||||||||
Info |
Misurare le prestazioni di un metodo
Un rapido esempio per misurare le prestazioni di un metodo contando il numero di millisecondi: $vrMillisecondsStart:=Milliseconds `qui fai qualsiasi cosa ALERT("Tempo trascorso: "+String(Milliseconds-$vrMillisecondsStart)) Oltre a Milliseconds, si possono usare equivalentemente anche Current time o Tickcount. |
||||||||||||||||||||||
Info |
4D, demo web 2.0 e iPhone / iPod Touch
Il pacchetto 4d Web 2.0 Pack contiene varie cose, fra le quali anche la libreria Ajax Framework .. Per vedere una demo ben spiegata è possibile guardare gli esempi on line su questo sito, dove ci sono le tecniche da utilizzare: http://demo.4d.com:8081/ Una demo di un'applicazione web 2.0 completa (con tecniche particolari come il drag & drop) si trova a questo indirizzo: http://demo.4d.com:8081/demos/wow/personal_planner.html Infine sono disponibili due modi per costruire applicazioni per iPhone/iPod touch.
In queste ultime demo si vede anche l'opzione Offline, perché sono incluse le tecniche per far funzionare tutto anche quando non si è collegati, usando Html 5 o le librerie Google Gears, Safari 3 e Firefox 3 supportano HTML 5. Gli utenti di Internet Explorer 7 e Firefox 2+ devono installare Google Gears per andare offline. |
||||||||||||||||||||||
Info |
[v11 SQL] Coordinate di un clic sulle immagini
4D dà le coordinate di un click sulle immagini nelle due variabili di sistema MouseX e MouseY: contengono il numero di pixel di distanza dal punto in alto a sinistra dell'immagine (0,0). La cosa veramente interessante è che se l'immagine è mostrata con il formato "Truncated non-centered" le coordinate sono corrette automaticamente in funzione anche di eventuale zoom o spostamento dell'immagine nel riquadro che la ospita. Le due variabili vanno valutate all'interno di un form event On Clicked oppure On Double Clicked. |
||||||||||||||||||||||
Tecniche |
Indirizzare la stampa su un cassetto della stampante
In linea di massima (solo sotto Windows):
|
||||||||||||||||||||||
Bug |
4D v_11 caratteri ascii dal 1 al 8
4D V 11.2 In preferenze non settato unicode mode $Test:=Char(5) ` dal 1 al 8 Non funziona If ($Test#"") ` fai qualche cosa End if Sostituito con: If (Position(Char(5);$Test;1)>0) ` fai qualche cosa End if |
||||||||||||||||||||||
Info |
Ajax o Flex?
Scritto in parole povere e per programmatori che vogliono sapere il succo della cosa: Web 2.0 è in linea di massima il sistema di far funzionare una pagina del browser come se fosse un'applicazione senza doverla ricaricare, com'è normale nella navigazione web. Quindi l'utente rimane nella stessa finestra e la sensazione è più simile a quella di un applicativo in locale. Ajax utilizza pagine html, css e javascript : le singole chiamate al sito sono processate all'interno del codice javascript con un comando che fa la richiesta al server e aspetta la risposta senza appunto cambiare pagina. Flex è un sistema di Adobe per fare la stessa cosa in modo più veloce perché usa il Flash come se fosse un runtime; però bisogna usare actionscript e pagine mxml e compilare ogni volta che si fa una modifica producendo dei file swf. Il vantaggio oltre alla velocità di esecuzione è che il risultato è molto più browser indipendente. Entrambe le soluzioni in teoria non costano niente, perché usano librerie software opensource. Anche l'SDK di flex è opensource e scaricabile gratuitamente, Adobe vende il sistema di editing (basato sul progetto opensource Eclipse) che rende più agevole il ciclo di produzione. 4d per entrambe le soluzioni ha preparato delle librerie o framework (che credo siano distribuite dentro 4d Web 2.0 Pack) che permettono di utilizzare nel modo più diretto possibile sia con la versione 2004 che con la v11. |
||||||||||||||||||||||
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 | |||||||||||||||||||||
Novita' |
[v11 - Conferenza] Uso dei nuovi tipi di indice [1]
La v11 mette a disposizione una svariata serie di indici. Eccone una breve spiegazione con relativo utilizzo: - BTree index è da usare per valori non ripetuti (ID dei record, ragioni sociali, nomi, ecc.) - Cluster index per valori ripetuti (booleani, categorie, sesso, ecc.) - Composite index (indici compositi) per gli ordinamenti(Nome + Cognome, Città + CAP, ecc.) - Keyword index per i testi. |
||||||||||||||||||||||
Info |
[v11 - Conferenza] Uso dei nuovi tipi di indice [2]
Alcune info aggiuntive sugli indici della v11. Il sistema di realizzazione del keyword index non è personalizzabile al momento, ma lo sarà. Se si usa QUERY su un campo indicizzato sia normalmente che con keyword index, quest'ultimo indice ha la precedenza (la ricerca verrà fatta sulle parole). Con il keyword index non si può usare la sintassi "@TESTO@", ma si può usare quella "TESTO@". Al momento, se si sceglie come tipo di indice "Automatic", 4D userà il cluster per i booleani, il BTree per gli altri campi, ma nelle versioni future l'algoritmo di scelta dell'indice verrà raffinato. |
||||||||||||||||||||||
Info |
Se 4D si apre dopo un minuto di inspiegabile attesa...
Mi capitava spesso di assistere ad un comportamento strano di 4D. Facendo doppio clic sulla struttura da aprire, il programma restava per circa un minuto in uno stato di attesa senza alcun apparente motivo. Passata questa attesa il programma si apriva regolarmente. Allo stesso modo, l'apertura della finestra di impostazioni di stampa aveva gli stessi tempi d'attesa. Il motivo è da ricercare nei driver di stampa delle stampanti in rete. Se la stampante predefinita del computer in questione è una stampante condivisa proveniente da un'altra macchina o da un print server, con alcuni driver si hanno i tempi di attesa descritti. Una soluzione può essere quella di utilizzare come stampante predefinita una stampante "falsa", e poi scegliere la stampante corretta in funzione della stampa richiesta. |
||||||||||||||||||||||
Info |
ONE RECORD SELECT
Il comando ONE RECORD SELECT usa la sintassi: ONE RECORD SELECT {(table)} e permette di ridurre la selezione della tabella table (se omessa è la default table) al redcord corrente. Se non esiste un record caricato in memoria o non esiste un record corrente il comando non ha effetto. |
||||||||||||||||||||||
Tecniche |
Come mettere gli Help Tips da programma
Cito una bella soluzione di Pat Bensky, dal Nug americano: Noi abbiamo definito un unico HelpTip. Questo contiene solamente <HelpText> HelpTip è selezionato per ogni oggetto su cui vogliamo che appaia l'aiuto. Dentro l'oggetto il codice è così: Case of :(form event=on mouse enter) HelpText:="quello che vuoi scrivere in questo aiuto" End case |
||||||||||||||||||||||
Novita' |
[v11 SQL] Quattro modi per utilizzare SQL [4]
Partiamo sempre dalla query 4D Un quarto modo per interagire col motore SQL di 4D è quello di utilizzare il comando EXECUTE IMMEDIATE all'interno di un blocco Begin SQL - End SQL. La query diventa: |
||||||||||||||||||||||
Novita' |
[v11 SQL] Quattro modi per utilizzare SQL [3]
Partiamo sempre dalla query 4D Un terzo modo per ottenere gli stessi dati via SQL è quello di utilizzare il comando QUERY BY SQL. In questo caso l'esempio diventa: Infatti il comando QUERY BY SQL non fa altro che eseguire una semplice SELECT del tipo: SELECT * FROM myTable WHERE <SQL_Formula> dove myTable è la tabella passata come primo parametro a QUERY BY SQL, e SQL_Formula il secondo parametro; otterremmo: QUERY BY SQL(myTable;SQL_Formula) Nel nostro caso, in cui non esiste una clausola WHERE, ne forziamo l'esistenza con "ID <> 0" e la query SQL eseguita diventa: SELECT * FROM MOVIES WHERE ID <> 0 |
||||||||||||||||||||||
Novita' |
[v11 SQL] Quattro modi per utilizzare SQL [2]
Partiamo sempre dalla solita query 4D Un secondo sistema per ottenere dati da 4D usando SQL è quello di eseguire una query ODBC usando come origine dei dati lo stesso database 4D. L'esempio diventa: dove al comando ODBC LOGIN viene associata come fonte dati SQL INTERNAL. |
||||||||||||||||||||||
Novita' |
[v11 SQL] Quattro modi per utilizzare SQL [1]
Supponiamo di avere la seguente query in modalità 4D Un primo modo per ottenere lo stesso risultato via SQL diventa il seguente: dove il riferimento a $AllMovies viene effettuato attraverso i caratteri speciali "<<" e ">>" Una sintassi equivalente è data dall'uso di ":" Una attenzione particolare deve essere posta alle variabili interprocesso, dove diventa necessario l'uso delle parentesi quadre: |
||||||||||||||||||||||
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 | |||||||||||||||||||||
Tecniche |
Controllo della correttezza di una password: il nuovo Position
Abbiamo visto in una faq precedente come confrontare due stringhe, ad esempio la password inserita da un utente. La nuova versione di 4D, v11 SQL, permette di evitare il ciclo sul controllo del codice Ascii (adesso Character code) dei caratteri. Si può infatti usare in sostituzione il comando Position, che ha assunto questa rinnovata sintassi: Position (find; aString; start; lengthFound; *) dove - find è la stringa da cercare; - aString è la stringa dove effettuare la ricerca; - start è il numero che l'iesimo carattere della stringa aString da cui iniziare la ricerca; - lengthFound se specificato, è una variabile che conterrà la lunghezza della stringa trovata in aString (necessaria quando si cerca æ e si trova ae, ß e si trova ss, ecc., nei due casi citati lengthFound varrebbe 2); - * se specificato, effettua la ricerca in maniera diacritica, distinguendo cioé maiuscole da minuscole, accentate da normali, ecc. Nel nostro caso, il confronto fra la stringa e la password sarebbe: $position:=Position($pwd;ThePassword;1;$length;*) $uguali:=(($position=1) & ($length=Length(ThePassword))) |
||||||||||||||||||||||
Info |
4D Chart: CT SET LABEL ATTRIBUTES
CT SET LABEL ATTRIBUTES permette di impostare la modalità di visualizzazione delle etichette. La sintassi è: CT SET LABEL ATTRIBUTES (area; object; axis; position; orientation; format{; frequency}) dove: - area è l'area di Chart - object è il grafico - axis è l'asse su cui agire: 0 = Category 1 = Series 2 = Values - position è la posizione dell'etichetta: -1 = No modifica 0 = Nessuna 1 = Sopra 2 = Sinistra 3 = Sotto 4 = Destra - orientation è l'orientamento: -1 = No change 0 = Normal 1 = Vertical 2 = Rotated right 3 = Rotated left 4 = Staggered 5 = Wrap around - format è una stringa che imposta il formato di visualizzazione - frequency è un intero (opzionale) che specifica ogni quanti valori visualizzare l'etichetta; il parametro è molto utile per i grafici molto "densi". Ecco ad esempio come visualizzare le etichette sull'asse X ogni 3 valori: CT SET LABEL ATTRIBUTES (Area;$Chart;0;-1;-1;"";3) |
||||||||||||||||||||||
Plugin |
4D Chart: CT SET PROPERTIES
CT SET PROPERTIES permette di impostare le proprietà dell'area 4D Chart. La sintassi è: CT SET PROPERTIES (area; printOrder; changeAlert; hotlinkType; saveAlert) dove - area è l'area di Chart - printOrder è l'ordine di stampa (non l'orientamento): 0 in orizzontale, 1 in verticale, -1 non modificare - changeAlert mostra un alert se l'utente prova a modificare l'area - hotlinkType è un parametro obsoleto, usare come valore -1 - saveAlert per chiedere all'utente il salvataggio dell'area. Per changeAlert e saveAlert e valori utilizzabili sono: 0 nessun messaggio, 1 avverti, -1 non modificare l'impostazione. |
||||||||||||||||||||||
Tecniche |
[v11 SQL] Memorizzazione dei BLOB
Una tecnica che molto presto i programmatori di 4D hanno dovuto imparare è stata quella riguardante lqa gestione dei BLOB. Molto spesso, infatti, gli sviluppatori si vedevano costretti a memorizzare i BLOB in tabelle separate rispette a quelle dei record di appartenenza dei BLOB stessi in modo da velocizzare i tempi di accesso al record, poiché infatti anche in modalità "lista" il record veniva completamente caricato. Tale workaround con la v11 non è più necessario, poiché infatti i BLOB vengono caricati solo quando viene carica to il dettaglio del record, velocizzando così notevolmente l'accesso alle liste dei dati. |
||||||||||||||||||||||
Info |
[v11 SQL] I file .RSR e .4DR
Con la nuova versione di 4D sono scomparsi i file .RSR e .4DR. Per essere più precisi, in realtà dei file di risorsa personalizzati possono essere creti e mantenuti all'interno della Cartella Resources presente sia nella cartella contenente la struttura che nella cartella dell'applicazione 4th Dimension. |
||||||||||||||||||||||
Plugin |
4D Chart: CT MOVE
il comando CT MOVE permette di spostare degli oggetti all'interno dell'area di chart. La sibntassi è: CT MOVE (area; scope; newLeft; newTop) dove area è la'area di Chart; scope indica a quali oggetti applicare il movimento: -1 indica tutti gli oggetti dell'area, 0 indica gli oggetti attualmente selezionati, un altro numero maggiore di 0 indica l'ID dell'oggetto a cui applicare l'azione; newLeft e newTop sono le nuove coordinate. |
||||||||||||||||||||||
Info |
[v11 SQL] I file di indice
Con la nuova verione di 4D il sistema di indicizzazione è cambiato radicalmente. Gli indici sono memorizzati in due file separati: - il file .INDX è il file che contiene gli indici per i dati; - il file .INDY è il file che contiene gli indici per la struttura. I file si trovano o nella cartella del database (su Windows) o nel package del database (su Mac). Questo approccio ha dei vantaggi non indifferenti: - non viene eseguito un backup degli ndici; - un indice danneggiato non danneggia i dati; - per ricreare tutti gli indici basta cancellare il file INDX: alla successiva apertura del database 4D cercherà il file e, non trovandolo, lo creerà nuovamente in autimatico. |
||||||||||||||||||||||
Plugin |
4D Chart: CT SET CHART COORDINATES
Il comando di 4D Chart CT SET CHART COORDINATES permette di impostare la posizione di un grafico all'interno dell'area. La sintassi è: CT SET CHART COORDINATES (area; object; left; top; right; bottom) dove area è l'area di 4D Chart object è il grafico creato, ad esempio, con CT Chart arrays left; top; right; bottom sono le coordinate del grafico (in punti). |
||||||||||||||||||||||
Plugin |
4D Chart: CT SET LEGEND TEXT
CT SET LEGEND TEXT permette di impostare i titoli delle serie (o delle categorie per i grafici a torta, i pie) di un grafico. La sintassi è: CT SET LEGEND TEXT (area; object; legendItem; legendtext) dove area è l'area di 4D Chart object è il grafico di cui si vogliono impostare i titoli nella legenda legendItem rappresenta la n-esima serie di cui vogliamo impostare il titolo legendtext è il testo che verrà usato come titolo. Si noti che se anche si usa la legenda in modalità reverse (cioé in ordine inverso rispetto a quello di partenza), avendo applicato il comando CT SET LEGEND ATTRIBUTES, legendItem continua a seguire l'ordine originario. |
||||||||||||||||||||||
Plugin |
4D Chart: CT SET DISPLAY
CT SET DISPLAY permette di visualizzare o meno le barre di un'area 4DChart. La sintassi è: CT SET DISPLAY (area; item; displayCode) dove "area" è l'area 4D Chart, "item" è la zona e "displayCode" è la modalità di viasualizzazione Il valore di "item" può essere: 1 Menu Bar 2 Chart Tools 3 Object Tools 6 Scroll Bars 9 Rulers Il valore di "displayCode" può essere: 0 = Nascondi 1 = Mostra 2 = Cambia |
||||||||||||||||||||||
Web |
Inviare immagini dinamiche in una pagina html
Per caricare una immagine dinamica, cioè inviata da 4d in funzione di alcuni parametri o calcoli, in una pagina web occorre inserire un tag del tipo: <img src="/4DACTION/webImmagine?parametro=<!--#4dvar vParametroEsempio-->" alt=""/> Il metodo webImmagine (che deve essere impostato nelle proprietà come disponibile a 4DAction) contiene un codice simile: ... `qui il codice elabora l'immagine usando il parametro passato $immagine:=CT Area to picture (AreaVirt;-2) PICTURE TO GIF($immagine; $mioBlob) SEND HTML BLOB($mioBlob;"image/gif") Con il formato GIF si mantiene meglio la grafica di un'immagine creata con Chart e contenente testo e grafici lineari. Alternativamente, se l'immagine è ad esempio un disegno o una foto potrebbe essere meglio utilizzare il formato Jpeg; allora il codice sarebbe il seguente: ... `qui sempre usando il parametro passato il codice recupera un'immagine da disco $percorso:="Hd:Immagini:"+vParametroEsempio READ PICTURE FILE($percorso;$Immagine) PICTURE TO BLOB($Immagine;$mioBlob;"JPEG") SEND HTML BLOB($mioBlob;"image/jpeg") (grazie ai contributi di Sandro Bonin e Giuseppe Scarafoni) |
||||||||||||||||||||||
Novita' |
[v11.1 SQL] DESCRIBE QUERY EXECUTION
Il comando DESCRIBE QUERY EXECUTION è stato aggiunto nella versione 11.1 del sistema di sviluppo per permettere una migliore analisi delle query. Passando al comando un parametro booleano True si attiva la possibilità di chiedere a 4th Dimension di tenere traccia di come viene eseguita una query (sia essa SQL o del linguaggio 4D). Le query infatti sono ottimizzate da 4D per essere efficenti al massimo, ma non è detto che il nostro modo di pensare una ricerca sia migliore da un punto di vista prestazionale rispetto alla stessa ricerca eseguita in altro modo. Gli aspetti che 4D permette di analizzare sono: - come viene pianificata la query (query plan); - come viene eseguita la query (query path). Tali informazioni vengono ottenute tramite i nuovi comandi Get Last Query Plan e Get Last Query Path. Ecco un esempio: C_TEXT ($vResultPlan;$vResultPath) ARRAY TEXT (aTitles;0) ARRAY TEXT (aDirectors;0) DESCRIBE QUERY EXECUTION (True) `analysis mode Begin SQL SELECT ACTORS.FirstName, CITIES.City_Name FROM ACTORS, CITIES WHERE ACTORS.Birth_City_ID=CITIES.City_ID ORDER BY 1 INTO :aTitles, :aDirectors; End SQL $vResultPlan:=Get Last Query Plan (Description in Text Format) $vResultPath:=Get Last Query Path (Description in Text Format) DESCRIBE QUERY EXECUTION (False) `End analysis mode |
||||||||||||||||||||||
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 | |||||||||||||||||||||
Novita' |
[v11 SQL] Confronto di caratteri ascii inferiore a 32
Dalla versione v11 SQL il parametro di confronto = non distingue più i caratteri da 1 a 8 e da 14 a 31. Quindi il Char(2) = Char(3), esattamente come fa con "A"="à". La cosa è importante per chiunque abbia sviluppato procedure di controllo del flusso delle seriali, ad esempio dove appunto questi caratteri servono come delimitatori. La soluzione è ovviamente quella di confrontare il Character Code, cioè: Character code(Char(2)) # Character code(Char(3)) |
||||||||||||||||||||||
Comandi |
[v11 SQL] Il comando OPEN SECURITY CENTER
Dalla versione v11 non è più necessario utilizzare un applicativo 4D Tools per le operazioni di manutenzione. Le funzionalità sono ora disponibili all'interno dell'applicazione, nella cosiddetta MSC, cioè Maintenance and Security Center. Per dare la possibilità all'utente finale di accedere alla stessa finestra, è possibile utilizzare il comando OPEN SECURITY CENTER. Alcune funzioni vengono automaticamente disabilitate in funzione dei privilegi dell'utente corrente. |
||||||||||||||||||||||
Info |
[v11 SQL] Licenze di distribuzione dei pacchetti monoutente
Dalla versione v11 ci sono alcune novità nella distribuzione degli applicativi prodotti. Innanzitutto non occorre più acquistare un engine, ma il runtime è incluso gratuitamente nel pacchetto di sviluppo. Inoltre nel runtime Unlimited Desktop sono inclusi senza spese aggiuntive il 4D Write e il 4D View. Ecco uno schema delle varie opzioni: 4D Interpreted Desktop Questa licenza è inclusa nel pacchetto di sviluppo 4D Developer Standard e permette la distribuzione di applicazioni in monoutenza non compilate con il runtime 4D Desktop. 4D Unlimited Desktop Questa licenza è inclusa nel pacchetto di sviluppo 4D Developer Professional e permette la distribuzione di applicazioni in monoutenza sia interpretati che compilati con 4D Desktop oltre che alla creazione di applicazioni incorporando la struttura nel runtime. Questa licenza include senza costi aggiuntivi le espansioni 4D Write e 4D View. 4D Web Application Server Questa licenza permette agli sviluppatori di distribuire applicazioni compilate o interpretate con 4D Desktop che abbiano la funzionalità di Server Web e di Server Web Services. Questa licenza include anche le funzionalità SQL Pass Through e ODBC Login per permettere al database di collegarsi ad altre fonti di dati. La licenza è venduta a postazione e non è inclusa nei pacchetti di sviluppo. 4D SQL Desktop Anche questa licenza non è inclusa nei pacchetti di sviluppo: acquistandola gli sviluppatori possono distribuire applicazioni compilate o interpretate con 4D Desktop con la possibilità di collegarsi a fonti di dati esterne utilizzando le funzionalità SQL Pass Through e ODBC Login. Questa opzione include anche le espansioni 4D Write e 4D View. |
||||||||||||||||||||||
Comandi |
[v11 SQL] Il comando CHECK LOG FILE
Il comando CHECK LOG FILE è assai potente: l'accesso ad esso dovrebbe essere ristretto agli utenti di più alto livello. CHECK LOG FILE permette di consultare il file log e di tornare indietro (Rollback) ad uno stadio precedente della base dati. Il comando è utilizzabile o via Runtime monoutente o da 4DServer, non da un client. |
||||||||||||||||||||||
Novita' |
[v11 SQL] Aprire un file trascinato sull'icona di 4d
Dalla versione v11 è disponibile il metodo del database On Drop, sia in monoutenza che dal client. Il metodo viene eseguito quando si trascina un file dalla scrivania sull'icona di 4d ( o su un'area vuota della finestra contenitore in Windows); normalmente è eseguito solo se l'applicazione è già aperta, però nel caso in cui il programma sia compilato con il Runtime (chiamato ora 4D Desktop) viene lanciato anche all'apertura. Adesso è possibile ad esempio aprire un documento di 4d Write trascinandolo sull'icona dell'applicativo compilato; ecco un esempio di codice da usare dentro il metodo On Drop: fileTrascinato_s:=Get file from pasteboard(1) If (Position(".4W7"; fileTrascinato_s)=Length(fileTrascinato_s)-3) areaEsterna:=Open external window(100;100;500;500;0;droppedFile;"_4D Write") WR OPEN DOCUMENT(areaEsterna; fileTrascinato_s) End if |
||||||||||||||||||||||
Info |
Errori durante il Backup automatico
Dalla versione 2004 il backup è stato integrato in 4D. Quando c'è un problema, sulla schermata del Server è possibile vedere il codice dell'errore. Ecco una breve descrizione:
|
||||||||||||||||||||||
Info |
[v11 SQL] Usare 4D come SQL Server
E' possibile accedere via ODBC a 4D, anche monoutenza, per utilizzarlo come SQL Server. Vi si può accedere da un programma come Crystal Report, Excel o anche un altro applicativo 4D. La funzionalità può essere avviata e stoppata da menu o da linguaggio con i comandi START SQL SERVER e STOP SQL SERVER. Comunque stoppando l'SQL Server l'engine SQL del linguaggio 4D continua a rispondere alle ricerche interne! La porta TCP di accesso standard è la 1919, ma si può cambiare nelle preferenze. Inoltre è possibile nello stesso pannello decidere i privilegi di accesso ai dati per gruppi di utenti: Read Only =in sola lettura Read/Write = in lettura e scrittura Full = è possibile anche modificare la struttura del database |
||||||||||||||||||||||
Novita' |
[v11 SQL] Nuovo valore assunto dalla variabile di sistema Document
La variabile di sistema Document, a partire dalla v11, conterrò sempre il percorso completo del documento. Per essere più precisi, al comando: docRef:=Create document("miodoc.txt") nelle versioni precedenti avremmo ottenuto: Document = "miodoc.txt" Con la v11 SQL invece: Document = "c:\Documenti\ miodoc.txt" oppure Document = "MacHD:Documenti:miodoc.txt" |
||||||||||||||||||||||
Plugin |
Ottenere testo da 4D Write con WR Get text
Il comando WR Get text del plugin 4D Write permette di ottenere testo da un'area (tutta o una parte) di 4D Write. Se ad esempio voglio importare un paragrafo di un'area Write scriverò il codice: C_LONGINT($primo_l;$ultimo_l) $aCapo:=Char(Carriage return ) WR Find (miaArea;$aCapo;0;0;0) WR GET SELECTION (miaArea;$primo_l;$ultimo_l) $testoriga:=WR Get text (miaArea;0;$ultimo_l-1) Il numero massimo di caratteri che il comando ritorna è 32.000. Già dalla versione 2004, e a maggior ragione con la v11 SQL, il comando WR Get text usa correttamente i caratteri Unicode. |
||||||||||||||||||||||
Novita' |
[v11 SQL] Le nuove costanti per BLOB to text
BLOB to text permette di estrarre testo da un blob. Con l'avvento della v11 SQL con la gestione dell'Unicode, le costanti per il secondo parametro, textformat, sono cambiate. Adesso le costanti sono: 0 Mac C string 1 Mac Pascal string 2 Mac Text with length 3 Mac Text without length 4 UTF8 C string 5 UTF8 Text with length 6 UTF8 Text without length |
||||||||||||||||||||||
Componenti |
[v11 SQL] Includere componenti all'interno della Build Application
Con la v11 SQL è possibile usare degli alias delle cartelle contenenti il component all'interno della cartella Conponents. Quando si sceglie Build Application, è possibile scegliere quali component integrare nell'applicazione costruita: così, anche se la cartella Components della versione interprete contiene un alias, in fase di compilazione l'applicazione finale conterrà i componenti effettivi in modo da garantirne la trasportabilità. |
||||||||||||||||||||||
Plugin |
Mettere i plugin dentro l'applicazione 4D
Per avere sempre i plugin disponibili ogni volta che si usa l'applicativo, sia nella versione 2004 che nella v11 è possibile includere la cartella Plugin. In Windows si mette allo stesso livello dell'eseguibile, mentre su Mac occorre metterlo nel bundle: il modo più semplice è chiedere le informazioni (command-I) sull'applicazione e usare il pannello Plugin con cui è possibile aggiungere o togliere i Plugin. ![]() |
||||||||||||||||||||||
Tecniche |
[v11 SQL] Diverso funzionamento di USE SET
Con la nuova versione di 4D, il comando USE SET ha nettamente cambiato comportamento. Se infatti, con le versioni precedenti, USE SET restituiva i record presenti nel set senza altre preoccupazioni, da adesso il comando restituisce un errore se uno dei record del set risulta cancellato nel frattempo. Un'idea per aggirare l'ostacolo potrebbe essere quella presentata dal seguente codice, dove la necessità è quella di usare i record del set "TempSet" creato in precedenza: ALL RECORDS CREATE SET("RecordPresenti") INTERSECTION("TempSet";"RecordPresenti";"TempSet") USE SET("TempSet") |
||||||||||||||||||||||
Codice |
Quando non riesco a cambiare stampante con SET CURRENT PRINTER
Mi è capitato a volte che SET CURRENT PRINTER non mi cambiasse la stampante, soprattutto se la stampante era una stampante di rete. Per autorisolvermi il problema ho adottato alcune strategie. Il primo tentativo, poco fruttuoso in realtà, è stato quello di pingare l'ip della stampante o del print server associato, usando: C_LONGINT($alive) For ($i;1;3) NET_Ping ([Stampanti]IP_da_controllare;"";$alive;1) If ($alive=1) $i:=5 End if End for ma a volte la stampante non veniva variata ugualmente. Allora sono passato all'approccio "controllo se la stampante è cambiata", cioè: Repeat SET CURRENT PRINTER([Stampanti]Stampante) $StampanteCorrente:=Get current printer Until ($StampanteCorrente=[Stampanti]Stampante) Avendo poi visto che in massimo due/tre passaggi la stampante veniva settata, per evitare un controllo troppo bloccante ho deciso di usare: For ($i;1;5) SET CURRENT PRINTER([Stampanti]Stampante) End for Così, se la stampante non viene settata per un qualsiasi motivo, stamperebbe comunque sulla stampante di default, ma questo errore non si è più verificato. |
||||||||||||||||||||||
Tecniche |
Aprire su Mac un file di backup spostato da Windows
Quando si sposta da un server Windows il file di backup per ripristinarlo su Mac, l'applicazione 4D potrebbe non riuscire a riconoscere il file perché mancano Tipo e Creatore. Eseguire questo pezzo di codice per selezionare il file e assegnargli le informazioni corrette: $ris:=Select document("";"";"";Use Sheet Window ) If (OK=1) SET DOCUMENT CREATOR(Document;"4D06") SET DOCUMENT TYPE(Document;"4DBK") End if |
||||||||||||||||||||||
Tecniche |
Come preparare il database alla conversione alla v11 SQL
I database dalla versione 6.0 in poi sono convertiti automaticamente da 4D v11 SQL. Se la versione della base dati è più vecchia è possibile prima convertirla alla 6.5: da notare che non devi avere una licenza per fare l'aggiornamento, basta la versione demo scaricata dal sito di 4d. Ecco una serie di passi da seguire per fare la conversione: Backup – Fai un backup completo della base dati. Verifica con 4D Tools – Assicurarsi che struttura o base dati siano a posto; basta usare la corrispondente versione di 4D Tools. Se il database è a posto è meglio compattarlo. Se è danneggiato invece è meglio provare a ripararlo. Disinstalla i componenti – I vecchi componenti devono essere disinstallati con il 4d Insider. Verifica la compatibilità dei plugin – Sostituisci tutti i plugin 4D con la corrispondente versione 4D v11 SQL. Assicurarsi che gli i plugin non 4d siano compatibili con 4D v11 SQL: in linea di massima si possono usare i plugin utilizzati con la versione 2004. Per Mac sarebbe meglio richiedere la versione Universal dei plugin. Assicurati di avere spazio su disco a sufficienza – 4D v11 SQL durante la conversione duplica tutti i file modificati facendo una copia di sicurezza di base dati e struttura. |
||||||||||||||||||||||
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 | |||||||||||||||||||||
Tecniche |
[v11 SQL] Modifica delle scorciatoie da tastiera
4D v11 SQL introduce nuove scorciatoia di tastiera, molte in allineamento con il normale uso nelle altre applicazioni. Ad esempio, Ctrl-P (win) o Cmd-P (mac) lanciano la stampa, mentre prima servivano ad aprire una procedura selezionata nel method editor. Per chi volesse ripristinare alcune combinazioni a cui si è abituato è possibile seguire questa procedura: - chiudere 4D - identificare nella cartella 4D Extensions all'interno del package su Mac o allo stesso livello dell'eseguibile su Windows - duplicare (per backup) il file 4DShortcuts.xml - Cercare l'elemento che ha come attributo nome "OpenMethod" - Cambiare l'attributo lettera da "K" a "P" - Bisogna assicurarsi che una lettera non sia usata più volte: in questo caso la scorciatoia per "Print" dovrebbe essere cambiata da "P" a "K" - Salvare il file - Rilanciare 4D |
||||||||||||||||||||||
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 | |||||||||||||||||||||
Novita' |
[v11 - Conferenza] DISTINCT VALUES per avere la lista delle singole parole
Sappiamo che DISTINCT VALUES si usa per popolare un array con il contenuto di un campo indicizzato della selezione corrente. Con la v11 SQL il codice: ALL RECORDS([Testo]) ARRAY STRING(80;arrTesto;0) DISTINCT VALUES([Testo]Informazioni;arrTesto) se il campo [Testo]Informazioni è indicizzato per parola chiave (keyword index), DISTINCT VALUES popola l'array arrTesto con le singole parole che compongono i testi del campo [Testo]Informazioni. È inoltre interessante notare che il comando lavora in modo coerente con la selezione. Con la leggera variante al codice precedente: ALL RECORDS([Testo]) REDUCE SELECTION([Testo];1) ARRAY STRING(80;arrTesto;0) DISTINCT VALUES([Testo]Informazioni;arrTesto) (aggiungendo REDUCE SELECTION) l'array viene popolato con le parole dell'unico record che rappresenta la selezione attuale. |
||||||||||||||||||||||
Novita' |
[v11 - Conferenza] Uso di Project Form e DIALOG
I project form sono indipendenti dalla tabella:
Il comando DIALOG adesso può ricevere come form anche una project form, che vengono passate al comando semplicemente col loro nome (senza il primo parametro che indica la tabella). |
||||||||||||||||||||||
Plugin |
[v11 - Conferenza] Futuro di 4D Draw
4D Draw, il plugin di 4th Dimension dedicato al disegno, è destinato a scomparire. Il plugin non è Universal Binary, e dunque per essere usato il database sotto Macintosh dovrà essere utilizzato con Rosetta. Il suggerimento di 4D è di usare le nuove funzionalità grafiche SVG incluse nella nuova versione. |
||||||||||||||||||||||
Comandi |
[v11 SQL] Nuovo comando Choose
4D v11 SQL ha ora un nuovo comando Choose. Invece di scrivere un lungo case per avere un valore in funzione di un parametro singolo, è possibile usare questo comando in una singola riga. Valore:=Choose(Criterio;Valore1;Valore2;..) -Se il Criterio è Boolean, Choose ritorna Valore1 se True o Valore2 se False. In this case, the command expects exactly three parameters: criterion, value1 and value2. -Se il Criterio è un numero, Choose ritorna il valore corrispondente, partendo dal Valore1 per lo Zero. Ad esempio: Lavoro:=Choose([Anagrafica]Mansione;"CEO";"Ingegnere Software";"Barista Starbucks";"Attore") Questo codice è esattamente equivalente a: Case of :([Anagrafica]Mansione =0) Lavoro:="CEO" :([Anagrafica]Mansione =1) Lavoro:="Ingegnere Software" :([Anagrafica]Mansione =2) Lavoro:="Barista Starbucks" :([Anagrafica]Mansione =3) Lavoro:="Attore" End case |
||||||||||||||||||||||
Info |
Evoluzione di 4D Pack: AP ShellExecute
4D v11 SQL dovrebbe essere l'ultima versione di 4D in cui sarà ancora possibile utilizzare il comando del 4D Pack AP ShellExecute. 4D informa infatti che nelle future versioni di 4D non sarà più presente questo comando, egregiamente sostituito dal comando LAUNCH EXTERNAL PROCESS presente nel linguaggio di programmazione di 4th Dimension. Per l'uso di LAUNCH EXTERNAL PROCESS rimandiamo a questa faq. |
||||||||||||||||||||||
Plugin |
[v11 SQL] Controllare l'esistenza di un metodo con AP Does method exist
Il comando AP Create method (presente già nel 4D Pack) consentiva di creare metodi all'interno di una struttura non compilata. Mancava però la possiibilità di controllare se un metodo con il nome specificato esistesse. A questa lacuna pone riparo il comando del 4D Pack AP Does method exist che prende come parametro una stringa e restituisce 0 se il metodo non esiste, 1 altrimenti. |
||||||||||||||||||||||
Comandi |
[v11 SQL] Uso di SELECT
SELECT è il comando del linguaggio SQL che permette di ottenere dei dati. Ecco un sunto della sintassi che può avere: SELECT [ALL | DISTINCT] {* | campo_di_ricerca, ..., campo_di_ricerca} FROM tabella_di_ricerca, ..., tabella_di_ricerca [WHERE condizioni_di_ricerca] [ORDER BY lista_di_ordinamento] [GROUP BY lista_di_raggruppamento] [HAVING condizioni_di_ricerca] [LIMIT {numero_intero | ALL}] [OFFSET numero_intero] [INTO {4d_language_reference, ..., 4d_language_reference | LISTBOX 4d_language_reference}] [FOR UPDATE] |
||||||||||||||||||||||
Info |
Compatibilità con Crystal Reports
Usando Crystal Reports® con 4D è possibile avere dei problemi per i report che usano dati provenienti da più tabelle. Questo perché Crystal Reports® "non sa" come utilizzare le join all'interno e all'esterno di 4D. Per risolvere questo problema basta cliccare, all'interno del DSN che gestisce l'origine ODBC per Crystal Reports, il pulsante "Crystal Reports® Compatibility setup...". Scelto "OK" e riavviata la macchina il problema sarà risolto. Tale pulsante non fa altro che aggiungere alcune chiavi nel registro di sistema (del tipo NoOuterJoinEscSeq=ODBC4D). Tali chiavi sono necessarie sia per Crystal Reports® v10 che per Crystal Reports® v11. |
||||||||||||||||||||||
Codice |
[v11 SQL] Elenco dei 4D server aperti con i nuovi comandi UDP
UDP (User Datagram Protocol) è un protocollo di comunicazione di facile implementazione più snello di TCP (per l'header TCP usa 20 byte, UDP 8) ma non altrettanto affidabile. Se da un lato infatti permette comunicazioni veloci, dall'altra non viene fatto alcun controllo d'errore o riparazione di dati non ricevuti. La v11 SQL mette a disposizione una serie di comandi che implementano la comunicazione via UDP. Quello che segue è un esempio che usa i comandi UDP per ottenere l'elenco dei server 4D presenti in una rete locale. ARRAY STRING (255;asHost;0) ARRAY STRING (32;asMachineName;0) ARRAY STRING (32;asService;0) ARRAY STRING (32;asDBName;0) C_BLOB ($Blob) $indirizzo_t:="255.255.255.255" $Porta_t:=19813 $posizione_l:=32 SET BLOB SIZE($Blob;96;0) TEXT TO BLOB("4D Server";$Blob;Mac text without length;$posizione_l) $Err:=UDP_New(0;$udpID) $Err:=UDP_SendBLOBTo($udpID;$indirizzo_t;$Porta_t;$Blob) $Secondi_l:=2 $Timeout_l:=Milliseconds+($Secondi_l*1000) Repeat DELAY PROCESS(Current process;6) `... espresso in ticks SET BLOB SIZE($Blob;0;0) $guardaIndirizzo_t:=$indirizzo_t $Err:=UDP_ReceiveBLOBFrom($udpID;$guardaIndirizzo_t;$Porta_t;$Blob) If (BLOB size($Blob)>0) $posizione_l:=0 $Host_t:=BLOB to text($Blob;Mac C string;$posizione_l;32) $posizione_l:=32 $Service_t:=BLOB to text($Blob;Mac C string;$posizione_l;32) $posizione_l:=64 $DBName_t:=BLOB to text($Blob;Mac C string;$posizione_l;32) $Pos:=Find in array(asMachineName;$Host_t) If ($Pos>0) APPEND TO ARRAY(asHost;$guardaIndirizzo_t) APPEND TO ARRAY(asMachineName;$Host_t) APPEND TO ARRAY(asService;$Service_t) APPEND TO ARRAY(asDBName;$DBName_t) End if End if Until ((Milliseconds>$Timeout_l) | ($Err#0)) $Err:=UDP_Delete($udpID) |
||||||||||||||||||||||
Codice |
[v11 SQL] Ottenere l'MD5 di un file con AP Get file MD5 digest
L'algoritmo MD5 (Message Digest 5) è una funzione di hash usata per la criptazione dei dati Il comando del 4D Pack AP Get file MD5 digest permette di ottenere il digest MD5 per un certo file. L'uso tipico del comando potrebbe essere il seguente: C_TEXT($thedoc) C_TEXT(<>digest) C_LONGINT($resfork) $resfork:=0 `su Mac: 0 specifica su data fork, 1 su resource fork $thedoc:=Select document $error:=AP Get file MD5 digest($thedoc;<>digest;§resfork) |
||||||||||||||||||||||
Novita' |
[v11 SQL] Il comando COMPONENT LIST
Il comando COMPONENT LIST, che prende come parametro un array, popola quest'ultimo con i nome dei components caricati dal database corrente. Il comando può essere chiamato sia dal database principale che dai componenti stessi. L'array viene riempito con i nomi completi dei file di riferimento (.4db, .4dc or .4dbase). Se non sono presenti componenti, l'array viene restituito vuoto. |
||||||||||||||||||||||
Comandi |
[v11 SQL] Il comando QUERY BY SQL
Avendo al proprio interno un motore nativo SQL, 4D v11 permette di utilizzare il comando QUERY BY SQL per eseguire query su database 4D utilizzando la sintassi SQL. Ad esempio: QUERY BY SQL([Employees];"name=’smith’") equivale alla query SQL: SELECT * FROM Employees WHERE "name=’smith’" in maniera molto simile all'uso di QUERY BY FORMULA. QUERY BY FORMULA non usa le relazioni definite nella struttura del database, le join devono invece essere definite all'interno della query. Ad esempio, se la struttura è: [PEOPLE] Name City [CITIES] Name Population la query sarà: QUERY BY FORMULA([PEOPLE]; [CITIES]Population>1000) oppure QUERY BY SQL([PEOPLE];"people.city=cities.name AND cities.population>1000") |
||||||||||||||||||||||
Componenti |
[4D Pop] Color Chart
Un altro componente della seria 4d Pop che mostra una palette grafica dove scegliere un colore e avere il codice 4d per usarlo nei propri metodi. ![]() Il componente lo potete scaricare da qui: ftp://ftp2-public.4d.fr/demos/francais/multiplateforme/bases_exemples/v11/composants/4DPop%20Color%20Chart.4dbase.zip Open Source Il component è fornito compilato, ma nella cartella è disponibile anche una cartella "Sources" con i sorgenti. |
||||||||||||||||||||||
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 |
||||||||||||||||||||||
Componenti |
[4D Pop] Bookmark
Un altro componente della seria 4d Pop che presentiamo serve a raccogliere una propria lista di indirizzi web. La lista è riordinabile con il drag e drop, editabile con il doppio clic, si possono aggiungere indirizzi trascinandoli dal Finder, dal browser o dal programma di Mail, da qualsiasi programma di testo. Il componente lo potete scaricare da qui: ftp://ftp2-public.4d.fr/demos/francais/multiplateforme/bases_exemples/v11/composants/4DPop%20Bookmarks.4dbase.zip Open Source Il component è fornito compilato, ma nella cartella è disponibile anche una cartella "Sources" con i sorgenti. |
||||||||||||||||||||||
Componenti |
[4D Pop] Migration tools
Il primo componente della seria 4d Pop che presentiamo è utilissimo per chi passa alla versione v11; contiene: 1. Shortcut Editor, con cui è possibile personalizzare le scorciatoie da tastiera di 4d (che sono tutte rinnovate), ma soprattutto sono presenti due menu per impostare tutte le scorciatoie simili alla 2004 oppure per ripristinare tutte quelle di default della v11. 2. Migrate constants: Per chi ha definito delle costanti private nella struttura di 4d usando le risorse 4DK#, questo comando crea un plugin apposta trasferendo tutti i dati necessari. 3. Migrate the macros: questo strumento riformatta tutte le macro che diano errori nel formato della nuova versione Il componente lo potete scarica da qui: ftp://ftp2-public.4d.fr/demos/francais/multiplateforme/bases_exemples/v11/composants/4DPop%20migration.4dbase.zip Open Source Il component è fornito compilato, ma nella cartella è disponibile anche una cartella "Sources" con i sorgenti. |
||||||||||||||||||||||
Componenti |
[4D Pop] La palette per gli sviluppatori
4D ha messo a disposizione un interessante componente, 4D Pop, scaricabile dall'indirizzo: ftp://ftp2-public.4d.fr/demos/francais/multiplateforme/bases_exemples/v11/composants/4DPop.4dbase.zip Questo component mette a disposizione tutti i componenti installati nella struttura all'interno di una palette, chiamata 4D Pop appunto. Il component si installa inserendo il database 4DPop nella cartella Components da creare nella cartella della struttura del nostro software, e nell'"On Statup Database Method" basta scrivere "Install 4DPop" e battere il tab per lanciare una macro che ci scriverà il seguente codice: If (Not(Is compiled mode)) ARRAY TEXT($tTxt_Components;0) COMPONENTS LIST($tTxt_Components) If (Find in array($tTxt_Components;"4DPop")>0) EXECUTE METHOD("4DPop_Palette") End if End if Open Source Il component è fornito compilato, ma nella cartella è disponibile anche una cartella "Sources" con i sorgenti. Esistono inoltre tutta una serie di plugin compatibili 4DPop di cui discuteremo nelle prossime faq. |
||||||||||||||||||||||
Componenti |
[v11 SQL] Componenti
Da questa versione la creazione e la gestione dei componenti è molto più facile e diretta. Creazione: un componente è una struttura generica, chiamata Matrix; per ogni metodo si può indicare se è richiamabile dal programma in cui è usato come componente ( Host ) Maschere: possono essere condivise solo le maschere del progetto, cioé le Form slegate dalle tabelle. Installazione: basta copiare la struttura ( oppure il solo Alias !) in una cartella Components Il componente può essere compilato; in questo caso può essere utilizzato anche in strutture interpretate. Quindi rispetto alle versioni precedenti: 1. non serve più l'Insider 2. non si devono più aggiungere tabelle o form a tabelle del programma ospite 3. Le variabili sono proprie del componente e non si possono sovrapporre a quelle del programma ospite; l'unico modo per accedere alle variabili è usare i puntatori. |
||||||||||||||||||||||
Info |
Limiti di 4D: tipi per variabili e campi *
Ecco i limiti di 4D 2003 per i vari tipi di dati: Date: dal 1/1/100 al 31/12/32.767; Time: da 00:00:00 a 596.000:00:00; Blob: fino a 2Gb; Text: 32.000 caratteri; Longint: da (-2^31) a (2^31)-1; Real: ±1.7e±308 (15 cifre). Nella versione v11 SQL sono modificati o aggiunti questi tipi: Alpha: 255 caratteri; Text: 2 miliardi di caratteri (2GB); Integer 64 bit: da (-2^63) a (2^63)-1; Float: numero reale senza arrotondamenti e conseguente perdita di precisione |
||||||||||||||||||||||
Info |
Limiti di 4D: la struttura *
Ecco elencati i limiti per una struttura 4D fino alla 2004: Data file: 127 segmenti da 2Gb ciascuno; Tabelle: 255; Campi: 511 per tabella; Record: 16 milioni di record per tabella; Indici: 16 milioni di chiavi; Forms; 32.000; Metodi: 32.000 (fino a 2Gb per metodo); Liste: 8.000 item per lista; Sicurezza: 16.000 utenti e 16.000 gruppi; Processi: 32.767 contemporaneamente. Dalla versione v11 SQL i limiti aggiornati di cui abbiamo notizia sono i seguenti: Data file: dimensione del file illimitata (il limite può dipendere dal sistema operativo) Tabelle: 32.767; Campi: 32.767 per tabella; Record: 1 miliardo di record per tabella; Indici: 128 miliardi di chiavi per tabella. |
||||||||||||||||||||||
Comandi |
[v11 SQL] Select folder Usa una cartella di partenza
Nelle precedenti versioni di 4D, il comandoSelect folder permetteva di scegliere una cartella a partire dalla root del sistema. Ciò risultava molto noioso se la cartella da raggiungere era particolarmente annidata. Per migliorare la fruibilità del comando, nell'ultima versione del tool di sviluppo è possibile passare come secondo parametro (opzionale) o una stringa vuota (e in tal modo verrà di default mostrata la cartella dei docimenti impostata sul sistema), oppure il percorso della cartella da mostrare all'apertura della finestra di scelta. E' possibile passare anche un intero (fino a 32000) che indica un determinato percorso memorizzato da 4d e riproposto quando viene usato lo stesso numero, così come succedeva con il comando Select Document. I numeri passati sono condivisi dai due comandi. |
||||||||||||||||||||||
Codice |
[v11 SQL] Scegliere il tipo di indici
Dalla versione v11 è ora possibile scegliere fra diversi tipi di indici: Automatic : il sistema seleziona quello più adatto B-tree : in pratica i classici indici ad albero da sempre usati e adatti più o meno a tutti i casi generali Cluster b-tree : è molto efficiente per i camp che non hanno molte varianti, come possono esserlo i booleani o il campo Sesso Keyword index : è un secondo indice che è possibile aggiungere ai campi alfabetici e testo; velocizza le Ricerche per parola chiave Composite: serve ad ottimizzare ricerche che vanno fatte spesso su più campi, come ad esempio Nome e Cognome oppure Prefisso e Numero di Telefono |
||||||||||||||||||||||
Plugin |
Prestazioni di 4DWrite
Il linguaggio del plugin 4D Write simula le azioni da eseguire su una certa area. E' possibile creare aree "virtuali" chiamate offscreen area che è possibile creare e cancellare in ogni momento. E interessante notare che, dal punto di vista prestazioni, è molto meglio, quando possibile, cancellare il contenuto di un'area e riutilizzarla piuttosto che cancellarla per poi ricrearla (ad esempio all'interno di un ciclo). |
||||||||||||||||||||||
Info |
[v11 SQL] Personalizzare l'icona della finestra di login
E' possibile personalizzare l'icona della finestra di login del database, dove si inserisce utente e password. Per default, l'icona è il logo di 4D: per sostituirla, basta mettere un'immagine chiamata LoginImage.png nella cartella Resources del database, dentro la cartella .4dbase vicino alla struttura. Il file deve essere nel formato "png" con una dimensione di 80x80 pixels |
||||||||||||||||||||||
Codice |
[v11 SQL] Requisiti minimi
Ecco la lista dei requisiti minimi per la v11. La cosa che risalta maggiormante è la necessità di uno schermo con risoluzione minima 1280x1024 (per lo sviluppo almeno, visto che il pulsante "Preferences" del Designer "deborda" in uno schermo 1024x768). Ecco il dettaglio: Windows Pentium III Windows Vista Windows XP 512 MB RAM (1 GB raccomandato) Risoluzione dello schermo 1280x1024 Mac OS Mac Intel ® or PowerPC (G5 raccomandato) Mac OS 10.4.5 o successivo 512 MB RAM (1 GB raccomandato) Risoluzione dello schermo 1280x1024 |
||||||||||||||||||||||
Codice |
[v11 SQL] Cercare duplicati usando il codice SQL
Inn SQL si possono risolvere alcune cose che in 4D sono lunghe e tediose, tipo cercare quanti duplicati ci sono in una tabella di record anagrafici. Ecco un esempio di ricerca in Sql: ARRAY LONGINT(arrayQuanti;0) ARRAY TEXT(arrayRagSoc;0) ARRAY TEXT(arrCitta;0) ARRAY TEXT(arrIndirizzo;0) Begin SQL SELECT count(RagioneSociale), RagioneSociale, Citta, Indirizzo FROM Anagrafica GROUP BY RagioneSociale, Citta, Indirizzo HAVING count(RagioneSociale)>1 INTO :arrayQuanti, :arrayRagSoc, :arrCitta, :arrIndirizzo End SQL La select cercherà nella tabella [Anagrafica] i record che abbiano gli stessi dati nei campi [Anagrafica]RagioneSociale, [Anagrafica]Citta, [Anagrafica]Indirizzo. Poi produrrà 4 colonne di dati e cioè il conteggio e i tre campi con i dati unici. Il risultato andrà negli array elencati in coda nello stesso ordine dei campi della prima riga. |
||||||||||||||||||||||
Tecniche |
[v11 SQL] Variabile degli oggetti nelle maschere
Le variabili associate ad un oggetto in una form può ora contenere non solo il nome di una variabile, ma anche direttamente una qualsiasi espressione o funzione in linguaggio 4d. Ad esempio, un oggetto picture può contenere la variabile pictFoto oppure il campo [utente]foto oppure ancora la funzione: dammiFoto([utente];"formatopiccolo") |
||||||||||||||||||||||
Codice |
[v11 SQL] Passaggio di parametri ai comandi SQL
Per passare un valore dinamico fra il linguaggio di 4d e l'SQL, si possono indicare i nomi delle variabili o in due coppie di segni minore/maggiore o prefissarli con un due punti, ad esempio: < :miaListBox La notazione con i due punti rappresenta un parametro per una Parameterized Query. La notazione con i segni di maggiore/minore viene chiamata Direct Association. Ecco due esempi: `Mostra il risultato di una select in una List Box, miaListBox. Begin SQL SELECT * FROM Angarafica INTO < End SQL `Inserisci un determinato valore in una chiamata sNome:="Mario" Begin SQL SELECT * FROM Anagrafica WHERE Nome = :sNome End SQL |
||||||||||||||||||||||
Codice |
[v11 SQL] Dove si trova l'insider?
L'insider non c'è più come applicativo a parte e le sue funzioni sono ora incorporate.. ad esempio:
|
||||||||||||||||||||||
Codice |
[v11 SQL] Campi testo, BLOB e immagini
In 4D v11, i campi testo, BLOB e immagini che possono contenere fino a 2gb di dati sono registrati fuori dal record stesso: questo aumenta la velocità del database, specialmente durante le ricerche: quando 4d accede al record non carica in memoria tutti i dati contenuti in questi campi. Sono invece caricati automaticamente quando il record cercato viene trovato. L'operazione non richiede nessuna modifica al codice esistente, se non che rende inutile eventuale codice impostato per registrare questi campi in una tabella separata: questa tecnica funziona ancora, ma con la v11 non serve più. |
||||||||||||||||||||||
Codice |
[v11 SQL] Informazioni sugli oggetti delle form
Durante lo sviluppo di una form, esiste una nuova scorciatoia per avere delle informazioni veloci (nome, coordinate, etc) su un oggetto qualsiasi. Per vederle basta tenere premuto la combinazione di tasti Ctrl+Shift (su Windows) o Command+Shift (su Mac) puntando sull'oggetto con il mouse. |
||||||||||||||||||||||
Novita' |
[v11 SQL] Come gestire i numeri di tabella e di campo
La possibilità di cancellare tabelle e campi pone un problema con la gestione di Count tables e Count fields, i comandi che permettevano di conoscere le dimensioni di riferimento nella struttura. I due comandi sono stati adesso modificati in Get last table number e Get last field number, che permettono di conoscere gli ultimi numeri di tabella e di campo usati. Visto però che alcune tabelle o campi potrebbero essere stati cancellati, si dovranno usare anche i nuovi comandi Is table number valid e Is field number valid, che ritornano True se tabella o campo non sono stati cancellati. Un ciclo completo sulla struttura diventa dunque: For($thetable;1;Get last table number) If (Is table number valid($thetable)) For($thefield;1;Get last field number($thetable)) If(Is field number valid($thetable;$thefield)) ... `il campo esiste ed è valido End if End for End if End for |
||||||||||||||||||||||
Codice |
[v11 SQL] Nuove proprietà delle ListBox
Le Listbox sono degli oggetti che permettono di mostrare nelle maschere griglie di dati. Dalla versione v11 le ListBox possono essere collegate (anche da linguaggio di programmazione) alla selezione corrente di una tabella o ad una named selection (in pratica una selezione salvata con un suo nome). Quando è collegata alla selezione corrente una listbox editabile aggiorna contemporaneamente i dati e riceve automaticamente gli aggiornamenti. Un'altra cosa interessante la possibilità di riempire al volo una listbox con il risultato di una select: Begin SQL select * from Anagrafica into :Listbox End SQL Questo codice riempirà automaticamente la listbox con i dati dalla tabella Anagrafica eventualmente creando le colonne mancanti o rendendo invisibile le colonne di troppo. |
||||||||||||||||||||||
Codice |
[v11 SQL] Ricerca per parola chiave
E' disponibile un nuovo comando che effettua la ricerca di una "parola" intera in un campo testo. Nella finestra delle Query l'operatore si chiama “contains keyword”, mentre nel linguaggio (nei comandi QUERY) si può usare il carattere % . La funzione trova solo singole parole che nel testo siano separate dalle altre da spazi o punti, virgole, etc. La ricerca è indifferente alle maiuscole e ai caratteri diacritici, tipo l'accento sulle vocali) e rispetta la @ come wildcard. |
||||||||||||||||||||||
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 | |||||||||||||||||||||
Comandi |
[v11 SQL] USE EXTERNAL DATABASE: query SQL esterne nel codice 4D
Il comando USE EXTERNAL DATABASE, la cui sintassi è USE EXTERNAL DATABASE (sourceName{; user; password}) permette di utilizzare il motore SQL di 4D (e le relative query) per accedere a dati presenti in DSN definiti nel sistema. Usando questo comando, tutte le successive chiamate del processo del tipo Begin SQL/End SQL saranno indirizzate al database sourceName, finché non viene utilizzato il comando USE INTERNAL DATABASE o un altro USE EXTERNAL DATABASE per accedere ad altri DSN (simile, per capirci, al funzionamento di SET QUERY DESTINATION). Ecco un esempio: C_TEXT(sourceNamesArr;sourceDriversArr;0) |
||||||||||||||||||||||
Codice |
Ingrandire un'immagine in una variabile
Se avete una variabile immagine in un form, potete zoomarla (ingrandirla o rimpicciolirla) moltiplicando la variabile per un numero maggiore o minore di 1. Ad esempio: immagineNelForm:= immagineNelForm * 1.1 `per ingrandirla del 10% immagineNelForm:= immagineNelForm * 0.9 `per rimpicciolirla del 10% |
||||||||||||||||||||||
Info |
Collegamento a SQL Server da Mac OS X
Ci sono tre possibilità di driver ODBC per Microsoft SQL Server per Mac OS X: OpenLink Software dal costo di 99$ Actual Technologies dal costo di 29$ FreeTDS gratis, ma bisogna ricompilarlo su mac e la versione 0.64 ha qualche problema nell'esecuzione dei comandi tipo SQLTables (che ritorna la lista delle tabelle). Questi driver sono tutti basati sulla libreria (o framework) chiamata iODBC, che si trova inclusa nelle installazioni dei primi due e deve essere installata a parte nel terzo caso oppure quando bisogna aggiornarla rispetto a quelle preinstallate. Per ottenere la sola libreria iOdbc (che è gratuita) già compilata per Mac OS X si può scaricare dal sito OpenLink solo l'opzione SDK che ha appunto l'ultima versione, attualmente la 3.52.5. Ad esempio, la versione attuale dell'Actual Technologies (v. 2.7), installi iOdbc 3.52.2 che dà degli errori durante l'uso del driver (dà la lista delle tabelle, ma non carica i dati). |
||||||||||||||||||||||
Bug |
Bug del Check Syntax in Client Server 4D 2004 Mac
Se in una installazione client server ad un certo punto non riuscite a fare più il check syntax, provate a ridurre il nome della struttura. In pratica sembra che il nome della cartella delle preferenze debba essere minore di 32 caratteri: il nome è costruito come nome + indirizzo ip + porta, nel caso in cui serva una porta diversa. Con "_" al posto degli spazi, cosi: NOMESTRUTTURA.4DB_123_123_123_123_19815 |
||||||||||||||||||||||
Novizi |
Convertire un'applicazione da Macintosh a Windows
In linea di massima, 4d in versione windows apre la struttura e i dati creati su Mac. In particolare, ecco alcuni punti da verificare: 1. Struttura dei file Se la versione di 4d è la 2003 occorre splittare i file Mac separando il documento dalle risorse, con le estensioni finali 4DB e RSR per la struttura e 4DD e 4DR per i dati, usando l'applicativo 4D Transporter (gratuito, scaricabile dal sito di 4d, funziona su Mac). Se il programma è invece stato creato con la 2004 dovrebbe essere già splittato. 2. Plugin Se la versione di 4d è la 2003 ci potrebbe essere allo stesso livello della struttura una cartella Mac4DX con dei plugin di comandi aggiuntivi; occorrerà avere una cartella Win4DX e controllare che ci siano gli stessi plugin in versione windows. Nella versione di 4D 2004 le cartelle Mac4DX e Win4DX sonos sostituite dalla cartella Plugins che contiene una versione dei plugin multipiattaforma, per cui in questo caso non ci sarebbe niente da fare. 3. Estetica Nella versione per Mac potrebbero essere stati usati font e dimensione di campi non perfettamente riproducibili in automatico su Windows. Ci sono varie tecniche per assegnare font in automatico (tipo usando gli stili), ma dipende da come è stato disegnato il programma. In generale, bisogna fare un giro nelle varie maschere a verificarne la leggibilità. |
||||||||||||||||||||||
Plugin |
Taglia e incolla con 4DWrite
Per effettuare le operazioni di taglia e incolla con 4DWrite si possono seguire due strade. La prima è quella di usare WR EXECUTE COMMAND (Temporary;wr cmd cut ) e WR EXECUTE COMMAND (Temporary;wr cmd paste ) per effettuare le operazioni tramite gli appunti. L'altra possibilità è usare: $myTempBlob:=WR Get styled text (Temporary) e WR INSERT STYLED TEXT (Temporary;$myTempBlob) Questo metodo consente il trasferimento del testo con i suoi attributi (colore, stile), eccettuato i nomi degli stili e i dati sui paragrafi (margini, tabulazioni, ecc). |
||||||||||||||||||||||
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 | |||||||||||||||||||||
Codice |
Print one job (Print Record+ Print form)
Per ottenere un unico documento dalla stampa di un record, magari anche multipagina, ed un allegato (utile per invio di Fax) inserire nel metodo del Form If (b_DaEseguire) Print form([TABLE];"Allegato_A") PAGE BREAK b_DaEseguire:=False End if mentre il metodo chiamante sara' quello standard per stampe OUTPUT FORM([TABLE];"Form") b_DaEseguire:=True PRINT RECORD([TABLE]) verificare che sia abilitato il selettore 'On Header' del Form del Record (purtroppo viene stampato per primo l'allegato) |
||||||||||||||||||||||
Codice |
Integrare Ajax Framework con una gestione web esistente
Se avete già una gestione delle pagine Web sul vostro applicativo 4D, quando installate Ajax Framework della 4d Web Pack 2.0, oltre alle istruzioni indicate nella documentazione, modificate così il metodo generale della On Web Connection: ` On Web Connection C_TEXT($1;$2;$3;$4;$5;$6) If ($1="/DAX/@") DAX_Dev_OnWebConn($1;$2;$3;$4;$5;$6) Else ` qui va il codice preesistente End if |
||||||||||||||||||||||
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 | |||||||||||||||||||||
Plugin |
ODBC: ridurre il numero di righe ritornate da una query SQL
E' possibile ridurre il numero di record restituiti da una query SQL utilizzando la costante ODBC MAX ROWS all'interno del comando ODBC SET OPTION. Ecco un esempio: ODBC LOGIN("TestODBC";"";"") SQLStmt:="SELECT * FROM Clienti" ODBC SET OPTION(ODBC Max Rows ;100) ODBC EXECUTE(SQLStmt;[Result1]Field1;[Result1]Field2) ODBC LOAD RECORD(ODBC All Records ) |
||||||||||||||||||||||
Novizi |
Numero di record limitato o illimitato
Quando si usa il comando SET QUERY LIMIT per limitare il numero di record ritornati da una query, è necessario reimpostare subito dopo il numero di record ritornati a "illimitato", usando SET QUERY LIMIT(0) Altrimenti, infatti, il numero di record ritornati dalle query all'interno del processo corrente sarà sempre limitato. |
||||||||||||||||||||||
Info |
Windows: Aprire i file PTH col 4D Client corretto
I file con estensione "PTH" (cioè PaTH, percorso) sono i file che contengono le informazioni di connessione ad un certo server. Se sulla nostra rete esistono più server è possibile creare collegamenti automatici tra un 4D Client e il file PTH da usare con quel client. Per creare l'associazione correttamente: - creare un collegamento al client da usare; - aprire le proprietà del collegamento - aggiungere alla riga "Destinazione" delle virgolette doppie prima e dopo il percorso del 4D client; - alla riga così ottenuta aggiungere uno spazio e poi, sempre tra virgolette, il percorso del file PTH salvato. Il collegamento così creato userà il file PTH impostato. |
||||||||||||||||||||||
Codice |
Un file col contenuto della cartella
Il seguente metodo salva in un file di testo l'elenco dei file contenuti in una cartella. $folder:=Select folder("Scegli la cartella") If (OK=1) ARRAY TEXT($arrelenco;0) DOCUMENT LIST($folder;$arrelenco) $testo:="" SORT ARRAY($arrelenco;>) For ($i;1;Size of array($arrelenco)) $testo:=$testo+$arrelenco{$i}+Char(Carriage return )+Char(Line feed ) C_BLOB($blob) TEXT TO BLOB($testo;$blob;3) BLOB TO DOCUMENT("elenco.txt";$blob) End for End if |
||||||||||||||||||||||
Codice |
Bloccare record multipli di una tabella in un processo
Quando carichi (con il load record o il next record, ad esempio) un record in modalità scrittura, 4d lo blocca automaticamente. Il blocco è di un solo record per tabella in ogni processo. Se vuoi bloccare più record, puoi usare il comando PUSH RECORD. Questo comando mette il record corrente in uno stack, per poi recuperarlo con un successivo POP RECORD: viene usato normalmente per tenere da parte un record mentre si fanno delle altre query sulla stessa tabella. Ma la cosa meno nota è che si possono "pushare" anche più record uno dopo l'altro e restano tutti bloccati in scrittura finché non vengono "poppati". I record vengono ritrovati nella modalità LIFO, l'ultimo inserito è il primo ritrovato. |
||||||||||||||||||||||
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 | |||||||||||||||||||||
Codice |
Effettare una chiamata con Skype da 4D
E' possibile, direttamente da 4th Dimension, effettuare una chiamata con Skype utilizzando molto semplicemente la sintassi: OPEN WEB URL("Skype:Nome_Utente?Call";*) |
||||||||||||||||||||||
Novita' |
4D 2004: Raggruppare i radio button
Nelle precedenti versioni di 4D i radio button all'interno dei form venivano raggruppati in base alla prima lettera del nome della variabile (m_button1, m_button2, m_button3, ecc.). Essendo questo approccio in certi casi insufficiente, dalla versione 2004 è possibile utilizzare il comando Group nel menu Object del form per raggruppare i radio button indipendentemente dal nome. Per ragioni di compatibilità è comunque possibile continuare ad utilizzare il vecchio metodo di raggruppamento selezionando il check box Radio buttons grouped by name nella pagina "Compatibility" della voce "Application" nelle Preferences di 4th Dimension. |
||||||||||||||||||||||
Info |
LAUNCH EXTERNAL PROCESS non esegue i comandi
Usando LAUNCH EXTERNAL PROCESS per eseguire comandi esterni come ad esempio l'apertura di un file attraverso un'altra applicazione, è buona regola inserire i riferimenti ai file (l'applicazione e il file da aprire) tra doppi apici, soprattutto nel caso in cui i nomi degli stessi o delle cartelle contengano degli spazi, poiché altrimenti LAUNCH EXTERNAL PROCESS non troverà i percorsi richiesti. Un esempio potrebbe essere: $mydoc:="C:\\Programmi\\Microsoft Office\\Office11\\WINWORD.EXE \"C:\\Documents and Settings\\Amministratore\\Documenti\\test 2.doc\"" LAUNCH EXTERNAL PROCESS($mydoc;$tIn;$tOut) |
||||||||||||||||||||||
Info |
Sicurezza nelle comunicazioni client - server su WAN
Esiste la possibilità di abilitare la crittografia fra client e server 4d, ma in realtà le prestazioni calano notevolmente. In linea generale le comunicazioni tra client e server 4d non sono facilmente intellegibili: mi spiego con un esempio specifico. Su un classico sql, le query sono stringhe dove compaiono nomi di tabelle e campi, così come la risposta del server sql è sempre espressa in formato testo. Su 4d invece il codice di comunicazione è tokenizzato e suddiviso in piccoli pacchetti per quanto riguarda i comandi (una query può essere spezzata anche in diverse righe di codice non consecutive) e i dati risultanti per quanto riguarda booleani, interi, reali, immagini e blob sono codificati e "affogati" nei singoli pacchetti. Chiaramente il problema potrebbe comunque esserci in funzione dei dati che uno tratta: ad esempio se in un solo campo di testo tengo registrato il numero di carta di credito e il nome del proprietario allora questa informazione diventa intelleggibile (per quanto potrebbe essere spezzata su più pacchetti comunque). Inoltre gli stessi pacchetti del protocollo interno 4d (non documentato pubblicamente) sono molto spezzettati rispetto alla normale comunicazione html; questo spiega il perchè la crittografia fra client e server diventa molto meno efficiente che nella normale navigazione su browser, appunto perché va a codificare-decodificare molti piccoli dati. Le soluzioni più semplici per avere la sicurezza nella comunicazione dei dati su Wan sono: - usare una vpn protetta fra i due router; - dedicare, accanto al server, una macchina come terminal server (microsoft o citryx metaframe) dove aprire i client da remoto. La prima soluzione è molto meno costosa, la seconda è peraltro più efficiente perchè quasi indipendente dai cali di prestazione della rete (le uniche informazioni che passano sono alcuni dati sui pixel del video): l'unica controindicazione però del terminal server potrebbe essere il caso in cui si debba usare qualcosa di meno gestibile tramite questa tecnologia (per capirci, una seriale che controlla un registratore di cassa). |
||||||||||||||||||||||
Info |
Ordinamento dei record selezionati con QUERY WITH ARRAY
Utilizzando il comando QUERY WITH ARRAY, i record popolano la selezione SEMPRE seguendo come ordine il record number. |
||||||||||||||||||||||
Tecniche |
Esempio di scambio array tra Server e Client
All'interno di 4D Client è possibile leggere il contenuto di una variabile (ad esempio un array) appartenente ad un processo residente sul server (stored procedure) utilizzando il comando GET PROCESS VARIABLE. Ecco un esempio di comunicazione: `Method del Client C_LONGINT(spErrCode) ARRAY TEXT(myarr1;0) $spProcessID:=Execute on server("MStoreProc1";128*1024;"Server 1") Repeat DELAY PROCESS(Current process;300) GET PROCESS VARIABLE($spProcessID;spErrCode;spErrCode) If (Undefined(spErrCode)) spErrCode:=1 End if Until (spErrCode<=0) GET PROCESS VARIABLE($spProcessID;myarr1;myarr1) spErrCode:=1 SET PROCESS VARIABLE($spProcessID;spErrCode;spErrCode) `------------------------------------------------------------------------------------------------------------------- `Method: MStoreProc1 `Description: Stored Procedure che ritorna un array. C_LONGINT(spErrCode) ARRAY TEXT(myarr1;0) ` Operazione non conclusa, imposto spErrCode a 1 spErrCode:=1 myarr1:=APPEND TO ARRAY(myarr1;"AAA") myarr1:=APPEND TO ARRAY(myarr1;"BBB") myarr1:=APPEND TO ARRAY(myarr1;"CCC") spErrCode:=0 ` Aspetto che il client prenda i risultati e me lo comunichi Repeat DELAY PROCESS(Current process;1) Until (spErrCode>0) |
||||||||||||||||||||||
Codice |
Svuotare velocemente gli array di testo su Windows
Si possono incontrare problemi di prestazioni di 4D su Windows quando si deve svuotare un array (solitamente per portarne la dimensione a 0). Ad esempio, il seguente metodo verrà eseguito per un tempo NON ragionevole, su una macchina Windows: `===== C_LONGINT($size;$i;$start;$end) $size:=100000 $start:=Milliseconds ARRAY TEXT($text;$size) ARRAY TEXT($text2;$size) For ($i;1;$size) $text{$i}:="blabla"+String($i) $text2{$i}:="blabla"+String($i) End for ARRAY TEXT($text;0) ARRAY TEXT($text2;0) $end:=Milliseconds `===== Però, se svuotiamo il contenuto degli elementi degli array prima di portarne la dimensione a 0, il metodo diventerà VELOCISSIMO: `===== C_LONGINT($size;$i;$start;$end) $size:=100000 $start:=Milliseconds ARRAY TEXT($text;$size) ARRAY TEXT($text2;$size) For ($i;1;$size) $text{$i}:="blabla"+String($i) $text2{$i}:="blabla"+String($i) End for For ($i;1;$size) $text{$i}:="" $text2{$i}:="" End for ARRAY TEXT($text;0) ARRAY TEXT($text2;0) $end:=Milliseconds `===== E ciò semplicemente perché lo svuotamento è nettamente più rapito su array di elementi "vuoti". |
||||||||||||||||||||||
Info |
4D 2004 - Nuove modalità di accesso a comandi e metodi nelle formule
Il Quick Report usa il "Formula Editor" come interfaccia per metodi e comandi. Nelle versioni precedenti era possibile utilizzare qualsiasi comando o metodo nelle formule. Con la versione 2004, con l'obiettivo di rendere più sicuri i dati, è necessario esplicitare quali sono i metodi che è consentitio inserire nelle formule, e i comandi 4D possono essere chiamati solo all'interno di metodi consentiti. Per ammettere un metodo alla lista dei metodi utilizzabili nel formula editor si usa il comando: SET ALLOWED METHODS($myarray) dove myarray è un array di tipo string contenente i nomi dei metodi ammessi. E' consentito usare anche la @ come stringa joly per selezionare più metodi. E' possibile controllare l'elenco degli array consentiti nel formula editor con GET ALLOWED METHODS(setMethodsArray). Se SET ALLOWED METHODS non è stato usato nel processo corrente, GET ALLOWED METHODS ritornerà un array di zero elementi. I database che utilizzavano formule di vecchio tipo con le versioni precedenti dovranno essere aggiornati utilizzando i cambiamenti descritti. |
||||||||||||||||||||||
Tecniche |
Uso combinato della sintassi di SELECTION TO ARRAY
Il comando SELECTION TO ARRAY riceve come parametri di posto dispari (il primo, il terzo, il quinto...) o un campo o una tabella. Queste due sintassi possono essere usate anche contemporaneamente, scrivendo ad esempio: SELECTION TO ARRAY([Clienti];alRecordNumbers;[Clienti]Nome; asNomi) dove alRecordNumbers conterrà i record numbers dei record esportati e asNomi i nomi. Questo sistema è utile se nella tabella da cui vengono estratti i dati non esiste un campo che sia chiave primaria per la tabella, o comunque se si vuole, ad esempio, accedere in un secondo tempo al record corrispondente utilizzando GOTO RECORD. Per le nozioni sulle chiavi vedere questa faq. Per la sintazzi di SELECTION TO ARRAY questa faq. |
||||||||||||||||||||||
Novita' |
4D 2004: Deselezionare le righe di un subform
Se serve deselezionare le righe di un subform si possono utilizzare queste due possibilità: - creare un set vuoto e utilizzare HIGHLIGHT RECORDS col set creato se il tipo di selezione del subform è "Multiple"; - usare GOTO SELECTED RECORD([Nome_Tabella_Subform];0) se il tipo di selezione del subform è "Single". |
||||||||||||||||||||||
Novita' |
4D 2004: Selezionare le righe di un subform
Con la versione 2004 di 4D è possibile controllare le righe da selezionare all'interno di un subform. Ciò è possibile grazie alle nuove funzionalità del comando HIGHLIGHT RECORDS: tale comando fin dalla versione 6.5, permetteva di selezionare i record di un set; adesso è in più possibile specificare la tabella da considerare e se abilitare o meno lo scroll automatico. La sintassi è dunque: HIGHLIGHT RECORDS ({table}{; setName{; *}}) Tutto questo vale se nel suform è abilitata l'opzione di selezione è multipla: se la selezione è singola si deve usare invece GOTO SELECTED RECORD. |
||||||||||||||||||||||
Info |
I tasti con azioni automatiche e i metodi relativi
Ai pulsanti dei form è possibile associare un metodo o un'azione automatica fra quelle definite da 4D. Nel caso al pulsante vengano associati sia un metodo che un'azione automatica, verrà eseguito prima il metodo e solo dopo l'azione automatica; una possibilità comunque da tenere in considerazione in questo caso è quella di inserire il comando automatico direttamente nel metodo: ad esempio, se devo fare un Delete subrecord (nome dell'azione automatica che cancella i record selezionati in un form di output), ma prima (o anche dopo) devo eseguire del codice (ad esempio vedere se le schede sono bloccate da altri processi), si può togliere l'azione automatica dal pulsante "Cestino", e scrivere il metodo in modo che contenga, nel posto che serve, il controllo del LockedSet, l'uso dei record "highlighted" e il DELETE SELECTION. |
||||||||||||||||||||||
Codice |
Tutti i valori di un XML
Il seguente codice riempie in maniera ricorsiva l'array attribute2DArr con tutti gli attributi e i valori presenti in un file XML. Volendo fare il parse di un XML risulta molto utile. Il metodo riceve come parametro il riferimento ottenuto tramite il comando DOM Parse XML source e la dichiarazione dell'array ARRAY TEXT(attribute2DArr;0;0) deve essere fatta al di fuori del metodo. C_TEXT($elementName;$elementValue) C_TEXT($attributeName;$attributeValue) $elementRef:=$1 `prendi le info sull'elemento ------------------------ DOM GET XML ELEMENT NAME($elementRef;$elementName) DOM GET XML ELEMENT VALUE($elementRef;$elementValue) $elementID:=0 `prendi le info sull'attributo---------------------- $numAttributes:=DOM Count XML attributes($1) If ($numAttributes#0) `lo metto nell'array $sizeOfArray:=Size of array(attribute2DArr)+1 INSERT ELEMENT(attribute2DArr;$sizeOfArray) For ($i;1;$numAttributes) DOM GET XML ATTRIBUTE BY INDEX($1;$i;$attributeName;$attributeValue) attributeTxt:=$attributeName+": "+$attributeValue APPEND TO ARRAY(attribute2DArr{$sizeOfArray};attributeTxt) End for End if `percorro l'albero ricorsivamente------------------- $elementRef:=DOM Get first child XML element($elementRef) If (OK=1) `esiste un figlio While (OK=1) Get_xmlParseTree ($elementRef) $elementRef:=DOM Get Next sibling XML element($elementRef) End while End if |
||||||||||||||||||||||
Codice |
Un esempio per Application type
A Supponiamo di voler distinguere ottenere la data corrente dal server (se siamo in modalità client/server) o dal computer locale. il codice da eseguire sarà: C_DATE($0) C_DATE($currentDate) If (Application type=4D Client ) $currentDate:=Current date(*) Else `se siamo sul server o in monoutenza $currentDate:=Current date End if $0:=$currentDate |
||||||||||||||||||||||
Info |
Crash di 4D: come usare il log col backup su db danneggiati
Nel caso una base dati diventi inutilizzabile, col file log è possibile riportare una base dati alla situazione attuale in maniera "funzionante". Vediamo come fare. - Intanto per sicurezza fare una copia della cartella contenente il programma (ad esempio, se il programma ha un link sul desktop/scrivania, basta fare tasto di destra sul collegamento, Proprietà, Trova destinazione / su Finder Archivio, Trova originale). - Aprire 4D/4D Server e scegliere "Restore database"; utilizzare il backup più recente; i dati del backup verranno salvati in una cartella. - Aprire il database in questa cartella. 4D chiederà di scegliere un file log. Scegliere il file log (.4DL) presente nella cartella originale del programma (o nella copia che avevamo fatto all'inizio). - I dati del log verranno così integrati alla base dati. Chiudere 4D - Sostituire i file dati (4DD e 4DR o .data) della cartella originale del programma con i dati presenti nella cartella di backup e il gioco è fatto. |
||||||||||||||||||||||
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. |
||||||||||||||||||||||
Codice |
4d e PHP: un esempio concreto
Con questo articolo voglio estendere quando gia' descritto nell'articolo di Serena Zanfini sull'integrazione di 4D ed il linguaggio PHP (il link dell'articolo e' http://www.sviluppo4d.it/4DCGI/Detail_FAQ_Display?ID=190 ). Tipicamente, in molti progetti di siti web, si utilizzano pagine dinamiche PHP per interfacciarsi ad un database SQL, tipicamente MySQL (basti pensare ai numerosi pacchetti di installazione di Apache+PHP+MySQL che ci sono in rete: xampp, easyphp, ...). Tipicamente il linguaggio PHP fornisce i costrutti per interfacciarsi a questi database, ma questo non accade per 4D. E non esiste neache una soluzione del tipo "4D Open for PHP". E possibile pero' accedere ai dati di 4D pubblicando alcune procedure come Web Services, tramite SOAP (Simple Object Access Protocol, i dettagli li trovate all'indirizzo www.w3.org/TR/soap/). Ovviamente non e' necessario che WebServer e 4D siano installati sulla stessa macchina, descrivero' in seguito tale dettaglio. Innanzitutto dovete avere una macchina con Apache e PHP installati: se siete in ambiente Mac OS X potete usare anche l'installazione fornita con il sistema altrimenti potete utilizzare i pacchetti forniti da Server Logistics (http://www.serverlogistics.com/) che sono semplicissimi da installare. Se invece il vostro WebServer deve essere installato in ambiente Windows, potete usare Xampp (http://www.apachefriends.org/en/xampp.html) o EasyPHP (http://easyphp.org). A questo punto potete procedere alla configurazione del database 4D. Quello che vi serve e' innanzitutto la licenza Web di 4D oppure la licenza per il solo modulo Web Services. Per quanto riguarda la configurazione del Web Server, vi consiglio di impostare il numero della porta attraverso la finestra delle Preferenze. Personalmente ho impostato tale porta al numero 5200. Mettete anche la spunta su "Publish Database as Startup", in modo da non dover avviare il Web Server tutte le volte a mano. Per quanto riguarda i Web Services, mettete la spunta su "Allow Web Services Requests". Per creare un nuovo Web Service e' sufficiente creare un nuovo metodo, sia esso wsTest. Per questo metodo vanno impostate le proprieta' "Offered as a Web Service" e "Published in WDSL". Ora possiamo scrivere un normale metodo che accetta argomenti e restituisce un valore, poi va' inserito del codice opportuno in modo che tali parametri siano accettati. Sia wsTest il nodi di questo metodo. Prima di descrivere quali modifiche fare al metodo rispetto alla forma standard, descriviamo il codice PHP per interagire con tale metodo o Web Service. E' necessaria un libreria PHP che si chiama NuSOAP, liberamente scaricabile dal sito web http://dietrich.ganx4.com/nusoap/ dove e' disponibile anche la documentazione. Il file della libreria, nusoap.php, va incluso nel codice della pagina PHP che fa' la chiamata al server 4D. Personalmente ho copiato questo file all'indirizzo /include del Web Server, in modo da non aver problemi con i percorsi per l'inclusione: infatti per includere la libreria utilizzo il comando: require_once($_SERVER['DOCUMENT_ROOT'].'/include/nusoap.php'); Inoltre, come avevo accennato in precedenza, per essere indipendenti dall'host dove risiede il server 4D, ho definito un file INI, che ho chiamato config.ini cosi' strutturato: [Principale] 4DServerIP = 192.168.10.5 4DServerPort = 5200 WebServerIP = 192.168.10.5 Questi parametri vengono letti tramite la funzione parse_ini_file di PHP, che trasforma questo file in un array associativo. Siamo ora in grado di comprendere il seguente codice PHP: $config = parse_ini_file("config/config.ini"); // faccio la chiamata al server 4D per avere il controllo dell'username // e della password require_once($_SERVER['DOCUMENT_ROOT'].'/include/nusoap.php'); $sc = "http://".$config['4DServerIP'].":"; $sc.=$config['4DServerPort']."/4DSOAP"; $soapclient = new soapclient($sc); $parameters = array('username'=>'mionome', 'password'=>'miapassword'); $ret = $soapclient->call('wsTest',$parameters); unset($soapclient); If (!$ret) { print "Errore SOAP:" . $soapclient->getError() . '\n '; exit; } Else { print "Funziona!"; } Come e' evidente in questa piccola porzione di codice, e' stato definito una array associativo i cui campi sono 'username' e 'password', la chiamata e' effettuata tramite la call. Il fatto che il PHP sia flessibile con i tipi ci avvantaggia un po' per quanto riguarda la variabile del risultato, l'unica cosa che dobbiamo controllare e' che non ci sia stato un errore nella chiamata del Web Service. Il metodo wsTest che viene eseguito e' il seguente: ` `Autenticazione ` `Parametri: `$0 TEXT- risultato `$1 TEXT- username `$2 TEXT- password C_TEXT($0) C_TEXT($1) C_TEXT($2) SOAP DECLARATION($0;Is Text ;SOAP Output ) SOAP DECLARATION($1;Is Text ;SOAP Input ;"username") SOAP DECLARATION($2;Is Text ;SOAP Input ;"password") ALL RECORDS([Utenti]) QUERY([Utenti];[Utenti]UserID=$1) If (Records in selection([Utenti]) # 1) $0:="Utente o password errata." Else FIRST RECORD([Utenti]) If ([Utenti]Password = $2) $0:="Ok" Else $0:="Utente o password errata." End if End if E' facile notare che la dichiarazione dei tipi dei parametri precede quella della dichiarazione SOAP, in modo da poter usare questa funzione non necessariamente attraverso una chiamata SOAP. I tipi di dato della dichiarazione SOAP possibili sono (il testo che va' inserito nella dichiarazione): Is BLOB Is Boolean Is Integer Is LongInt Is Real Boolean array String array Date array Integer array LongInt array Real array Text array Is Text Is Date Is Time Is String Var L'ultimo campo della dichiarazione SOAP deve essere il nome della variabile nell'array associativo definito in PHP. Se decidiamo di ottenere piu' di una variabile in uscita, nel codice PHP bastera' aggiungere varie dichiarazioni di SOAP Output, ed il risultato in PHP sara' un array associativo (che prende i nomi delle variabili cosi' come definiti in 4D). Un ultima nota di questo articolo va' fatta per quanto riguarda il timeout della chiamata SOAP. Infatti, se utilizzate il debug per testare il vostro codice, puo' darsi che durante l'esecuzione passo passo del codice 4D vada in timeout la chiamata SOAP (tipicamente dopo 60 sencodi, ma non sono sicuro). E' possibile pero' impostare questo tempo di timeout, in modo da provare il nostro codice "in tranquillita'", tramite il comando 4D: SET WEB SERVICE OPTION(Web Service HTTP Timeout;120) Vi consiglio di inserire questo codice all'avvio dell'applicazione 4D e rimuoverlo poi prima della compilazione. |
||||||||||||||||||||||
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 | |||||||||||||||||||||
Plugin |
Modificare le opzioni di default di QPix
La funzione QPx_SetOption del plugin QPix di Escape permette di modificare alcune della impostazioni di default del plugin. La sintassi è: QPx_SetOption(optionName; numericValue; textValue) dove - optionName è il nome dell'opzione; - numericValue è il nuovo valore da assegnare all'opzione (se numerico); - textValue è il nuovo valore da assegnare all'opzione (se testuale). Ad esempio "/pdf/gen/thumb-width" e "/pdf/gen/thumb-height" permettono di stabilire la dimensione dell'anteprima del file PDF generato da QPx_CreatePDFFile o QPx_CreatePDFBLOB; oppure "/export/exif-thumb-width" e "/export/exif-thumb-height" controllano la dimensione dell'anteprima generata da QPx_ExportImageFile, QPx_ExportImageFileToBLOB, QPx_ExportPicture, QPx_ExportPictureToBLOB, QPx_ExportAreaImage, QPx_ExportImporterImage, o QPx_ExportImporterImageToBLOB. |
||||||||||||||||||||||
Plugin |
Creare un PDF da un'immagine
Nel plugin QPix di Escape è presente, tra le altre, una funzione che permette di ottenere un file PDF a partire da un'immagine. La funzione è QPx_CreatePDFFile(pdfFilePath; sourceImages; optionFlags) dove - pdfFilePath è il percorso al file PDF; - sourceImages è un array di tipo testo contenente, in ogni elemento, il percorso ad uno dei file da inserire nel PDF; - optionFlags è dato dalla combinazione dei parametri qpx_PDFShowProgress (mostra una progressi dialog, valore esadecimale 0x0001), qpx_PDFInsertAllPages (inserisce nel PDF tutte le pagine, 0x0002) e qpx_PDFCreateThumbnails (genera una miniatura della pagina della dimensione massima di 256x256 come default, ma il valore è modificabile cambiando le impostazioni del plugin con QPx_SetOption). |
||||||||||||||||||||||
Codice |
Eseguire una query con i comandi External Data Source
Ecco un esempio con i comandi necessari ad eeseguire una query via ODBC utilizzando i comandi integrati in 4D 2004. $testoquery:="SELECT ....... FROM ....... WHERE ........" ODBC LOGIN("DatabaseAccess";"";"") ODBC EXECUTE($testoquery;array1;array2;......) ODBC LOAD RECORD(ODBC All Records ) ODBC LOGOUT |
||||||||||||||||||||||
Plugin |
Eseguire una query con 4D ODBC Pro 2004
Ecco un esempio contenente i comandi necessari per eseguire una query su un database utilizzando il plugin OBDC Pro. Si noti che arArrays è un array di puntatori agli array che dovranno ricevere i risultati e $result può gestire i vari errori che il plugin potrebbe ritornare. C_REAL(connection_ID) $result:=ODBC_SQLAllocConnect (connection_ID) valuePtr:=SQL_MODE_READ_ONLY $result:=ODBC_SQLSetConnectAttr (connection_ID;SQL_ATTR_ACCESS_MODE ;->valuePtr) $result:=ODBC_SQLConnect (connection_ID;"DatabaseAccess";"";"") $testoquery:="SELECT...... FROM ...... WHERE ......" $result:=ODBC_SQLAllocStmt (connection_ID;$statementID) $result:=ODBC_SQLPrepare ($statementID;$testoquery) $result:=ODBC_SQLExecute ($statementID) For ($i;1;Size of array(arArrays)) $result:=(ODBC_SQLBindCol ($statementID;$i;arArrays{$i})) End for While ($result#SQL_NO_DATA) $result:=ODBC_SQLFetch ($statementID) End while $result:=0 $result:=(ODBC_SQLFreeStmt ($statementID;SQL_CLOSE )) $result:=(ODBC_SQLFreeStmt ($statementID;SQL_UNBIND )) $result:=(ODBC_SQLFreeStmt ($statementID;SQL_RESET_PARAMS )) $result:=ODBC_SQLDisconnect (connection_ID) |
||||||||||||||||||||||
Info |
4D 2004: posizione dei plugin
Le cartelle Win4dx e Mac4dx nella versione 2004 continuano ad essere utilizzate per compatibilità, ma con la nuova versione la cartella che contiene i plugin è diventata unica e si chiama, guarda caso, "PlugIns". Questa cartella può essere posizionata: - al livello del file struttura: in questo caso i plugin installati saranno disponibili solo per quel database - al livello dell'applicazione: in tal caso i plugin installati saranno disponibili per tutte le strutture. |
||||||||||||||||||||||
Info |
Conoscere il nome di un 4D Server usando TELNET
Conoscendo IP del server e la porta di esecuzione, è possibile usare Telnet per conoscere il nome del database 4D in esecuzione. Ricevendo un telnet, infatti, 4D Server risponde con il nome del database in esecuzione. |
||||||||||||||||||||||
Plugin |
Il primo grafico con 4D Chart
Creare un grafico a partire da alcuni dati è davvero agevole. Basta prendere la selezione desiderata, un campo per la "x" vettoriale, un campo per la y, un campo per i valori e utilizzare il comando CT Chart data. Vediamo un esempio: ALL RECORDS([Table1]) tableNum:=Table(->[Table1]) categoryField:=Field(->[Table1]Field1) seriesField:=Field(->[Table1]Field2) valuesField:=Field(->[Table1]Field3) vChart:=Open external window(50;50;650;600;8;"Grafico Profitti";"_4D Chart") CT SET DOCUMENT SIZE (vChart;586;766) $err:=CT Chart data (vChart;2;1;0;0;tableNum;categoryField;seriesField;valuesField) Il comando CT SET DOCUMENT SIZE è necessario per fare sì che, in caso di stampa del documento, il grafico venga stampato su una sola pagina. Per i comandi di stampa con 4D Chart vi rimandiamo a questa faq. |
||||||||||||||||||||||
Info |
Interrompere una ricerca
La ricerca "Find in database" permette di effettuare ricerche di stringhe anche in tutto il database (Form, Tabelle, methods, ecc.). Su grandi database o con connessioni di rete lente (tipo wi-fi) la ricerca può essere assai lunga e durare più di quanto previsto. Se ciò succede, la ricerca può essere interrotta molto semplicemente premendo il tasto ESC. |
||||||||||||||||||||||
Tecniche |
Importare dati da Excel a 4D
I dati presenti in un foglio di calcolo di Excel possono essere importati in 4th Dimension in vari modi. Il più immediato è quello esportare i dati in uno dei formati che 4D può importare in maniera automatica: i file CSV, TXT, SYLK, e DIFF. I dati, ad esempio, possono essere salvati in formato testo delimitato da tabulazione. Per fare ciò, scegliere "File" "Salva con nome..." e scegliere come tipo di file "Testo delimitato da tabulazione", e quindi eseguire l'esportazione. Per importare i dati, in modalità "User" scegliere "File / Import / From File...". Altre possibilità per eseguire l'importazione sono aprire uno stream DDE oppure via ODBC. |
||||||||||||||||||||||
Codice |
Trovare errori nei TAG html [2]
` ====================================== ` CHECK HTML TAGS di Roberto Vergani (05-2006) ` ====================================== C_TEXT($info;$sourceText;$resultText;$tag) C_INTEGER($X;$J;$k;$n;$size;$vLineNumber;$startLine;$offset) C_STRING(2;$char) C_BOOLEAN($notFound) ARRAY TEXT($vtErrorText;0) $size:=Test clipboard("TEXT") Case of : ($size<=0) ALERT("Gli appunti non contengono testo, elaborazione interrotta.") : ($size>31000) ALERT("Il contenuto degli appunti supera i 31K, elaborazione interrotta.") Else $info:="Questa procedura controlla la parità dei tags HTML"+Char(13) $info:=$info+"Procedi dopo avere copiato in appunti il codice sorgente." CONFIRM($info;"Procedi";"Annulla") If (OK=1) ` ECCEZIONI: questi TAG usualmente non hanno chiusura, SONO IGNORATI ` aggiungi o togli quello che vuoi, inserisci senza i delimitatori < > ` tutti i tags che iniziano con ARRAY TEXT($vtExceptions;13) $vtExceptions{1}:="img" $vtExceptions{2}:="br" $vtExceptions{3}:="br/" $vtExceptions{4}:="input" $vtExceptions{5}:="link" $vtExceptions{6}:="meta" $vtExceptions{7}:="?xml" $vtExceptions{8}:="area" $vtExceptions{9}:="param" $vtExceptions{10}:="base" $vtExceptions{11}:="hr" $vtExceptions{12}:="frame" $vtExceptions{13}:="spacer" ARRAY TEXT($vtRighe;0) $SourceText:=Get text from clipboard If (OK=0) ALERT("Si è verificato un errore nel leggere gli appunti (procedura interrotta).") Else SET CURSOR(4) ARRAY TEXT($vtTags;0) ARRAY INTEGER($vtCount;0) ARRAY INTEGER($vtLine;0;0) ARRAY INTEGER($vtPosition;0;0) $vLineNumber:=1 $startLine:=1 $X:=1 If ($size>3000) Open window((Screen width-300)/2;(Screen height-150)/2;((Screen width-300)/2)+300;((Screen height-150)/2)+150;1) End if Repeat $char:=($SourceText?$X?) GOTO XY(10;6) MESSAGE("Parsing: "+String($X)+" / "+String($size)+" bytes") Case of : ($char=Char(13)) $vLineNumber:=$vLineNumber+1 $X:=$X+1 $startLine:=$X : ($char="<") & (($SourceText?$X+Num($X<($size+1))?)#"!") ` ignora tutti i tag che iniziano con $offset:=1 Repeat $offset:=$offset+1 Until (($SourceText?$X+$offset?=">") | ($SourceText?$X+$offset?=Char(32)) | ($SourceText?$X+$offset?=Char(13))) $tag:=Substring($SourceText;$X+1;$offset-1) $n:=Find in array($vtExceptions;$tag) If ($n=-1) ` se il tag non è un'eccezione da ignorare If (Ascii($tag)=47) ` se il tag inizia con ascii 47 = / $notFound:=False $tag:=Substring($tag;2) $n:=Find in array($vtTags;$tag) If ($n=-1) ` è chiuso un tag che compare per la prima volta e non è presente nell'elenco dei tag esistenti $notFound:=True Else If (Size of array($vtLine{$n})=0) $notFound:=True Else DELETE ELEMENT($vtLine{$n};Size of array($vtLine{$n})) DELETE ELEMENT($vtPosition{$n};Size of array($vtPosition{$n})) End if End if If ($notFound=True) INSERT ELEMENT($vtErrorText;Size of array($vtErrorText)+1) $vtErrorText{Size of array($vtErrorText)}:=""+$tag+"> tag chiuso senza apertura, linea "+String($vLineNumber)+" posizione "+String($X-$startLine+1) End if Else $n:=Find in array($vtTags;$tag) If ($n=-1) $n:=Size of array($vtTags)+1 INSERT ELEMENT($vtTags;$n) INSERT ELEMENT($vtCount;$n) INSERT ELEMENT($vtLine;$n) INSERT ELEMENT($vtPosition;$n) End if $J:=Size of array($vtLine{$n})+1 INSERT ELEMENT($vtLine{$n};$J) INSERT ELEMENT($vtPosition{$n};$J) $vtTags{$n}:=$tag $vtCount{$n}:=$vtCount{$n}+1 $vtLine{$n}{$J}:=$vLineNumber $vtPosition{$n}{$J}:=$X-$startLine+1 End if End if $X:=$X+$offset-1 Else $X:=$X+1 End case Until ($X>Length($SourceText)) If ($size>8000) CLOSE WINDOW End if $resultText:="CHECK HTML TAGS di Roberto Vergani (05-2006)"+(Char(13)*3) $n:=Size of array($vtErrorText) $k:=0 For ($X;1;Size of array($vtLine)) $k:=$k+Size of array($vtLine{$X}) End for If ($n>0) | ($k>0) $resultText:=$resultText+"### SONO STATI RILEVATI ERRORI :"+(Char(13)*2) For ($X;1;Size of array($vtLine)) If (Size of array($vtLine{$X})>0) For ($J;1;Size of array($vtLine{$X})) $resultText:=$resultText+"<"+$vtTags{$X}+"> tag aperto e non chiuso, linea "+String($vtLine{$X}{$J})+" posizione "+String($vtPosition{$X}{$J})+Char(13) End for End if End for $resultText:=$resultText+Char(13) For ($X;1;$n) $resultText:=$resultText+$vtErrorText{$X}+Char(13) End for $info:="### RILEVATI ERRORI."+Char(13) Else $resultText:=$resultText+"Il codice esaminato sembra essere OK." $info:="Nessun errore."+Char(13) End if $resultText:=$resultText+(Char(13)*3) $resultText:=$resultText+"Sono stati esaminati:"+(Char(13)*2) For ($X;1;Size of array($vtTags)) $value:=String($vtCount{$X}) ` riutilizzo di variabile $resultText:=$resultText+(" "*(5-Length($value)))+$value+" tag <"+$vtTags{$X}+">"+Char(13) End for SET TEXT TO CLIPBOARD($resultText) SET CURSOR(0) ALERT($info+"L'esito dell'elaborazione è contenuto negli appunti, incolla dove vuoi.") End if End if End case |
||||||||||||||||||||||
Codice |
Trovare errori nei TAG html [1]
Chi costruisce pagine html da utilizzare in modalità non contestuale utilizzando dati e variabili in modo dinamico, in genere deve costruire blocchi di codice html che costituiscono la pagina con i dati, per esempio un blocco di intestazione, un blocco contenuto in un loop e ripetuto per ogni record, eventuali break, un blocco di fine pagina. E’ praticamente sempre necessario costruire tabelle ed avviene spesso di commettere errori nella parità dei TAG, dove per parità intendo che ad ogni TAG di apertura corrisponda il relativo TAG di chiusura: Recentemente mi è avvenuto di lavorare su pagine molto complesse e, spostando blocchi di codice dentro e fuori dai loop, ad un certo punto avevo errori di visualizzazione o negli allineamenti e non riuscivo più a controllare se tutti i TAG fossero a posto. Ho cercato ma non ho trovato un applicativo semplice che controllasse il codice. Allora l’ho scritto. E’ un method che non usa form e che si può inserire in qualunque struttura. Esamina il codice presente negli appunti ed ha quindi il limite di 32K di lunghezza del sorgente ma è più che sufficiente per l’esigenza di controllare codice in 4D. L’uso è immediato: copiare il codice da esaminare e lanciare il method dall’ambiente user, a fine elaborazione viene prodotto un report che è collocato sempre negli appunti: incollare dove possa essere letto ed eventualmente stampato. Naturalmente questo method considera tutte le stringhe che iniziano con il carattere “<“ e il report potrebbe riportare presunti errori che invece non sono tali: basta ignorarli. Questo method non è un semplice contatore che somma aperture e chiusure ma lavora rispettando la nidifcazione dei TAG. Il report elenca gli errori riportando i riferimenti di riga e posizione in cui sono stati trovati. Prevede anche delle eccezioni, TAG che non hanno chiusura e che vengono ignorati; l’elenco delle eccezioni è facilmente modificabile. Può essere usato anche quando il codice html è contenuto in istruzioni 4D, esempio: addToBody ("<table border=0 cellpadding=0 cellspacing=0 bgcolor="+Char(34)+myVar+Char(34)+">") addToBody ("<tr>") addToBody ("<td height=12 width=8 valign=top><img src="+Char(34)+""+Char(34)+" border=0 width=1 height=1 alt="+Char(34)+""+Char(34)+"></td>") addToBody ("<td width=582 valign=top>") addToBody ("<p><font size=-1><span class="+Char(34)+"style108"+Char(34)+"><font color="+ myVar+"</font></span></font></p></td>") addToBody ("<td width=10 valign=top><img src="+Char(34)+""+Char(34)+" border=0 width=1 height=1 alt="+Char(34)+""+Char(34)+"></td>") addToBody ("</tr>") addToBody ("</table>") Nel caso di codice 4D non ricompone i tag eventualmente tagliati dalle virgolette per il limite della lunghezza delle stringhe. Mi sono divertito ad esaminare parecchie pagine scaricate qua e la per la rete ed è curioso notare quante contengano errori, errori che i browser attuali sono abbastanza intelligenti da perdonare e che quindi risultano non visibili. |
||||||||||||||||||||||
Codice |
Messenger, AIM o ICQ fra client 4D con poco codice
In modalità client/server è possibile realizzare un sistema di messaggistica istantanea (tipo Messenger, AIM, ICQ) utilizzando pochissime righe di codice. Vediamo come. Il seguente metodo, Registration, permette di registrare il client in modo da renderlo pronto a ricevere messaggi da altri 4D Client. `-------------------- UNREGISTER CLIENT Repeat vPseudoName:=Request("Enter your name:";"User";"OK";"Cancel") Until ((OK=0) | (vPseudoName # "")) If (OK=0) ...` Non fa niente Else REGISTER CLIENT(vPseudoName) End if `-------------------- L'istruzione che segue mette in moto il processo che consente di ottenere la lista aggiornata dei client collegati. Una buona idea potrebbe essere quella di inserirla nel On Startup Database Method: PrClientList:=New process("4D Client List";64000;"Lista dei registered clients") Il metodo 4D Client List permette di ottenere la lista dei client registrati: `-------------------- If (Application type=4D Client) ` il codice che segue è valido solo in modalità client/server $Ref:=Open window(100;100;300;400;-(Palette window+Has window title);"Lista dei client registrati") Repeat GET REGISTERED CLIENTS($ClientList;$ListeCharge) `Lista dei client in $ClientList ERASE WINDOW($Ref) GOTO XY(0;0) For ($p;1;Size of array($ClientList)) MESSAGE($ClientList{$p}+Char(Carriage return)) End for `lo mostra qualche secondo DELAY PROCESS(Current process;60) Until (False) ` loop infinito End if `-------------------- Il seguente metodo manda un messaggio a un altro 4D Client usando il metodo Display_Message `-------------------- $Addressee:=Request("Destinatario del messaggio:";"") ` Inserire uno dei nomi visualizzati dalla finestra aperta in ` On Startup database method If (OK # 0) $Message:=Request("Messaggio:") ` il messaggio If (OK # 0) EXECUTE ON CLIENT($Addressee;"Display_Message";$Message) ` manda il messaggio End if End if `-------------------- Ecco il metodo Display_Message `-------------------- C_TEXT($1) ALERT($1) `-------------------- Infine, il metodo che permetta ad un client di non essere più visibile fra i client collegati in modo da non poter ricevere messaggi dovrà contenere la sola istruzione: UNREGISTER CLIENT |
||||||||||||||||||||||
Info |
Differenze fra SET PROCESS VARIABLE e VARIABLE TO VARIABLE
4D fornisce due comandi per far impostare il valore di una variabile in un processo diverso: SET PROCESS VARIABLE e VARIABLE TO VARIABLE. I due comandi, benché simili, presentano due sostanziali differenze: - SET PROCESS VARIABLE permette di passare alla variabile di destinazione anche una espressione, invece di una variabile. - SET PROCESS VARIABLE non permette di far passare fra i processi un array intero, ma solo elementi di array. Per far passare fra processi degli array bisogna usare VARIABLE TO VARIABLE (tranne array di puntatori e array bidimensionali, che non possono essere passati). Entrambi i comandi non accettano inoltre: - variabili locali come destinazione; - elementi di array di puntatori; - elementi di array bidimensionali. |
||||||||||||||||||||||
Codice |
Liberare la memoria dopo aver usato un XML
In linea generale, tutte le volte che si usa un XML bisogna pulirlo alla fine, perchè l'occupazione in memoria non è della sola variabile longint Riferimento, ma di una struttura ben più grande a cui questa punta. Quindi, la sequenza è: 1) Riferimento:=DOM Create XML Ref("XYZ")`qui lo crei 2..n) ... qui costruisci l'xml n+1) DOM EXPORT TO VAR(Riferimento;blob) `qui lo usi, esporti, etc n+2) DOM CLOSE XML (Riferimento) `<-----AGGIUNGI QUESTO !!!! |
||||||||||||||||||||||
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 | |||||||||||||||||||||
Plugin |
Una procedura per ordinare con 4D Open for Java
4D Open for Java è un insieme di comandi che permette di interrogare un 4D Server via Java: Linux, Unix, Windows, Mac, ecc. sono tutti sistemi che possono dunque interagire con un server 4D. Ecco, ad esempio, una procedura per effettuare un ordinamento: opSelection selection = process.AllRecords(table); selection.mTableNumber = 1; opFieldArray fieldArray = new opFieldArray(1); fieldArray.mTargetTable = 1; fieldArray.mFieldArray[0] = new opField(1,1); fieldArray.mFieldArray[0].mFieldNumber=1; fieldArray.mFieldArray[0].mOrdering=GREATER_THAN; // (*)Ascending order fieldArray.mFieldArray[0].mFieldType=1; process.OrderBy(fieldArray); process.RecordsInSelection(selection); int found = selection.mRecordsInSelection; opDataArray dataArray[] = new opDataArray[1]; dataArray[0] = new opDataArray(found); process.SelectionToArray(dataArray,fieldArray); for(short i=0;i{ System.out.println(dataArray[0].mDataArray[i].mString); } |
||||||||||||||||||||||
Codice |
Calcolo del giorno di Pasqua
Da un recente "daily tip" di 4DToday, segnaliamo il codice che permette di ottenere la data del giorno di Pasqua per un certo anno, che è il parametro da passare al metodo: C_INTEGER($1;$G;$I;$C;$H;$I;$J;$L;$M;$D) C_STRING(6;$0) $G:=(($1%19)+1)-1 $I:=((19*$G)+15)%30 $C:=($1\100) $H:=($C-($C\4)-(((8*$C)+13)\25)+(19*$G)+15)%30 $I:=$H-(($H\28)*(1-((29\($H+1))*((21-$G)\11)))) $J:=($1+($1\4)+$I+2-$C+($C\4))%7 $L:=$I-$J $M:=3+(($L+40)\44) $D:=$L+28-(31*($M\4)) $0:=String($D;"00")+"/"+String($M;"00")+"/"+String($1) Fonte: 4DToday Inviato da Paul Mohammadi |
||||||||||||||||||||||
Info |
Tutte le faq su 4D, Access e FileMaker Pro
Ecco un indice per consultare le faq di confronto su Access, FileMaker Pro e 4th Dimension 4th Dimension, MS Access e FileMaker Pro [1] NOMENCLATURA 4th Dimension, MS Access e FileMaker Pro [2] Creazione della struttura 4th Dimension, MS Access e FileMaker Pro [3] I form * 4th Dimension, MS Access e FileMaker Pro [4] La sicurezza * 4th Dimension, MS Access e FileMaker Pro [5] Inserimento nei campi ** 4th Dimension, MS Access e FileMaker Pro [6] I report 4th Dimension, MS Access e FileMaker Pro [7] L'automazione 4th Dimension, MS Access e FileMaker Pro [8] Gli eventi 4th Dimension, MS Access e FileMaker Pro [9] Le variabili 4th Dimension, MS Access e FileMaker Pro [10] Programmare una multiutenza 4th Dimension, MS Access e FileMaker Pro [11] Mantenimento di un db multiutente 4th Dimension, MS Access e FileMaker Pro [12] Gestione delle transazioni 4th Dimension, MS Access e FileMaker Pro [13] Le ricerche 4th Dimension, MS Access e FileMaker Pro [14] I sistemi operativi 4th Dimension, MS Access e FileMaker Pro [15] Criteri di scelta |
||||||||||||||||||||||
Tecniche |
Usare 4D da remoto: alcune alternative
La possibilità di avere connessioni internet sempre attive a costi bassissimi e la necessità delle aziende di "dislocarsi" sul territorio mantenendo un unico software centrale per tutte le sedi porta spesso alla problematica: come uso 4D attraverso internet? Vediamo alcune possibilità. Una soluzione potrebbe essere utilizzare il software attraverso interfaccia web: questo richiede l'acquisto della licenza web e consente di utilizzare il software con qualsiasi sistema operativo. Se il server ha un indirizzo ip pubblico e' possibile usare direttamente 4D Client per connettersi a 4D Server. La "controindicazione" in tal caso è la quantità di traffico generata, che potrebbe essere notevole. Per "minimizzare" il traffico si potrebbe optare per dei servizi di tipo "terminal": l'onere del lancio del client viene demandato al server terminal, e il traffico internet generato diventa solo quello necessario alla visualizzazione dello schermo. |
||||||||||||||||||||||
Plugin |
Cambiare il colore di un grafico: CT SET CHART FILL ATTRIBUTES
Quando si genera un grafico con 4D Chart, il plugin si occupa autonomamente di assegnare i colori alle varie serie. Se si desidera personalizzare il colore delle serie, si utilizza il comando CT SET CHART FILL ATTRIBUTES (area; object; partType; partSpecifics; pattern; color). Il comando prende come parametri l'ID dell'area, l'ID dell'oggetto, il tipo di oggetto, la parte specifica dell'oggetto (questi ultimi due parametri sono espressi da costanti specifiche di 4D Chart), il pattern (da 1 a 36, -1 per non variarlo) e il colore (anche qui -1 per non cambiarlo). Ad esempio, per far diventare verde "solido" il colore della prima serie del grafico $Chart nell'area Area, scriveremo: $Color:=CT Index to color (10) CT SET CHART FILL ATTRIBUTES (Area;$Chart;8;100;3;$Color) |
||||||||||||||||||||||
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 | |||||||||||||||||||||
File |
Cambia stato Visibile/Invisibile di un documento
Questa struttura è un esercizio di uso della ricorsione e di come utilizzare un solo Record ma con un gran numero di subrecord, per poter utilizzare il Runtime License Light, cioè l'engine Demo free, per creare delle utility. In realtà non sempre funziona l'attribuzione del flag visibile/invisibile (ad esempio per i pacchetti), ma chiunque voglia può proporre modifiche e varianti. Puoi scaricarlo da qui: Invisible/Visible |
||||||||||||||||||||||
File |
Rinomina Documenti
Questa struttura (compilandola con il Runtime License Light, cioè l'engine Demo free) permette di scorrere tutti i Files di una Cartella rinominando gli stessi (comodo, ad esempio, per rinominare foto scaricate da una fotocamera) Puoi scaricarlo da qui: Rinomina |
||||||||||||||||||||||
Codice |
Percorso dell'applicazione o della struttura
Questo metodo ritorna il percorso corrente dell'applicazione compilata con l'engine o della struttura sia su Mac che su PC ` Method: dammiPercorso C_LONGINT($lun;$pos) C_TEXT($0;$sep;$percorso) $sep:=system folder≤length(system folder)≥ If ((Application type=4D Runtime Volume License) & ($sep=":")) $percorso:=Replace string(Application file;".app";"") Else $percorso:=Structure file End if $lun:=Length($percorso) $pos:=$lun Repeat $pos:=$pos-1 Until ($percorso?$pos?=$sep) $0:=Substring($percorso;1;$pos) |
||||||||||||||||||||||
Info |
Lista dei server recenti
Quando ti colleghi ad un server con il 4D Client viene registrato un documento con il percorso nella cartella Favorites 2004. Questa cartella si trova qui: Windows = C:\\Documents and Settings\CurrentUser\Application Data\4D folder Macintosh = Mac HD:Users:CurrentUser:Library:Application Support:4D dove, il nome del disco di avvio può essere diverso da Mac HD, e al posto di CurrentUser ci sarà il nome dell'utente Al prossimo collegamento a 4D Server, il 4D Client mostrerà prima l'elenco dei server il cui nome legge dai documenti nella cartella Favorites 2004. Questi documenti contengono inoltre anche l'indirizzo ip del server. |
||||||||||||||||||||||
Info |
A cosa serve lo stack
Usando i comandi New process o Execute on server viene utilizzato un valore che rappresenta, in byte, la dimensione dello stack. Lo stack non è la memoria totale del processo. I processi condividono la memoria per quanto riguarda record, variabili interprocesso, ecc. Un processo usa della memoria aggiuntiva per memorizzare le variabili del processo. Lo stack contiene il resto: la "pila" delle chiamate ricorsive, con il numero e la dimensione dei parametri e delle variabili locali, i form aperti dal processo prima della sua chiusura. |
||||||||||||||||||||||
Web |
Aprire un documento XML
Per aprire un documento XML da processare il comando da utilizzare è Parse XML source (per la 2004 DOM Parse XML source). La sintassi è: Parse XML source (document{; validation{; dtd}}) dove document è il percorso al file, validation è un booleano che controlla se il documento rispetta o no le specifiche DTD (Document Type Declaration, una serie di regole che un documento XML deve rispettare) e il percorso dove è memorizzato il file di validazione. Stesso principio usano i comandi Parse XML variable (DOM Parse XML variable per la 2004), ma su variabili testo o blob. Il comando resistuisce una stringa da utilizzare come riferimento al documento. |
||||||||||||||||||||||
Codice |
Mantenere i colori del method editor
Uno dei crucci maggiori per i programmatori è quello di mantenere il più standard possibile il proprio ambiente di lavoro. Ad esempio poter mantenere gli stessi colori per il method editor tra varie macchine. Per rendere possibile tutto questo basta riutilizzare il file 4D Preferences 2004(.RSR) che contiene tutte le informazioni di personalizzazione dell'applicazione 4th Dimension. Questo principio è molti utile, ad esempio, per avere tutti i client con i colori "configurati" allo stesso modo. Le cartelle dove rintracciare il file (per 4th Dimension, 4D Server e 4D Client) si possono ottenere da questa faq. |
||||||||||||||||||||||
Tecniche |
Metodo di indirizzamento delle stampe [3]
Applicazione Nell’applicativo sopra citato ho creato una gestione delle stampe che salva i parametri per ogni diverso modulo funzionale (fatture, etichette, ecc. ecc.) e i parametri sono salvati separatamente per ogni utente o postazione di lavoro, perché non tutti i client accedono alle stesse stampanti. Una volta impostata una specifica stampa per una determinata procedura di una determinata postazione di lavoro, i parametri di stampa sono automaticamente proposti come default per le successive stampe identiche; è comunque sempre possibile scegliere una diversa impostazione tra quelle salvate, tutte accessibili in qualunque funzione di stampa dell’intera struttura. Ecco un esempio dell’interfaccia (ancora stile OS 9...) in cui è fatto uso anche della possibilità di registrare il numero di copie da stampare ![]() Dopo avere impostato i parametri per la prima volta, basta un tasto per ottenere stampe corrette; in alternativa basta scegliere una voce dal popup per cambiare la destinazione della stampa o il prelevamento della carta, selezionando una pre-impostazione salvata. RV marzo 2006 |
||||||||||||||||||||||
Tecniche |
Metodo di indirizzamento delle stampe [2]
Recupero e utilizzo delle impostazioni di stampa, è importante la corretta successione dei comandi: 1) impostare la stampante da usare utilizzando il nome salvato; 2) applicare i parametri di stampa con AP BLOB to print settings usando il paramType “0” per impostare sia Layout sia Print; 3) lanciare la stampa senza cambiare più nulla: no PAGE SETUP no PRINT SETTINGS altrimenti si ricade nell’indefinito. Esempio SET CURRENT PRINTER([ParametersTable]PrinterName) $error:=AP BLOB to print settings ([ParametersTable]ParametersBLOB;0) Case of : ($error=-1) ALERT ("Il BLOB dei Parametri di Stampa contiene dati errati.") : ($error=0) ALERT ("Errore di stampante non definita.") Else ` lanciare la stampa End case Nota bene: - dove si fa riferimento al nome della stampante, è sempre inteso il system name e non l’user name, ovvero il nome della coda di stampa, quello che si ottiene con il comando PRINTERS LIST; - nel caso di stampe che utilizzano la funzione Print Form, è indispensabile inizializzare il job con un PAGE BREAK(>), nota il “>”; - questa soluzione salva tutti i parametri impostati con il PRINT SETTINGS, anche il numero di copie. - dopo caricati i parametri, se si chiama PRINT SETTINGS si perdono le impostazioni caricate e verranno usate quelle mostrate nei dialoghi di definizione di stampa standard dell’OS; - dopo avere caricato i parametri di stampa, se desidera esaminarli (con PRINT SETTINGS)si troverà che il secondo dialog di stampa standard dell’OS (il primo definisce la pagina, il secondo i parametri) mostrerà una Preimpostazione (Preset) che può non corrispondere a quella salvata (è definita dall’OS sarà l’ultima usata o quella di default dipende dalle impostazioni di sistema): è ininfluente, viene ignorata e verrà usata quella effettivamente salvata (salvo avere confermato i dialoghi di stampa aperti con PRINT SETTINGS). |
||||||||||||||||||||||
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 | |||||||||||||||||||||
Novita' |
4D 2004.3 - Il comando SET SCROLLBAR VISIBLE
Nelle prime versioni della 2004, era presente il comando SHOW LISTBOX SCROLLBAR che permetteva di visualizzare le barre di scorrimento per le listbox. Dalla versione 2004.3 questo comando è stato rimpiazzato dal più potente SET SCROLLBAR VISIBLE, che dal capitolo List Box" è stato spostato in quello "Object Properties"; questo comando può adesso essere utilizzato, oltre che sulle List box, anche su Scrollable area e Subform. |
||||||||||||||||||||||
Comandi |
Il comando ALERT
Il comando ALERT permette di mostrare a video una dialog con un'icona, un testo da massimo 255 caratteri e un pulsante. La sintassi è ALERT (message{; ok button title}) dove message è il messaggio da mostrare a video (può essere un testo direttamente oppure una variabile) e, opzionale, ok button title è il testo da assegnare al pulsante OK. Se il testo passato è superiore a 255 caratteri viene troncato. La dimensione del pulsante viene adattata automaticamente alla dimensione del testo del pulsante. ATTENZIONE: Il comando non deve essere eseguito all'interno dei form event On Activate oppure On Deactivate perché ciò genera un loop infinito. |
||||||||||||||||||||||
Info |
Not enough stack space to complete the current method
Passando database, possibilmente sviluppati inizialmente con versioni (e computer) assai datate di 4D, alla versione 2004.3 di 4th Dimension, potrebbe d'un tratto diventare assai frequente l'errore "Not enough stack space to complete the current method": cioè, nel creare il nuovo processo con New process o Execute on server, non gli si è dato abbastanza spazio nello stack. Il problema è che nelle ultime versioni era consigliato aumentare lo stack dai vecchissimi 32K almeno a 64K o meglio 128K. In realtà le versioni precedenti alla 2004.3 aumentavano arbitrariamente la dimensione dello stack per evitare errori al programmatore dopo una conversione di struttura: questo però ha portato ad un minor controllo di quello che succede come occupazione della memoria. Ora 4D obbedisce strettamente alle impostazioni fatte e quindi se si ha qualche chiamata con meno di 64K di stack è facile vedere questo mesaggio. |
||||||||||||||||||||||
Comandi |
Creare un logical mirror [1]: come funziona
Solitamente le tecniche di backup standard permettono di effettuare salvataggi (solitamente notturni o a richiesta) dei database. Però in qualche caso non basta avere una copia di backup, ma sarebbe utile fermare le operazioni di accesso al database per il minor tempo possibile. Per venire incontro a questo tipo di esigenza, con la versione 2004.3 è comparso un nuovo tipo di backup: logical mirror. Su macchine 4D Server diventa infatti possibile avere due programmi sempre aggiornati e funzionanti: vediamo come funziona. Supponiamo di avere due Server, uno MacchinaPrincipale e l'altro MacchinaMirror. Su MacchinaPrincipale facciamo partire l'applicazione, eseguiamo un backup e definiamo un file log (che per MioDatabase sarà MioDatabase.4DL). Usciamo dall'applicazione. Copiamo tutti i file (compreso il log file) su MacchinaMirror. Facciamo partire l'applicazione su entrambe le macchine: MacchinaMirror ci chiederà quale log file utilizzare e noi sceglieremo il file MioDatabase.4DL che abbiamo trasferito. Decidiamo di eseguire l'aggiornamento del mirror in automatico (ad esempio dopo una certa quantità di operazioni). Eseguiamo un metodo contenente il comando New log file. Il precedente file di log verrà salvato , ad esempio, col nome, MioDatabase[0001-0000].4DL Inviamo il il file MioDatabase[0001-0000].4DL a MacchinaMirror, usando 4DInternetCommands o 4DOpen. Mentre MacchinaPrincipale continua tranquillamente a lavorare, MacchinaMirror si accorge della presenza di un nuovo file log da integrare. Esegue allora il metodo contenente il comando INTEGRATE LOG FILE che integrerà MioDatabase[0001-0000].4DL nel database. Questo è inoltre diventato così il nuovo file log. Se quindi MacchinaPrincipale si rompe, diventando temporaneamente inutilizzabile, si può decidere di passare ad usare MacchinaMirror. Copiamo il file MioDatabase.4DL da MacchinaPrincipale a, nella posizione usuale, MacchinaMirror: questa, al solito, si accorgerà della presenza di un nuovo file di log e lo integrerà nel database, che diventerà il nuovo database da utilizzare, durante la riparazione di MacchinaPrincipale. Riparata MacchinaPrincipale, si inseriscono su questa i file attualmente su MacchinaMirror. I due server cominciano nuovamente a funzionare come in partenza. Il tutto senza interruzioni lavorative e con un brevissimo tempo di attivazione del server mirror. |
||||||||||||||||||||||
Codice |
Spostamento circolare sulle ListBox
Usando le frecce per scorrere una listbox, quando la selezione arriva ad uno degli estremi della lista (inferiore o superiore che sia), una ulteriore pressione dei tasti freccia (verso il basso o verso l'alto rispettivamente) non cambia, giustamente, la riga selezionata. Se si vuole fare in modo che, quando la riga selezionata è l'ultima, una ulteriore pressione del tasto "Freccia giù" porti la selezione al primo elemento della listbox, basta creare un pulsante nel form, associare al pulsante lo shortcut "Down Arrow" e scrivere il seguente codice nel metodo del pulsante: Case of : (Form event=On Clicked ) If (ListBox=0) ListBox:=1 Else ListBox:=ListBox+1 If (ListBox>Size of array(arrEsempio)) ListBox:=1 End if End if SELECT LISTBOX ROW(ListBox;ListBox) End case Stesso principio si può adottare per un pulsante associato a "Up Arrow": Case of : (Form event=On Clicked ) ListBox:=ListBox-1 If (ListBox<=0) ListBox:=Size of array(arrEsempio) End if SELECT LISTBOX ROW(ListBox;ListBox) End case |
||||||||||||||||||||||
Bug |
Termometri in 4D 2004.3
Un problema solo formale e il suo work-around. Creando un termometro in un form, la proprietà "Fill color" risulta non accessibile. Il problema è comunque facilmente risolvibile: basta modificare il tipo di oggetto da thermo a dial e poi di nuovo a thermometer, e la proprietà riappare. Al momento il baco è riproducibile e sotto studio. |
||||||||||||||||||||||
Comandi |
Il comando Get 4D folder
Il comando Get 4D folder ritorna il percorso per le cartelle utilizzate da 4D, in base al parametro passato al comando (infatti la sintassi è Get 4D folder {(folder)} ). Le costanti utilizzabili come parametro sono: Active 4D Folder oppure 0 (valori di default) Licenses Folder oppure 1 Extras Folder oppure 2 4D Client Database Folder oppure 3 Nel dettaglio: Active 4D Folder contiene i seguenti file: le preferenze delle applicazioni o delle utility dell'ambiente 4D; i file per il protocollo TCP/IP; le cartelle che 4D Client scarica dal server per salvare risorse, plug-in, extras; Solitamente il percorso della cartella è: Su Mac OS: {Disco fisso}:Library:Application Support:4D Su Windows: {Disco fisso}:\Documents and Settings\All Users\Application Data\4D Su 4DClient la cartella diventa: {Disco fisso}:\Documents and Settings\Current user\Application Data\4D dove Current user è l'utente che ha aperto la sessione di Windows. License Folder Contiene i file con le licenze, si trova: Su Mac OS : {Disco fisso}:Library:Application Support:4D:Licenses Su Windows: {Disco fisso}:\Documents and Settings\All Users\Application Data\4D\Licenses 4D Client Database Folder (solo per le macchine client) E' la cartella contenente tutti i file necessari al funzionamento del programma client, con le relative sottocartelle. Il percorso è: Su Windows: {Disco fisso}:\Documents and Settings\Current user\Application Data\4D\DatabaseName_Address (dove Current user è l'utente che ha aperto la sessione Windows). Su Mac OS: {Disco fisso}:Library:Application Support:4D:DatabaseName_Address Extras Folder Funziona solo su 4D Client e permette di conoscere il percorso alla cartella scaricata automaticamente da 4D Server contenente gli extra, tutti quei file che solitamente vogliamo siano presenti su ogni client (risorse statistiche, testi, xml, preferenze). Il percorso è: Su Windows: {Disco fisso}:\Documents and Settings\Current user\Application Data\4D\DatabaseName_Address\Extras (dove Current user è sempre l'utente che ha aperto la sessione Windows). Su Mac OS: {Disco fisso}:Library:Application Support:4D:DatabaseName_Address:Extras |
||||||||||||||||||||||
Novita' |
4D 2004 - Proprietà delle ListBox: Number of Static Columns
Fra le proprietà delle ListBox, quella denominata Number of Static Columns permette di impostare il numero di colonne, a partire dalla prima e comprese quelle nascoste, che non possono essere mosse in modalità User/Custom. Quindi per impedire che le colonne vengano mosse, basta impostare questo parametro sullo stesso numero impostato su Number of Columns. |
||||||||||||||||||||||
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 | |||||||||||||||||||||
Comandi |
4D 2004 - Il comando SELECT LISTBOX ROW
In una listbox, il comando SELECT LISTBOX ROW permette di impostare la selezione per le righe il cui numero viene passsato come parametro. La sintassi è: SELECT LISTBOX ROW ({*; }object; position{; action}) dove - object è l'oggetto listbox (se si passa la variabile "*" non serve, altrimenti si usa se si vuole passare il nome dell'oggetto); - position è la riga da prendere in considerazione; - action è un intero (facoltativo) che permette di impostare l'azione da compiere sulla riga. Per azione si intende: • Replace listbox selection (0): sostituisce la selezione attuale con quella specificata da position, è l'azione di default. • Add to listbox selection (1): la riga position viene aggiunta alla selezione corrente. • Remove from listbox selection (2): la riga position viene rimossa dalla selezione corrente. Per scorrere direttamente via linguaggio alla riga selezionata si può usare il comando SCROLL LINES. Per passare automaticamente alla modalità di inserimento si può usare il comando EDIT ITEM. |
||||||||||||||||||||||
Novita' |
4D 2004: la variabile associata ad una listbox
La variabile associata ad un oggetto list box può essere utilizzata per impostare o ottenere la selezione di righe della ListBox stessa. La variabile è infatti un array di tipo Boolean creato e mantenuto da 4th Dimension. La dimensione dell'array è determinata dalla listbox: conterrà infatti lo stesso numero di elementi del più piccolo fra gli array associati alle colonne. Ogni elemento dell'array è impostato su True se la corrispondente linea è selezionata, False altrimenti. 4th Dimension aggiorna automaticamente il contenuto dell'array in base alle azioni dell'utente. D'altra parte, è possibile modificare il valore degli elementi dell'array in modo da modificare la selezione nella listbox. Questo frammento di codice, ad esempio, inverte la selezione del primo elemento della listbox lbElenco: If (lbElenco{1} = True) lbElenco{1}:= False Else lbElenco{1}:= True End if Quindi questo array non è modificabile in dimensione o in tipo. |
||||||||||||||||||||||
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 |
Risolvere gli errori web nei programmi compilati
Se, scrivendo un programma destinato ad un uso via web, in interpretato funziona tutto regolarmente, mentre compilato alcune richieste ritornino il messaggio: A runtime error occurred at line number: When executing the method: Unknown Invalid parameters in an Execute command. Il motivo di tale errore è presto spiegato: all'interno dei metodi chiamati dalle pagine html (definiti come "Available through 4DACTION, 4DMETHOD and 4DSCRIPT") è necessario inserire le definizioni: C_TEXT($0;$1) |
||||||||||||||||||||||
Comandi |
Il comando GET CLIPBOARD
Il comando GET CLIPBOARD, la cui sintassi è GET CLIPBOARD (dataType; data) dove - dataType è ua stringa di 4 caratteri passata al comando indicante il tipo di dato presente negli appunti (case sensitive) - data è il blob che riceve il contenuto degli appunti permette di riempire un blob con il contenuto della clipboard. Il risultato del comando può essere uno dei seguenti: - i dati sono estratti correttamente dagli appunti e la variabile OK viene impostata a 1. - gli appunti non contengono il tipo di dati specificato in dataType, la variabile OK viene settata a 0 e viene generatoun errore -102 - non c'è sufficiente memoria per eseguire il comando, OK vale 0 e viene generato un errore -108. |
||||||||||||||||||||||
Codice |
Cancellare record non bloccati
Ecco un frammento di codice da usare per cancellare dei record selezionati in un form di output, controllando che non siano bloccati. CREATE SET(Current form table->;"SetSelezione") USE SET("UserSet") DELETE SELECTION(Current form table->) USE SET("OriginalSet") $lockedRecords:=Records in set("LockedSet") Case of :($lockedRecords=1) $msg:=”Un record è bloccato e non può essere cancellato. Lo visualizzo?“ :($lockedRecords>1) $msg:=”Alcuni record sono bloccati e non possono essere cancellati. Li visualizzo?“ Else $msg:=”” End case If ($lockedRecords#0) CONFIRM$msg;"Yes";"No") If (OK=1) USE SET("LockedSet") End if CLEAR SET("LockedSet") End if CLEAR SET("SetSelezione ") FLUSH BUFFERS Per altre informazioni sull'uso dei set consultare questa faq. |
||||||||||||||||||||||
Novizi |
Date antecedenti
Per ottenere un valore di tipo date partire da un altro si usa il comando Add to date. E' importante sottolineare che il comando accetta anche numeri negativi come parametro: questo significa che per portare indietro di due mesi la data contenuta nella variabile $data_d posso scrivere: $data_d:=Add to date($data_d;0;-2;0) |
||||||||||||||||||||||
Plugin |
Calcolo di altezza e larghezza di un testo
In 4D è incluso un plugin, 4D Chart, che non è molto considerato (forse perchè è gratis :) );in realtà oltre a fare i grafici fornisce alcuni strumenti interessanti, ad esempio per la elaborazione di testi o disegni all'interno di una immagine. Ecco un interessante esempio di utilizzo. Usando una offscreen area di 4D Chart è possibile conoscere larghezza e altezza di una campo testo, anche multilinea. I parametri passati sono il testo, il carattere, la dimensione, lo stile, il puntatore all'oggetto che deve ricevere la larghezza e il puntatore all'oggetto che deve ricevere l'altezza. Ecco il metodo: C_TEXT($Testo_t) $Testo_t:=$1 C_STRING(255;$TipoCarattere_S) $TipoCarattere_S:=$2 C_LONGINT($Dimensione_L;$StileTesto_L) $Dimensione_L:=$3 $StileTesto_L:=$4 C_LONGINT($Larghezza_L;$Altezza_L) $Larghezza_L:=0 $Altezza_L:=0 If ($Testo_t#"") C_LONGINT($NumeroTipoCarattere_L) $NumeroTipoCarattere_L:=CT Font number ($TipoCarattere_S) If ($NumeroTipoCarattere_L#0) C_LONGINT($ChartArea_L; $TestoChart_L) $ChartArea_L:=CT New offscreen area $TestoChart_L:=CT Draw text ($ChartArea_L;0;0;2048;5;$Testo_t) CT SET TEXT ATTRIBUTES ($ChartArea_L;$TestoChart_L;$NumeroTipoCarattere_L;$Dimensione_L;$StileTesto_L;0;0) C_LONGINT($sinistra_L;$alto_L;$destra_L;$basso_L) CT GET BOUNDARY ($ChartArea_L;$TestoChart_L;$sinistra_L;$alto_L;$destra_L;$basso_L) $Larghezza_L:=$destra_L-$sinistra_L `La larghzza viene trovata riducendola $Altezza_L:=$basso_L-$alto_L `L’altezza è corretta If ($Larghezza_L>0) Repeat $Larghezza_L:=$Larghezza_L-100 CT SIZE ($ChartArea_L;$TestoChart_L;$Larghezza_L;$Altezza_L) CT GET BOUNDARY ($ChartArea_L;$TestoChart_L;$sinistra_L;$alto_L;$destra_L;$basso_L) Until ((($basso_L-$alto_L)>$Altezza_L) | ($Larghezza_L<100)) $Larghezza_L:=$Larghezza_L+(100*Num(($basso_L-$alto_L)>$Altezza_L)) Repeat $Larghezza_L:=$Larghezza_L-20 CT SIZE ($ChartArea_L;$TestoChart_L;$Larghezza_L;$Altezza_L) CT GET BOUNDARY ($ChartArea_L;$TestoChart_L;$sinistra_L;$alto_L;$destra_L;$basso_L) Until ((($basso_L-$alto_L)>$Altezza_L) | ($Larghezza_L<20)) $Larghezza_L:=$Larghezza_L+(20*Num(($basso_L-$alto_L)>$Altezza_L)) Repeat $Larghezza_L:=$Larghezza_L-1 CT SIZE ($ChartArea_L;$TestoChart_L;$Larghezza_L;$Altezza_L) CT GET BOUNDARY ($ChartArea_L;$TestoChart_L;$sinistra_L;$alto_L;$destra_L;$basso_L) Until ((($basso_L-$alto_L)>$Altezza_L) | ($Larghezza_L<1)) $Larghezza_L:=$Larghezza_L+1 Else `Se il testo supera i 2048 pixel, ritorna 0 End if CT DELETE OFFSCREEN AREA ($ChartArea_L) End if End if $5->:=$Larghezza_L $6->:=$ Altezza_L Fonte: 4DToday - Michel Pourcel |
||||||||||||||||||||||
File |
Archiviazione o Protocollazione Immagini
Quante volte ci siamo chiesti "dove avro' messo quella ricevuta?" io mi sono stufato e visto che ho uno scanner in grado di salvare in formato jpeg o tiff, ho fatto questa struttura: http://www.sviluppo4d.it/4DCGI/Downloads/Archiviazione_Immagini.zip (poteva essere fatta meglio, con piu' campi, con vari livelli di accesso, con pulsanti di stampa, con l' invio per Email, con ........ (a voglia aggiungere roba) ma cosi' ognuno se la puo' personalizzare come crede) ovviamente richiede la presenza del QuickTime L'ho provata anche su windows, con solo il runtime, e pare tutto ok anche con immagini da oltre un mega e spiccioli la caratteristica e' quella di memorizzare piu' pagine con un unico riferimento Non ho volutamente usato Subrecords e con un trigger ( on load, on save ) sul Table IMMAGINI potevo salvare le immagini su folder nel caso On Save .... e richiamarle nell On Loading ... Ho giocato un po' con le dimensioni delle finestre ( magari non saro' stato molto preciso) la prima cosa da fare e' individuare la cartella dove lo Scanner salva le immagini cosi' da poter creare un alias (collegamento) allo stesso livello dell'applicazione ciao Franco Gallai Dhal Srl Arezzo P.S. : se qualcuno ci ricava un'applicazione, spero si ricordi di me |
||||||||||||||||||||||
Comandi |
Il comando SELECTION TO ARRAY
Il comando SELECTION TO ARRAY la cui sintassi è SELECTION TO ARRAY (field | table; array{; field2 | table2; array2; ...; fieldN | tableN; arrayN}) dove table è la tabella da cui ottenere i record number, oppure field sono i campi da cui ricevere i dati array sono gli array che riceveranno i dati crea uno o più array ricopiando i dati o i record number della selezione corrente nei vari array. SELECTION TO ARRAY è in grado anche di caricare i valori di tabelle in relazione "a Uno" con la tabella attuale, purché sia, temporaneamente o di default, automatica. Ogni array riceve dati dello stesso tipo, eccettuati i seguenti casi: - se un campo testo viene copiato in uno String array, l'array resta di tipo String; - un campo time viene copiato in un array di tipo Long Integer. Il comando è ottimizzato per 4DServer Dopo l'esecuzione di SELECTION TO ARRAY, sia la selezione che il record corrente non vengono modificati, ma il record corrente non risulta caricato: è dunque necessario usare un LOAD RECORD per caricarlo nuovamente. |
||||||||||||||||||||||
Bug |
4D 2003.7 - OSX 10.3 10.4 - PRINT SETTINGS - Non imposta la stampante richiesta
In un'applicazione, sia monoutenza che server, su Mac OSX 10.3 o 10.4, non è possibile indirizzare una stampa effettuata con PRINT FORM su una stampante diversa da quella di default. Il comando PRINT SETTINGS nonostante permetta di selezionare tutte le stampanti installare sul sistema, in realtà manda poi la stampa sempre e solo su quella impostata come default da Utiltiy di Configurazione Stampanti. Il tutto funziona invece correttamente se usiamo mac osx 10.2.8. Ho già segnalato a ITALsoftware il bug e hanno inviato una segnalazione al supporto di 4Th Dimension. |
||||||||||||||||||||||
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)) |
||||||||||||||||||||||
Codice |
Programma risolutore Sudoku: metodo ricorsivo
Per dimostrare l'equivalenza tra procedure iterative e procedure ricorsive, pubblichiamo due metodi per risolvere uno schema Sudoku 9x9x9. Ecco la soluzione del Sudoku ricorsiva: `Solver $prossimo:=$1 If ($prossimo>0) $row:=($prossimo\9)+(1*Num(Mod($prossimo;9)>0)) $column:=$prossimo-(($row-1)*9) $0:=False For ($i;1;9) arrValori{$row}{$column}:=$i If (CheckRules ($row;$column)) $0:=Solver (GetNext ) End if If ($0) $i:=12 End if End for If ($0=False) arrValori{$row}{$column}:=0 End if Else $0:=True End if `CheckRules $0:=True $row:=$1 $column:=$2 $valore:=arrValori{$row}{$column} For ($i;1;9) If ((($i#$row) & (arrValori{$i}{$column}=$valore)) | (($i#$column) & (arrValori{$row}{$i}=$valore))) $0:=False $i:=12 End if End for If ($0) $firstcol:=($column-1\3)*3 $firstrow:=($row-1\3)*3 For ($i;1;3) For ($j;1;3) $checkRow:=$firstrow+$i $checkCol:=$firstcol+$j If ((Not(($checkRow=$row) & ($checkCol=$column))) & (arrValori{$checkRow}{$checkCol}=$valore)) $0:=False $i:=12 $j:=12 End if End for End for End if `GetNext ARRAY LONGINT($arrPosizione;0) ARRAY LONGINT($arrQuanti;0) For ($i;1;9) For ($j;1;9) If ((arrFissi{$i}{$j}=False) & (arrValori{$i}{$j}=0)) INSERT ELEMENT($arrPosizione;Size of array($arrPosizione)+1) INSERT ELEMENT($arrQuanti;Size of array($arrQuanti)+1) $arrPosizione{Size of array($arrPosizione)}:=(($i-1)*9)+$j For ($valore;1;9) arrValori{$i}{$j}:=$valore If (CheckRules ($i;$j)) $arrQuanti{Size of array($arrQuanti)}:=$arrQuanti{Size of array($arrQuanti)}+1 End if End for arrValori{$i}{$j}:=0 End if End for End for MULTI SORT ARRAY($arrQuanti;>;$arrPosizione;>) If (Size of array($arrQuanti)>0) $0:=$arrPosizione{1} Else $0:=0 End if |
||||||||||||||||||||||
Codice |
Programma risolutore Sudoku: metodo iterativo
Diamo seguito ad una faq precedente, pubblicando i metodi che permettono di risolvere un problema Sudoku utilizzando un sistema di programmazione iterativo. `btElabora ARRAY INTEGER(assudo;729) ARRAY INTEGER(supos;81) ARRAY INTEGER(sudo;81) $x:=1 Repeat $pvar:=Get pointer("sudo"+String($x)) If ($pvar->="") sudo{$x}:=0 Else sudo{$x}:=Num($pvar->) End if $x:=$x+1 Until ($x>81) $pp:=sudoarr (1) $x:=1 Repeat supos{$x}:=0 $x:=$x+1 Until ($x>81) ARRAY INTEGER($vuoti;0) $x:=1 $y:=1 Repeat If (sudo{$x}=0) INSERT ELEMENT($vuoti;$y) $vuoti{$y}:=$x $y:=$y+1 End if $x:=$x+1 Until ($x>81) $tempo:=Tickcount `Open window(200;200;300;350;16;"Elaborazione") Open window(200;200;340;350;16;"Elaborazione") sudomess $x:=1 Repeat $posa:=supos{$vuoti{$x}}+1 $posass:=($vuoti{$x}*9)-8 If ($posa<10) supos{$vuoti{$x}}:=$posa sudo{$vuoti{$x}}:=assudo{$posass+$posa-1} sudomess If (assudo{$posass+$posa-1}#0) If ($x Else $pp:=True End if If ($pp) $x:=$x+1 Else sudo{$vuoti{$x}}:=0 sudomess If (assudo{$posass+$posa}=0) supos{$vuoti{$x}}:=0 $x:=$x-1 End if End if Else sudo{$vuoti{$x}}:=0 sudomess supos{$vuoti{$x}}:=0 $x:=$x-1 End if Else sudo{$vuoti{$x}}:=0 sudomess supos{$vuoti{$x}}:=0 $x:=$x-1 End if Until ($x>Size of array($vuoti)) | ($x<1) CLOSE WINDOW $x:=1 Repeat $pvar:=Get pointer("sudo"+String($vuoti{$x})) $pvar->:=String(sudo{$vuoti{$x}}) $x:=$x+1 Until ($x>Size of array($vuoti)) If ($x<1) ALERT("SOLUZIONE IMPOSSIBILE") Else ALERT("Risolto in "+String(Int((Tickcount-$tempo)/60))+" secondi") End if `sudomess riga1:=String(sudo{1})+" "+String(sudo{2})+" "+String(sudo{3})+" "+String(sudo{4})+" "+String(sudo{5})+" "+String(sudo{6})+" "+String(sudo{7})+" "+String(sudo{8})+" "+String(sudo{9}) riga2:=String(sudo{10})+" "+String(sudo{11})+" "+String(sudo{12})+" "+String(sudo{13})+" "+String(sudo{14})+" "+String(sudo{15})+" "+String(sudo{16})+" "+String(sudo{17})+" "+String(sudo{18}) riga3:=String(sudo{19})+" "+String(sudo{20})+" "+String(sudo{21})+" "+String(sudo{22})+" "+String(sudo{23})+" "+String(sudo{24})+" "+String(sudo{25})+" "+String(sudo{26})+" "+String(sudo{27}) riga4:=String(sudo{28})+" "+String(sudo{29})+" "+String(sudo{30})+" "+String(sudo{31})+" "+String(sudo{32})+" "+String(sudo{33})+" "+String(sudo{34})+" "+String(sudo{35})+" "+String(sudo{36}) riga5:=String(sudo{37})+" "+String(sudo{38})+" "+String(sudo{39})+" "+String(sudo{40})+" "+String(sudo{41})+" "+String(sudo{42})+" "+String(sudo{43})+" "+String(sudo{44})+" "+String(sudo{45}) riga6:=String(sudo{46})+" "+String(sudo{47})+" "+String(sudo{48})+" "+String(sudo{49})+" "+String(sudo{50})+" "+String(sudo{51})+" "+String(sudo{52})+" "+String(sudo{53})+" "+String(sudo{54}) riga7:=String(sudo{55})+" "+String(sudo{56})+" "+String(sudo{57})+" "+String(sudo{58})+" "+String(sudo{59})+" "+String(sudo{60})+" "+String(sudo{61})+" "+String(sudo{62})+" "+String(sudo{63}) riga8:=String(sudo{64})+" "+String(sudo{65})+" "+String(sudo{66})+" "+String(sudo{67})+" "+String(sudo{68})+" "+String(sudo{69})+" "+String(sudo{70})+" "+String(sudo{71})+" "+String(sudo{72}) riga9:=String(sudo{73})+" "+String(sudo{74})+" "+String(sudo{75})+" "+String(sudo{76})+" "+String(sudo{77})+" "+String(sudo{78})+" "+String(sudo{79})+" "+String(sudo{80})+" "+String(sudo{81}) GOTO XY(2;1) MESSAGE(riga1) GOTO XY(2;2) MESSAGE(riga2) GOTO XY(2;3) MESSAGE(riga3) GOTO XY(2;4) MESSAGE(riga4) GOTO XY(2;5) MESSAGE(riga5) GOTO XY(2;6) MESSAGE(riga6) GOTO XY(2;7) MESSAGE(riga7) GOTO XY(2;8) MESSAGE(riga8) GOTO XY(2;9) MESSAGE(riga9) `sudoarr C_INTEGER($1) C_BOOLEAN($0) $pieno:=True $x:=$1 Repeat $posass:=($x*9)-8 If (sudo{$x}=0) $z:=$posass $zz:=1 Repeat assudo{$z}:=0 $z:=$z+1 $zz:=$zz+1 Until ($zz>9) $y:=1 $pos:=0 $arr:=0 sudopos ($x) Repeat If (ChkRiga ($x;$y)) assudo{$posass+$pos}:=$y $arr:=$arr+assudo{$posass+$pos} $pos:=$pos+1 End if $y:=$y+1 Until ($y>9) If ($arr=0) $pieno:=False End if End if $x:=$x+1 Until ($x>81) | ($pieno=False) $0:=$pieno `sudopos C_INTEGER($1) C_BOOLEAN($0) $pieno:=True $x:=$1 Repeat $posass:=($x*9)-8 If (sudo{$x}=0) $z:=$posass $zz:=1 Repeat assudo{$z}:=0 $z:=$z+1 $zz:=$zz+1 Until ($zz>9) $y:=1 $pos:=0 $arr:=0 sudopos ($x) Repeat If (ChkRiga ($x;$y)) assudo{$posass+$pos}:=$y $arr:=$arr+assudo{$posass+$pos} $pos:=$pos+1 End if $y:=$y+1 Until ($y>9) If ($arr=0) $pieno:=False End if End if $x:=$x+1 Until ($x>81) | ($pieno=False) $0:=$pieno `ChkRiga C_INTEGER($1) C_INTEGER($2) C_BOOLEAN($0) $giusto:=True $cas:=$1 $num:=$2 $inriga:=suriga*9-8 $finriga:=$inriga+8 Repeat If (sudo{$inriga}=$num) $giusto:=False End if $inriga:=$inriga+1 Until ($giusto=False) | ($inriga>$finriga) If ($giusto) $incol:=sucol $fincol:=72+sucol Repeat If (sudo{$incol}=$num) $giusto:=False End if $incol:=$incol+9 Until ($giusto=False) | ($incol>$fincol) If ($giusto) $inq:=suiq $finq:=suiq+20 $x:=1 Repeat If (sudo{$inq}=$num) $giusto:=False End if If ($x=3) $inq:=$inq+7 $x:=1 Else $inq:=$inq+1 $x:=$x+1 End if Until ($giusto=False) | ($inq>$finq) End if End if $0:=$giusto |
||||||||||||||||||||||
Plugin |
4D Open e l'errore -9947
Aprendo una connessione 4D Open ad un database 4D è possibile ottenere un codice di errore -9947; questo errore indica che l'opzione "Autorizza le connessioni via 4D Open" è deselezionata nelle preferenze del database. E' possibile attivare questa opzione solo da 4th Dimension o 4D Client, ma non direttamente dalla finestra di preferenze di 4D Server. |
||||||||||||||||||||||
Codice |
Calcolo Coefficienti Sistema lineare di 3 equazioni
Informazioni sull'utilizzo del seguente metodo è spiegato nella faq Calcolo della linea di tendenza polinomiale in un grafico ` Method_CalcoloCoefficienti ` Roberto Vergani Luglio 2002 ` Regressione Polinomiale ` equazione normale della parabola dei minimi quadrati. ` Sistema lineare di 3 equazioni nelle incognite A, B e C ` Calcolo dei coefficienti C_INTEGER($X;$elementi) C_REAL($somma_X;$somma_Y;$sommaQuadrati_X;$sommaCubo_X;$sommaQuarta_X;$somma_XY;$somma_QuadratoX_Y) C_REAL($determinante_A;$determinante_A1;$determinante_A2;$determinante_A3) C_REAL($elementi;$costante_A;$costante_B;$costante_C) C_POINTER($1) C_REAL(vReal_Coefficiente_A;vReal_Coefficiente_B;vReal_Coefficiente_C) C_INTEGER( $elementi:=Size of array($1->) $somma_X:=0 $somma_Y:=0 $sommaQuadrati_X:=0 $sommaCubo_X:=0 $sommaQuarta_X:=0 $somma_XY:=0 $somma_QuadratoX_Y:=0 For ($X;1;$elementi) $somma_X:=$somma_X+$X $somma_Y:=$somma_Y+($1->{$X}) $sommaQuadrati_X:=$sommaQuadrati_X+($X^2) $sommaCubo_X:=$sommaCubo_X+($X^3) $sommaQuarta_X:=$sommaQuarta_X+($X^4) $somma_XY:=$somma_XY+($X*($1->{$X})) $somma_QuadratoX_Y:=$somma_QuadratoX_Y+(($X^2)*($1->{$X})) End for ` soluzione con il metodo di Cramer ` descrizione del sistema ` Σ_Quarta_X*a + Σ_Cubo_X*b + Σ_Quadrati_X*c = Σ_QuadratoX_Y ` Σ_Cubo_X*a + Σ_Quadrati_X*b + Σ_X*c = ?__XY ` Σ_Quadrati_X*a + Σ__X*b + $elementi*c = ?__Y ` ==== MATRICE DEI COEFFICIENTI ` Tabella mnemorica della matrice ` {1}{1} {1}{2} {1}{3} ` {2}{1} {2}{2} {2}{3} ` {3}{1} {3}{2} {3}{3} ARRAY REAL($matrice;3;3) ` matrice quadrata di ordine tre (allocata come vettore di reali bidimensionale) $matrice{1}{1}:=$sommaQuarta_X $matrice{1}{2}:=$sommaCubo_X $matrice{1}{3}:=$sommaQuadrati_X $matrice{2}{1}:=$sommaCubo_X $matrice{2}{2}:=$sommaQuadrati_X $matrice{2}{3}:=$somma_X $matrice{3}{1}:=$sommaQuadrati_X $matrice{3}{2}:=$somma_X $matrice{3}{3}:=$elementi ` CALCOLO DETERMINANTE DI A (non uso un loop per maggiore leggibilità) ` diagonali discendenti $determinante_A:=$matrice{1}{1}*$matrice{2}{2}*$matrice{3}{3} $determinante_A:=$determinante_A+($matrice{1}{2}*$matrice{2}{3}*$matrice{3}{1}) $determinante_A:=$determinante_A+($matrice{1}{3}*$matrice{2}{1}*$matrice{3}{2}) ` diagonali ascendenti $determinante_A:=$determinante_A-($matrice{3}{1}*$matrice{2}{2}*$matrice{1}{3}) $determinante_A:=$determinante_A-($matrice{3}{2}*$matrice{2}{3}*$matrice{1}{1}) $determinante_A:=$determinante_A-($matrice{3}{3}*$matrice{2}{1}*$matrice{1}{2}) If ($determinante_A#0) ` altrimenti il sistema è incompatibile o non determinato ` Sostituzione della colonna 1 con i termini noti dell'equazione $matrice{1}{1}:=$somma_QuadratoX_Y $matrice{2}{1}:=$somma_XY $matrice{3}{1}:=$somma_Y ` CALCOLO DETERMINANTE DI A1 ` diagonali discendenti $determinante_A1:=$matrice{1}{1}*$matrice{2}{2}*$matrice{3}{3} $determinante_A1:=$determinante_A1+($matrice{1}{2}*$matrice{2}{3}*$matrice{3}{1}) $determinante_A1:=$determinante_A1+($matrice{1}{3}*$matrice{2}{1}*$matrice{3}{2}) ` diagonali ascendenti $determinante_A1:=$determinante_A1-($matrice{3}{1}*$matrice{2}{2}*$matrice{1}{3}) $determinante_A1:=$determinante_A1-($matrice{3}{2}*$matrice{2}{3}*$matrice{1}{1}) $determinante_A1:=$determinante_A1-($matrice{3}{3}*$matrice{2}{1}*$matrice{1}{2}) ` Sostituzione della colonna 2 con i termini noti dell'equazione ` (previo ripristino della colonna 1 ai valori della Matrice A) $matrice{1}{1}:=$sommaQuarta_X $matrice{2}{1}:=$sommaCubo_X $matrice{3}{1}:=$sommaQuadrati_X $matrice{1}{2}:=$somma_QuadratoX_Y $matrice{2}{2}:=$somma_XY $matrice{3}{2}:=$somma_Y ` CALCOLO DETERMINANTE DI A2 ` diagonali discendenti $determinante_A2:=$matrice{1}{1}*$matrice{2}{2}*$matrice{3}{3} $determinante_A2:=$determinante_A2+($matrice{1}{2}*$matrice{2}{3}*$matrice{3}{1}) $determinante_A2:=$determinante_A2+($matrice{1}{3}*$matrice{2}{1}*$matrice{3}{2}) ` diagonali ascendenti $determinante_A2:=$determinante_A2-($matrice{3}{1}*$matrice{2}{2}*$matrice{1}{3}) $determinante_A2:=$determinante_A2-($matrice{3}{2}*$matrice{2}{3}*$matrice{1}{1}) $determinante_A2:=$determinante_A2-($matrice{3}{3}*$matrice{2}{1}*$matrice{1}{2}) ` Sostituzione della colonna 3 con i termini noti dell'equazione ` (previo ripristino della colonna 2 ai valori della Matrice A) $matrice{1}{2}:=$sommaCubo_X $matrice{2}{2}:=$sommaQuadrati_X $matrice{3}{2}:=$somma_X $matrice{1}{3}:=$somma_QuadratoX_Y $matrice{2}{3}:=$somma_XY $matrice{3}{3}:=$somma_Y ` CALCOLO DETERMINANTE DI A3 ` diagonali discendenti $determinante_A3:=$matrice{1}{1}*$matrice{2}{2}*$matrice{3}{3} $determinante_A3:=$determinante_A3+($matrice{1}{2}*$matrice{2}{3}*$matrice{3}{1}) $determinante_A3:=$determinante_A3+($matrice{1}{3}*$matrice{2}{1}*$matrice{3}{2}) ` diagonali ascendenti $determinante_A3:=$determinante_A3-($matrice{3}{1}*$matrice{2}{2}*$matrice{1}{3}) $determinante_A3:=$determinante_A3-($matrice{3}{2}*$matrice{2}{3}*$matrice{1}{1}) $determinante_A3:=$determinante_A3-($matrice{3}{3}*$matrice{2}{1}*$matrice{1}{2}) ` terna soluzione vReal_Coefficiente_A:=$determinante_A1/$determinante_A vReal_Coefficiente_B:=$determinante_A2/$determinante_A vReal_Coefficiente_C:=$determinante_A3/$determinante_A Else vReal_Coefficiente_A:=0 vReal_Coefficiente_B:=0 vReal_Coefficiente_C:=0 End if |
||||||||||||||||||||||
Info |
Calcolo della linea di tendenza polinomiale in un grafico
Ovvero: Statistica, rendere evidente la tendenza di una serie di valori in un grafico creato con 4D Chart La graficazione di valori utilizzando le funzioni di 4D Chart ha lo scopo di permettere all’utente di valutare un fenomeno “a colpo d’occhio”. Avviene spesso che i valori da rappresentare siano discontinui tanto da vanificare l’utilità del grafico, come in questo esempio che rappresenta la vendita giornaliera di un articolo ![]() in casi come questo è indispensabile tracciare una linea di tendenza che renda evidente l’andamento dei valori, la stessa cosa che svolge la funzione “linee di tendenza” di Excel. Una tra le più efficienti è la derivata polinomiale, ecco il risultato: ![]() Solo ora si può apprezzare l’andamento e la tendenza dei valori. L’equazione per il calcolo della derivata polinomiale, come è noto è y = Ax^2 + Bx + C dove A, B e C sono i coefficienti della parabola, che devono essere calcolati a partire dai valori noti. Il calcolo dei tre coefficienti è la soluzione del sistema lineare di tre equazioni in tre incognite: ![]() Il method Method_CalcoloCoefficienti che invio (in calce al presente messaggio) è l’implementazione in 4D della soluzione del sistema in tre incognite sopra enunciato e calcola i tre coefficienti a partire da un array di valori che viene passato in un puntatore. Esempio d’uso L’uso è molto semplice, faccio un esempio riferito ai valori di vendita giornaliera di un articolo. Prima di tutto trasferire i valori delle vendite giornaliere in un array, per esempio vt_MioArrayVendite chiamare il method passando il puntatore all’array dei valori Method_CalcoloCoefficienti (->vt_MioArrayVendite) il method Method_CalcoloCoefficienti ritorna i tre coefficienti in tre variabili reali: vReal_Coefficiente_A vReal_Coefficiente_B vReal_Coefficiente_C che permettono di calcolare i valori della curva di tendenza con l’equazione standard della parabola dei minimi quadrati. Y = (vReal_Coefficiente_A*(X^2))+(vReal_Coefficiente_B*X)+vReal_Coefficiente_C Nota bene: nel caso in cui i valori noti (passati al method) siano incongruenti e generino un sistema di equazioni indeterminato o impossibile, il valori dei tre coefficienti vengono ritornati tutti a zero. Quindi questa eventualità va prevista e gestita. Ottenuti i coefficienti, calcoliamo i valori della curva e li memorizziamo in un nuovo array vt_Tendenza If ((vReal_Coefficiente_A+vReal_Coefficiente_B+vReal_Coefficiente_C)#0) ` se è stato possibile calcolare i coefficienti (sistema determinato) For ($X;1; Size of array(vt_MioArrayVendite)) vt_Tendenza{$X):=(vReal_Coefficiente_A*($X^2))+(vReal_Coefficiente_B*$X)+vReal_Coefficiente_C End for Else ` non è possibile creare una linea di tendenza End if Ora possiamo rappresentare nel grafico sia i valori di vendita (array vt_MioArrayVendite) sia la curva di tendenza (array vt_Tendenza). Naturalmente la curva così ottenuta premette anche di tracciare una teorica tendenza futura, prolungando i valori dell’asse X. ![]() Clic qui per Metodo Calcolo Coefficienti Sistema lineare di 3 equazioni |
||||||||||||||||||||||
Info |
Conversione da 2003 a 2004 per gli output form
Dalla versione 2004 è presente una nuova proprietà per i form, "With Constraints", che permette la gestione dei form ridimensionabili. Nella conversione dalla versione 2003 alla 2004 tale proprietà risulta selezionata di default per i form. Un problema che può capitare, in base alla poszione degli oggetti, è che il pulsante di chiusura venga nascosto dalla barra di scorrimento: per riportare tutto alla situazione originale basta disattivare tale proprietà. |
||||||||||||||||||||||
Codice |
Riempire una combo su una pagina web
Dal forum tecnico italiano pubblico il procedimento da seguire per riempire una combo su una pagina web. Nella pagina web viene inserito il seguente testo: <!--#4DSCRIPT/Web_CaricaArray--> : The method does not exist. : The method does not exist. : The method does not exist. Ecco il metodo Web_CaricaArray C_TEXT($0;$1) ALL RECORDS([Pazienti]) ORDER BY([Pazienti];[Pazienti]Cognome) $menu:=Char(1)+"<"+"select name=\"SelectableList\">\r" FIRST RECORD([Pazienti]) While (Not(End selection([Pazienti]))) $menu:=$menu+"<"+"option value=\""+[Pazienti]Cognome+"\">"+[Pazienti]Cognome+"\r" NEXT RECORD([Pazienti]) End while $menu:=$menu+"" $0:=$menu Due cose da notare: - il value è quello che ritorna dopo che l'utente ha selezionato qualcosa - il Char(1) come primo carattere iniziale segnala a 4d che il testo che si invia è codice html (altrimenti lui sostituisce i caratteri < con il simbolo & lt; per mostrarli bene a video come testo). |
||||||||||||||||||||||
Info |
Da Mac a Windows: alternativa a 4D Transporter
Per chi vuole "trasportare" le proprie applicazioni ed i dati dal formato 4D Mac a Windows esiste il tool 4D Transporter. Tuttavia, come forse qualcuno avra' gia' notato, per utilizzare questo prodotto in ambiente Mac OSX e' necessario aver installato il sottosistema Classic. Per chi, come me, non voglia installare il sottosistema Classic e' disponibile il programma ResTransporter, rilasciato con licenza freeware. Lo potete scaricare dalla pagina: http://www.softrobots.de/dimension/restransporter/index.html oppure direttamente attraverso il link: http://www.softrobots.de/Dateien/ResTransporterX.sit Buona conversione! |
||||||||||||||||||||||
Tecniche |
Icona personalizzata nelle applicazioni compilate
Con 4th Dimension è possibile realizzare applicazioni integrando un particolare runtime: ecco le istruzioni per utilizzare, dalla versione 2004, un'icona personalizzata. L'icona deve avere lo stesso nome della file della struttura interpretata (il normale file che finisce in .4DB): basta mettere il file dell'icona nella stessa cartella e 4d la userà automaticamente quando si genererà l'applicativo finale. - Per Windows, il file dell'icona ha estensione .ico extension - Per Mac OS, il file dell'icona è di tipo .icns |
||||||||||||||||||||||
Plugin |
Controllare la memoria disponibile
Quando si lavora con i blob, benché la loro dimensione può arrivare a 2GB, è necessario però controllare di avere memoria libera a sufficienza. Occorre farlo anche quando si utilizzano array prima di caricare una grande quantità di dati, perchè l'operazione potrebbe non andare a buon fine per problemi di spazio. A questo scopo, prima di fare operazioni di un certo tipo, si può controllare la disponibilità usando questo comando del plugin gratuito 4D Pack: AP AVAILABLE MEMORY (MemoriaTotale; MemoriaFisica; MemoriaDisponibile; StackDisponibile) Il comando AP AVAILABLE MEMORY ritorna le informazioni in bytes sulla memoria installata (totale e fisica) e su quella disponibile a 4D del computer corrente. Ritorna anche la quantità di spazio libero nello stack per il processo corrente. |
||||||||||||||||||||||
Codice |
Spostamento delle immagini in Picture Library
Non tutti hanno l'insider per spostare le immagini da un applicativo all'altro, questo metodo consente di copiarle da e verso un Table ARRAY LONGINT($Riferimento;0) ARRAY STRING(80;$Nomi;0) PICTURE LIBRARY LIST($Riferimento;$Nomi) If (True) ALL RECORDS([IMMAGINI]) While (Not(End selection([IMMAGINI]))) $i:=Find in array($Riferimento;[IMMAGINI]Riferimento) If ($i<1) SET PICTURE TO LIBRARY([IMMAGINI]Immagine;[IMMAGINI]Riferimento;[IMMAGINI]Nome) End if NEXT RECORD([IMMAGINI]) End while Else C_PICTURE($Picture) READ WRITE([IMMAGINI]) If (Size of array($Riferimento)>0) For ($i;1;Size of array($Riferimento)) GET PICTURE FROM LIBRARY($Riferimento{$i};$Picture) QUERY([IMMAGINI];[IMMAGINI]Riferimento=$Riferimento{$i}) If (Records in selection([IMMAGINI])=0) CREATE RECORD([IMMAGINI]) [IMMAGINI]Riferimento:=$Riferimento{$i} [IMMAGINI]Nome:=$Nomi{$i} [IMMAGINI]Immagine:=$Picture SAVE RECORD([IMMAGINI]) UNLOAD RECORD([IMMAGINI]) End if End for End if End if |
||||||||||||||||||||||
File |
Elenco Comuni Italiani
Elenco dei comuni italiani, con CAP, Provincia, Codice Fiscale, Codice Istat, Codice Inps. ComuniItaliani |
||||||||||||||||||||||
Novizi |
Iniziare a programmare con 4D
Segnaliamo un un'unica faq i link alle risorse con cui iniziare a farsi un'idea del funzionamento di 4D. La versione demo di 4th Dimension è scaricabile dal sito di 4D: fra i download proposti, scegliere la versione del file "4th Dimension vvvv" (mentre scriviamo vvvv sta per 2004) per la propria piattaforma: quella scaricata è la versione più recente del sistema di sviluppo e, se non avete acquistato 4D, potrete utilizzarlo tranquillamente e totalmente in modalità "Demo", l'unica limitazione è data dalla dimensione del progetto (come numero di tabelle/archivi/file e numero di method/procedure/scripts). Se siete studenti, insegnanti o organizzazioni no-profit, potete ottenere una versione di 4D gratis o ad un prezzo simbolico. Scaricato il file siete già pronti a partire: vediamo come fare ciò che vogliamo fare. Su questo sito si trova una sorta di "compendio breve" su 4D, inviato da Roberto Vergani, ecco i link: Prima introduzione a 4d: EVENTI e gerarchia esecuzione Prima introduzione a 4d: FILE E CAMPI Prima introduzione a 4d: FORMS [schermate] Prima introduzione a 4d: METODI [procedure, scripts] Prima introduzione a 4d: SUBTABLE Un manuale completo, Jumpstart 4D, in inglese, è segnalato in questa faq. |
||||||||||||||||||||||
Codice |
Calcolo lunghezza massima dei testi nei campi
Quando si importano in 4d file di testo la creazione delle tabelle viene fatto in automatico le lunghezze dei campi Alpha è di default 80. Ecco un metodo da usare per analizzare il contenuto di tutte le tabelle di un database per trovare per i campi testo o alpha la stringa più lunga (con l'esempio più lungo) e quante volte il campo è usato. `Nexus srl www.nexusonline.it `Umberto Migliore 29 nov 2005 READ ONLY(*) $doc:=Create document("") If (ok=1) $cr:=Char(Carriage return ) $tab:=Char(Tab ) For ($t;1;Count tables) $table_ptr:=Table($t) DEFAULT TABLE($table_ptr->) SEND PACKET($doc;Table name($t)+$tab+String(Records in table)+" recs"+$cr) $quanti:=Count fields($t) ARRAY LONGINT($quantiUsati_al;$quanti) ARRAY LONGINT($maxLun_al;$quanti) ARRAY TEXT($maxTesto_at;$quanti) For ($f;1;$quanti) $quantiUsati_al{$f}:=0 $maxLun_al{$f}:=0 $maxTesto_at{$f}:="" End for ALL RECORDS While (Not(End selection)) If (Mod(Selected record number;100)=0) MESSAGE(Table name($t)+": "+String(Selected record number)+"/"+String(Records in table)) End if For ($f;1;$quanti) $field_ptr:=Field($t;$f) If ((Type($field_ptr->)=Is Alpha Field ) | (Type($field_ptr->)=Is Text )) $text:=u_EliminaSpazi ($field_ptr->) $len:=Length($text) If ($len>0) $quantiUsati_al{$f}:=$quantiUsati_al+1 If ($len>$maxLun_al{$f}) $maxLun_al{$f}:=$len $maxTesto_at{$f}:=$text End if End if Else $maxLun_al{$f}:=-1 End if End for NEXT RECORD($table_ptr->) End while For ($f;1;$quanti) SEND PACKET($doc;Field name($t;$f)+$tab+String($quantiUsati_al{$f})+$tab+String($maxLun_al{$f})+$tab+$maxTesto_at{$f}+$cr) End for End for CLOSE DOCUMENT($doc) End if |
||||||||||||||||||||||
Tecniche |
Menu Quit su Mac OS X
4D 2004 su Mac OS X si occupa di spostare automaticamente il menu Quit dal suo posto nel menu File sotto il menu Application del Mac OS X. Basta assegnargli un metodo e lasciare l'azione automatica Quit. |
||||||||||||||||||||||
Info |
Le righe di output che scompaiono
Tra le novità "nascoste", nel senso di poco segnalate, della versione 2004, ne esiste una piccolissima riguardante i form di output che può in certi rari casi diventare un problema: andiamo con ordine. Fino alla versione 2003 le righe selezionate dei form di output venivano "colorate" di nero, utilizzando la tecnica della inversione per mostrare i colori. Dalla versione 2004 è possibile invece utilizzare il colore di selezione di sistema: queste opportunità, se da un lato risulta molto elegante, dall'altro può rivelarsi infernale se il colore di selezione di sistema è lo stesso di quello delle scritte del form di output: in questo caso infatti il testo delle righe selezionate "scompare", poiché uniforme al colore di selezione. Per poter utilizzare il sistema di "colorazione" precedente basta andare nelle proprietà del form, nella categoria "Form properties" e deselezionare la voce System Highlight Color |
||||||||||||||||||||||
Novizi |
Control flow nell'esecuzione di un metodo: profondità
Abbiamo analizzato i vari metodi di controllo di flusso di 4D. Le varie strutture sono variamente combinabili. È interessante notare come il limite di profondità nell'inserire tali strutture (If/While/For/Case of/Repeat) è di 512 livelli. |
||||||||||||||||||||||
Novizi |
Control flow nell'esecuzione di un metodo: ramificata
Una struttura ramificata (anche se il termine inglese Branching rende meglio l'idea) controlla il verificarsi o meno di una condizione per far prendere al codice "strade" diverse, valutando se una certa espressione restituisce un valore TRUE o FALSE. Un esempio di struttura ramificata è dato dalla sequenza If...Else...End if, dove il flusso del programma viene suddiviso in più percorsi. Altro esempio è dato dall'insieme di Case of...Else...End case, che invece suddivide l'esecuzione in più percorsi. |
||||||||||||||||||||||
Novizi |
Control flow nell'esecuzione di un metodo: ciclica
Una struttura ciclica viene utilizzata per eseguire più volte una certa quantità di codice. Per tale scopo, le strutture linguistiche usate sono: While...End while Repeat...Until For...End for I cicli sono controllati in due modi: o in base al verificarsi di una condizione o specificando il numero di cicli (anche se in realtà è possibile scmbiare i due sistemi senza problemi). Quindi la differenza sostanziale sta nel fatto che i While e i Repeat vengono eseguiti un numero indefinito di volte, mentre i cicli For vengono eseguiti un numero prestabilito di volte. |
||||||||||||||||||||||
Novizi |
Control flow nell'esecuzione di un metodo: sequenziale
Per quanto un metodo possa essere scritto in maniera semplice o complessa, i sistemi di scrittura del codice 4D (sistemi di controllo di flusso) sono sempre tre: Sequenziale Ramificato Ciclico cominciamo a entrare nel dettaglio. Il sistema sequenziale è dato dalla esecuzione lineare, sequenziale appunto, di una serie di istruzioni 4th Dimension: OUTPUT FORM([People]; "Listing") ALL RECORDS([People]) DISPLAY SELECTION([People]) Si può anche usare una istruzione o un comando in un'unica riga, è sempre programmazione sequenziale: [People]Last Name:=Uppercase([People]Last Name) |
||||||||||||||||||||||
Comandi |
Il comando SET BLOB SIZE
Il comando SET BLOB SIZE, la cui sintassi è: SET BLOB SIZE (blob; size{; filler}) permette di specificare una nuova dimensione size per il blob blob passato come parametro. Il comando è ad esempio usato per svuotare il contenuto di un blob. Il parametro opzionale filler permette di specificare, in caso di aumento di dimensione del blob, il codice ascii del carattere da utilizare per "riempire" i byte aggiunti. |
||||||||||||||||||||||
Tecniche |
Uso di Get pointer con gli array
Il comando Get pointer permette di ottenere un puntatore ad una variabile (processo o interprocesso) il cui nome viene passato come parametro al comando. Per ottenere puntatori a campi si utilizza Field, per i puntatori alle tabelle usare Table. Per gli array, è possibile usare i puntatori per operazioni del tipo INSERT ELEMENT o DELETE ELEMENT. Inoltre si possono passare puntatori ad elementi ben precisi degli array, ad esempio: Get pointer($ArrName+"{3}") mentre non è possibile puntare ad elementi variabili, come: Get pointer($ArrName+"{myVar}") Il comando risulta molto utile per gestire griglie di elementi; se ho una griglia di 5x10 variabili v1, v2, ...., v50, posso settare i valori così: For ($vlVar;1;50) $vpVar:=Get pointer("v"+String($vlVar)) $vpVar->:="" End for |
||||||||||||||||||||||
Info |
Vantaggi dell'overclocking su applicazioni 4th Dimension
Una delle attività preferite degli smanettoni su Windows è sicuramente quella dell'overclocking, ovvero l'agire sui parametri (ma a volte anche in maniera fisica) della scheda madre. Alcune delle tecniche più utilizzare sono la modifica dei voltaggi di funzionamento e la variazione delle frequenze di funzionamento insieme ai fattori moltiplicativi di queste frequenze. Tali azioni sono effettuabili solo su hardware ad alta affidabilità e comportano problemi accessori, come lo stress a cui vengono sottoposti i vari componenti e il surriscaldamento che tali modifiche comportano, per non dire la possibile instabilità della macchina. Ma allora quale vantaggio c'è nell'overclockare un computer? Semplicemente nella possibilità di ottenere un aumento di prestazioni fino al 50% utilizzando la stessa componentistica. Uno dei sistemi di valutazione più utilizzati per calcolare l'efficienza di un overclock è il calcolo di 1Mb o di 32MB di cifre decimali per "p greco". Ecco il link dove scaricarlo. Per testare la velocità di 4D con vari hardware uso solitamente il codice di questa faq su 500.000 record: ecco alcuni risultati. Alcuni dati di partenza: create 6361tick withDialog 11911tick export 1083tick Sostituendo il processore con uno avente un 6% di MHz in più e la scheda madre con una avente un bus più veloce del 20% ecco l'incremento dei risultati: create 5299tick withDialog 10817tick export 986tick Da notare che questi dati sono praticamente identici a quelli ottenuti da un server di ultimissima generazione zeppo di RAM e doppio processore (certo, viene usato solo uno dei quattro processori visto dal sistema operativo, speriamo in 4D 2007...), meno che per il test "withDialog", visto che la scheda video non è dedicata al refresh dello schermo. Ora, abbassando il fattore moltiplicativo del processore, alzandone di conseguenza l'FSB, e aumentando il voltaggio di memoria e scheda video, i risultati cambiano così: GLOBAL mm:ss:tt [500000 Inter] 00:05:09, 18557tick create 00:00:54, 3256tick withDialog 00:01:35, 5708tick export 00:00:13, 788tick import 00:01:14, 4446tick index 00:00:53, 3187tick qryMedium 00:00:01, 61tick qryLarge 00:00:01, 55tick qryDouble 00:00:05, 309tick orderSingle 00:00:00, 26tick orderDouble 00:00:12, 721tick Un incremento di prestazioni anche del 20% rispetto alla configurazione senza overclock! |
||||||||||||||||||||||
Plugin |
Conversione dei data types tra 4D Server e SQL
Il driver ODBC per 4D Server converte i tipi di dati 4D in ben precisi tipi di dati SQL secondo il seguente schema: Alpha SQL_VARCHAR Text SQL_LONGVARCHAR Real SQL_DOUBLE Integer SQL_SMALLINT Long Integer SQL_INTEGER Date SQL_DATE Time SQL_TIME Boolean SQL_BIT Picture SQL_LONGVARBINARY Subtable N/A BLOB N/A Questa invece la conversione dei tipi da una fonte ODBC SQL verso 4D Server: SQL_VARCHAR Alpha SQL_CHAR Alpha SQL_LONGVARCHAR Text SQL_REAL Real SQL_DOUBLE Real SQL_DECIMAL Real SQL_SMALLINT Integer SQL_TINYINT Integer SQL_INTEGER Long Integer SQL_LONGVARBINARY Picture SQL_DATE Date SQL_TIMESTAMP Date SQL_TIME Time SQL_BIT Boolean |
||||||||||||||||||||||
Codice |
Aprire le porte seriali con Serial ToolKit for 4D
A differenza di SET CHANNEL, che apre le porte seriali passando il numero di porta COM da usare, Serial ToolKit apre le porte in base al numero di COM installate, indipendentemente dal loro indirizzo: il che significa che potrei dover passare l'indirizzo 2 a Serial ToolKit per aprire la COM1. Per ottenere il mumero di porta corretto si usa la funzione STK_CountPorts per conoscere il numero di porte installate, e un ciclo ($i da 1 a STK_CountPorts) in cui chiedere a STK_GetIndPort se $i vale il numero corrispondente alla porta COM che ci interessa. |
||||||||||||||||||||||
Comandi |
Mostrare la posizione di un file o di una cartella
Dalla 2004.1 è disponibile il comando SHOW ON DISK per mostrare la posizione di un file o di una cartella. Il comando apre proprio la cartella del Finder su Mac o dell'Explorer su Windows. Il parametro passato può essere il nome di un file o di una cartella. SHOW ON DISK(“C:\\MiaCartella\\MioDocumento.txt”) SHOW ON DISK(“C:\\MiaCartella\\CartellaInterna) SHOW ON DISK(“Macintosh HD:MiaCartella:MioDocumento.txt”) SHOW ON DISK(“Macintosh HD:MiaCartella:CartellaInterna") Se si indica una cartella il Finder/Explorer ne mostrano la posizione; nel caso in cui la si volesse già aperta passare un secondo parametro *. SHOW ON DISK(“C:\\MiaCartella\\CartellaInterna”;*) SHOW ON DISK(“Macintosh HD:MiaCartella:CartellaInterna";*) |
||||||||||||||||||||||
Comandi |
Il verso di esecuzione dei comandi di comunicazione interprocesso
I comandi GET PROCESS VARIABLE, SET PROCESS VARIABLE and VARIABLE TO VARIABLE permettono di far comunicare fra di loro i processi. Tali comandi sono utilizzabili sia in versione monoutente che in modalità Client/Server. In quest'ultimo caso, è importante ricordare come le operazioni di lettura o scrittura avvengono solo nel verso "dal client al server": non è dunque possibile far comunicare direttamente fra di loro due client o eseguire le operazioni di lettura/scrittura dal server verso il client. |
||||||||||||||||||||||
Info |
Il numero di tabella
Molto spesso, ad esempio per le comunicazioni via 4D Open, risulta necessario conoscere il numero di tabella al di fuori di un metodo. Fra i sistemi possibili possiamo citare la possibilità di scrivere all'interno della voce Watch del Runtime Explorer "Table(->[Nome_tabella])"; oppure andare alla voce "Info su..." del menu "Help" in modalità Design, e alla voce "Database" vedere il numero delle varie tabelle. Dalla versione 2004, il numero di tabella si trova anche nella struttura, nella finestra di Proprietà della Tabella. |
||||||||||||||||||||||
Info |
Sfondo bianco per un'immagine
Ilaria Giagnoni ha segnalato una interessante info per la stampa delle picture: per ottenere delle immagini con sfondo bianco basta che la variabile contenente l'immagine sia impostata come "enterable". |
||||||||||||||||||||||
Codice |
Esporta descrizione struttura di una Tabella
C_LONGINT($Table_l;$i) DEFAULT TABLE([Strutture]) $Table_l:=Table(Current default table) $doc:=Create document("") If (ok=1) SEND PACKET($doc;"TABLE "+Table name($Table_l)+Char(Carriage return)) For ($i;1;Count fields($Table_l)) $t:=Type(Field($Table_l;$i)->) Case of : (($t=Is LongInt ) | ($t=Is Integer )) $tipo:="Long" : ($t=Is Real ) $tipo:="Real" : ($t=Is Alpha Field ) $tipo:="Alfa" : ($t=Is Text ) $tipo:="Text" : ($t=Is Boolean ) $tipo:="Bool" : ($t=Is Date ) $tipo:="Date" : ($t=Is Time ) $tipo:="Time" : ($t=Is Picture ) $tipo:="Pict" Else $tipo:="blob "+String($t) End case SEND PACKET($doc;Char(Tab)+$tipo+Field name($Table_l;$i)+Char(Carriage return)) End for CLOSE DOCUMENT($doc) End if |
||||||||||||||||||||||
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 | |||||||||||||||||||||
Codice |
Apertura di un file con 4D 2003
Le funzioni AP ShellExecute e AP Sublaunch, inserite o modificate a partire dal 4D Pack della versione 6.8.2, permettono di lanciare applicazioni esterne o aprire file. Ad esempio: $err:=AP ShellExecute ("C:\Test.doc") oppure $err:=AP ShellExecute ("MacHD:Test.doc") Ma si può anche fare in modo che il file venga aperto da una applicazione specifica, utilizzando ad esempio AP Sublaunch in questo modo: $err:=AP Sublaunch ("C:\\Programmi\\Microsoft Office\\OFFICE11\\WINWORD.EXE c:\\Test.doc") Per il lancio di applicazioni esterne con la versione 2004 vi rimando a questa faq. Per l'uso di "\\" per il passaggio di percorsi Windows vi rimando a questa faq. Per aprire una voce di Pannello di Controllo usando AP Sublaunch si può vedere questa faq. |
||||||||||||||||||||||
Codice |
Calcolo della varianza
Sempre da Math4D pubblichiamo il metodo per il calcolo della varianza di una serie, dove la serie è passata al metodo come puntatore ad un array. La varianza è data dalla formula: Sommatoria(x^2)/n - (Sommatoria(x)/n)^2 Ecco il metodo: $k:=Size of array($1->) $x2:=0 $x:=0 For ($i;1;$k) $x2:=$x2+($1->{$i}^2) `Sommatoria(x2) $x:=$x+$1->{$i} ` Sommatoria(x) End for $0:=$k*$x2 ` Dimensione array*Sommatoria(x^2) $0:=$0-($x^2) ` nSommatoria(x^2) - (Sommatoria(x))2 $0:=$0/($k^2) ` (nSommatoria(x2) - (Sommatoria(x))2) / n2 |
||||||||||||||||||||||
Tecniche |
Arrotondamenti dinamici per eccesso o per difetto
Il problema: trovare un sistema che consenta di effettuare degli arrotondamenti "intelligenti", cioé non allo zero, ma al 5 più vicino - se ho 23,61 deve restituire 23,60 - se ho 23,68 deve restituire 23,70 - se ho 23,66 deve restituire 23,65 Una formula che risolva il problema con un'unica istruzione è: Round($numero_r/0,05;0)*0,05 |
||||||||||||||||||||||
Codice |
Ottenere l'indirizzo IP
Il modo più semplice è usare il comando IT_MyTCPAddr del plugin 4d Internet Command (gratuito e incluso con 4d). Il comando richiede due parametri di tipo Stringa, dove il comando ritorna il numero IP corrente e la corrispondente maschera di Subnet. Ecco un esempio di utilizzo: C_TEXT($indirizzo_t;$subnet_t) C_LONGINT($errorCode_l) $errorCode_l := IT_MyTCPAddr ($indirizzo_t; $subnet_t) If ($errorCode_l =0) ALERT("IP address: " + $indirizzo_t + "\n" + "Subnet Mask: "+ $subnet_t) End if Questo è l'indirizzo con cui siete identificati nella rete locale; se però volete sapere qual'è l'indirizzo con cui siete visti su Internet il problema è più ampio. Se usate un modem vi viene assegnato un numero tutte le volte che telefonate; altrimenti nella maggior parte dei casi è il numero con cui il router accede ad internet. Per saperlo da programma è necessario utilizzare un server esterno che ci dica come ci vede: ad esempio potete usare il server Nexus WS Server con una semplice chiamata Web Service. Ecco un esempio con il codice in 4d per ottenere l'indirizzo ip pubblico. |
||||||||||||||||||||||
Codice |
Conversione da numero arabo a numero romano
Per completare l'argomento iniziato con la faq precedente ecco il metodo di conversione di un numero in notazione araba in notazione romana. C_STRING(255;$0;$risultatoRomano_S) C_INTEGER($1;$numeroArabo_I) C_BOOLEAN($finito_B) C_STRING(2;$decina_S;$cinquina_S;$unità_S) C_STRING(4;$prefissi_S) `inizializzazione $finito_B:=False $numeroArabo_I:=$1 $risultatoRomano_S:="" MATHERROR:=0 `calcolo Repeat $num:=$numeroArabo_I Case of : ($num>999) $prefissi_S:="M"*Num(Substring(String($numeroArabo_I);1;1)) : ($num>99) $unità_S:="C" $cinquina_S:="D" $decina_S:="M" : ($num>9) $unità_S:="X" $cinquina_S:="L" $decina_S:="C" Else $unità_S:="I" $cinquina_S:="V" $decina_S:="X" End case If ($num<1000) $num:=Num(Substring(String($numeroArabo_I);1;1)) $prefissi_S:="" Case of : ($num<4) $prefissi_S:=$unità_S*$num : ($num=4) $prefissi_S:=$unità_S+$cinquina_S : ($num=5) $prefissi_S:=$cinquina_S : ($num<9) $prefissi_S:=$cinquina_S+($unità_S*($num-5)) : ($num=9) $prefissi_S:=$unità_S+$decina_S End case End if $risultatoRomano_S:=$risultatoRomano_S+$prefissi_S $numeroArabo_I:=Num(Substring(String($numeroArabo_I);2)) $finito_B:=($numeroArabo_I<=0) Until ($finito_B=True) $0:=$risultatoRomano_S |
||||||||||||||||||||||
Codice |
Conversione da numero romano a numero arabo
Pubblichiamo di seguito una versione tradotta del metodo "MATH_RomainVersArabe" presente nella libreria Math4Dv2. il metodo prende come parametro una stringa in forma "romana" e restituisce l'equivalente in numeri arabi: C_STRING(80;$1) C_INTEGER($0;$risultatoArabo_L) `inizializzazione $numeroRomano_S:=$1 $risultatoArabo_L:=0 MATHERROR:=0 `calcolo Repeat Case of : ($numeroRomano_S[[1]]="M") $risultatoArabo_L:=$risultatoArabo_L+1000 $numeroRomano_S:=Substring($numeroRomano_S;2) : ($numeroRomano_S[[1]]="D") $risultatoArabo_L:=$risultatoArabo_L+500 $numeroRomano_S:=Substring($numeroRomano_S;2) : ($numeroRomano_S[[1]]="C") Case of : (Length($numeroRomano_S)=1) $risultatoArabo_L:=$risultatoArabo_L+100 $numeroRomano_S:="" : ($numeroRomano_S[[2]]="M") $risultatoArabo_L:=$risultatoArabo_L+900 $numeroRomano_S:=Substring($numeroRomano_S;3) : ($numeroRomano_S[[2]]="D") $risultatoArabo_L:=$risultatoArabo_L+400 $numeroRomano_S:=Substring($numeroRomano_S;3) Else $risultatoArabo_L:=$risultatoArabo_L+100 $numeroRomano_S:=Substring($numeroRomano_S;2) End case : ($numeroRomano_S[[1]]="L") $risultatoArabo_L:=$risultatoArabo_L+50 $numeroRomano_S:=Substring($numeroRomano_S;2) : ($numeroRomano_S[[1]]="X") Case of : (Length($numeroRomano_S)=1) $risultatoArabo_L:=$risultatoArabo_L+10 $numeroRomano_S:="" : ($numeroRomano_S[[2]]="C") $risultatoArabo_L:=$risultatoArabo_L+90 $numeroRomano_S:=Substring($numeroRomano_S;3) : ($numeroRomano_S[[2]]="L") $risultatoArabo_L:=$risultatoArabo_L+40 $numeroRomano_S:=Substring($numeroRomano_S;3) Else $risultatoArabo_L:=$risultatoArabo_L+10 $numeroRomano_S:=Substring($numeroRomano_S;2) End case : ($numeroRomano_S[[1]]="V") $risultatoArabo_L:=$risultatoArabo_L+5 $numeroRomano_S:=Substring($numeroRomano_S;2) : ($numeroRomano_S[[1]]="I") Case of : (Length($numeroRomano_S)=1) $risultatoArabo_L:=$risultatoArabo_L+1 $numeroRomano_S:="" : ($numeroRomano_S[[2]]="X") $risultatoArabo_L:=$risultatoArabo_L+9 $numeroRomano_S:=Substring($numeroRomano_S;3) : ($numeroRomano_S[[2]]="V") $risultatoArabo_L:=$risultatoArabo_L+4 $numeroRomano_S:=Substring($numeroRomano_S;3) Else $risultatoArabo_L:=$risultatoArabo_L+1 $numeroRomano_S:=Substring($numeroRomano_S;2) End case Else MATHERROR:=-1 `numero inesistente $numeroRomano_S:="" $risultatoArabo_L:=0 End case Until ($numeroRomano_S="") $0:=$risultatoArabo_L Autori, redattori e collaboratori per Math4Dv2: Jacques Bossy Philip Burns Olivier Deschanels Marc Duc-Jacquet Bernard Escaich Antoine Galmiche Micaël Germann Teddy Linet Frédéric Quoirez Michel Saiz Robert Van Loo |
||||||||||||||||||||||
Codice |
Leggere i tag ID3 di un file MP3
Tutto quello che serve per ascoltare un file MP3 è un lettore di file MP3! All'interno di questi file sono celate delle informazioni suppletive sul brano. Un esempio di struttura di tali tag: 000-002 03 bytes TAG ID -> "TAG" 003-032 30 bytes Titolo del brano 033-062 30 bytes Nome dell'interprete 063-092 30 bytes Album 093-096 04 bytes Anno 097-127 30 bytes Commenti 128-128 01 byte Tipo Utilizzando i comandi Open document, SET DOCUMENT POSITION e RECEIVE PACKET possiamo scriverci un metodo che inserisce in un array (passato come secondo parametro) i tag ID3 di un file MP3 (il cui percorso completo viene passato come primo parametro). C_TEXT($1) `percorso del file C_POINTER($2) `puntatore all'array con 7 posti che riceve i tag C_TEXT($MyText) C_STRING(3;$Tag) C_LONGINT($MyOffset) $RefDoc:=Open document($1;"") If (ok=1) `Leggo gli ultimi 128 bytes del file MP3 SET DOCUMENT POSITION($RefDoc;-128;2) RECEIVE PACKET($RefDoc;$MyText;500) CLOSE DOCUMENT($RefDoc) $Tag:=$MyText[[1]]+$MyText[[2]]+$MyText[[3]] If ($Tag="TAG") `c'è un tag MP3 $2->{1}:=EliminaSpazi (Substring($MyText;4;30)) $2->{2}:=EliminaSpazi (Substring($MyText;34;30)) $2->{3}:=EliminaSpazi (Substring($MyText;64;30)) $2->{4}:=EliminaSpazi (Substring($MyText;94;4)) $2->{5}:=EliminaSpazi (Substring($MyText;98;30)) If ((Ascii(Substring($MyText;128;1))+1)<=Size of array(<>tType)) $2->{6}:=<>tType{Ascii(Substring($MyText;128;1))+1} End if Else ALERT("No MP3 Tag.") End if $2->{7}:=$1 End if Il metodo EliminaSpazi si trova in questa faq. |
||||||||||||||||||||||
Codice |
Cambiare logo nei formati
A volte capita di modificare il logo nei formati, questo metodo magari non risolve tutte le casistiche ma ridimension |