Naviga: |
Ho trovato 835 faq.
Categoria | Argomento | Commenti | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Comandi deprecati aggiornati alla v19
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Convertire numeri arabi in numeri romani
Di seguito lo sviluppo di un algoritmo per la conversione di un numero arabo in numero romano. Il testo romano viene generato da destra a sinistra //u_DaAraboARomano //-------------------------- If (Count parameters=0) $romano:=u_DaAraboARomano (87) //per test Else $number:=$1 $udigits:="IVXLCDM" $romano:="" $posizione:=1 Repeat $modulo:=$number%10 If (($modulo%5)<4) For ($i;($modulo%5);1;-1) $romano:=$udigits[[$posizione]]+$romano End for End if If (($modulo>=4) & ($modulo<=8)) $romano:=$udigits[[$posizione+1]]+$romano End if If ($modulo=9) $romano:=$udigits[[$posizione+2]]+$romano End if If ($modulo%5=4) $romano:=$udigits[[$posizione]]+$romano End if $number:=Trunc($number/10;0) $posizione:=$posizione+2 Until ($number<=0) $0:=$romano End if |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Check Digit Ean13/Ean8
// calcola il check digit del codice ean // se il codice ean è di 8 o 13 caratteri elimino un carattere e ricalcolo il check digit C_TEXT($check;$ritorno;$codice) C_COLLECTION($strParts) C_LONGINT($lngIndex;$intTotal;$intCount;$intUp As;$elementi;$modoup) If (Undefined($1)) $0:="" End if If ($1="") $0:="" End if $codice:=$1 If (Length($codice)=13) $codice:= prendiSinistra($codice;12) End if If (Length($codice)=8) $codice:= prendiSinistra($codice;7) End if $codice:=$codice+"C" $strParts:=Split string($codice;"") $elementi:=$strParts.length For ($lngIndex;$elementi-2;0;-2) For ($intCount;1;3) $intTotal:=$intTotal+Num($strParts[$lngIndex]) End for End for $lngIndex:=13 For ($lngIndex;$elementi-1;0;-2) $intTotal:=$intTotal+Num($strParts[$lngIndex]) End for $intUp:=$intTotal Repeat $intUp:=$intUp+1 $modoup:=Mod($intUp;10) Until ($modoup=0) $check:=String($intUp-$intTotal) For ($lngIndex;0;$elementi-2) $ritorno:=$ritorno+$strParts[$lngIndex] End for $ritorno:=$ritorno+$check $0:=$ritorno Sotto il codice per le funzioni prendiSinistra/prendiDestra ---- prendiSinistra ------ // $1=testo // $2=lunghezza // $0=testo left If ($2=0) $0:="" End if C_LONGINT($lungo) $lungo:=Length($1) If ($lungo=0) $0:="" End if $0:=Substring($1;1;$2) ---- prendiDestra ---- // $1=testo // $2=lunghezza // $0=testo right If ($2=0) $0:="" End if $lunghezza:=Length($1) If ($lunghezza=0) $0:="" End if $lunghezza:=Length($1) $0:=Substring($1;$lunghezza-$2+1;$2) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Numeri a lettere
Ritorna il numero in formato lettera come ad esempio per gli assegni bancari : 1234,56 = MilleDuecentoTrentaQuattro//56 C_TEXT($result;$risultato;$intero) // il dato passato è un numero double che devo trasformare in un formato italiano $intero:=String($1;"###########0.00") // $intero:=$1 // importo in lettere C_TEXT($resto) C_LONGINT($lungo) $lungo:=Length($intero) C_LONGINT($decimale) $decimale:=Position(",";$intero) $resto:="/"+tright ($intero;2) $intero:=tleft ($intero;$decimale-1) C_TEXT($verifica) $verifica:=Substring($intero;1;1) If ($verifica="-") $intero=Mid(intero, 2) End if If ($1=0) $0="zero/00" End if C_LONGINT($mille) $mille:=-1 C_LONGINT($k) $k:=Mod(Length($intero);3) If ($k#0) $intero=Repeate (3-$k,"0")+$intero End if While ($intero#"") $mille:=$mille+1 C_TEXT($parziale;$tripla;$s) C_LONGINT($tv;$td; $tc) C_LONGINT($x;$y) $tripla:=tright ($intero;3) $intero:=tleft ($intero;Length($intero)-3) $tv:=Num($tripla) $td:=Mod($tv;100) $tc:=($tv-$td)/100 If (Not($tc=0) $parziale:="cento" If ($tc>1) $parziale:=unita ($tc)+$parziale End if End if If ($td<20) $parziale:=$parziale+unita ($td) Else $x:=Mod($td;10) $y:=($td-$x)/10 $parziale:=$parziale+decine ($y) $s:=unita ($x) $primoc:=tleft ($s;1) $instr:=Position($primoc;"uo";1) If ($instr#0) If ($s#"") If (Not$y=0) $parziale:=tleft ($parziale;Length($parziale-1)) End if End if End if $parziale:=$parziale+$s End if $s:=migliaia ($mille) If ($mille>0) If ($parziale#"") $k:=$mille If ($parziale#"uno") $k:=$k+4 $s:=migliaia ($k) $ddestra:=tright ($parziale;3) If ($ddestra="uno") $parziale:=tleft ($parziale;Length($parziale)-1) End if Else $parziale:="" End if $parziale:=$parziale+$s End if End if $result:=$parziale+$result End while If ($1<0) $result="meno"+$result End if $0:=$result+$resto E di seguito le varie altre funzioni utilizzate : --- Repeate --- C_TEXT($testo) C_LONGINT($contatore) For ($contatore;1;$1) $testo:=$testo+$2 End for $0:=$testo --- unita --- C_COLLECTION($lettere) C_TEXT($risultato) $lettere:=Split string(",uno,due,tre,quattro,cinque,sei,sette,otto,nove,dieci,undici,dodici,tredici,quattordici,quindici,sedici,diciassette,diciotto,diciannove";",") C_LONGINT($lunghezza) $lunghezza:=$lettere.length If ($1<0) $risultato:="" Else If ($1>$lunghezza) $risultato:="" Else $risultato:=$Lettere[$1] End if End if $0:=$risultato --- migliaia --- C_COLLECTION($lettere) C_TEXT($risultato) $lettere:=Split string(",mille,unmilione,unmiliardo,millemiliardi,mila,milioni,miliardi,milamiliardi,milamiliardi,migliaiadimiliardi";",") C_LONGINT($lunghezza) $lunghezza:=$lettere.length If ($1<0) $risultato:="" Else If ($1>$lunghezza) $risultato:="" Else $risultato:=$Lettere[$1] End if End if $0:=$risultato --- isnumeric --- If (Undefined($1)) $0=False End if $lettera:=$1 $numero:=Num($lettera) $letteranunero:=String($numero) If (Substring($lettera;1;1)="0") $letteranunero:="0"+$letteranunero End if If (Length($lettera)=Length($letteranunero) $0:=True Else $0:=False End if --- decine ---- C_COLLECTION($lettere) C_TEXT($risultato) C_LONGINT($lunghezza) $lettere:=Split string(",dieci,venti,trenta,quaranta,cinquanta,sessanta,settanta,ottanta,novanta";",") $lunghezza:=$lettere.length If ($1<0) $risultato:="" Else If ($1>$lunghezza) $risultato:="" Else $risultato:=$Lettere[$1] End if End if $0:=$risultato --- tleft ---- // $1=testo // $2=lunghezza // $0=testo left If ($2=0) $0:="" End if C_LONGINT($lungo) $lungo:=Length($1) If ($lungo=0) $0:="" End if $0:=Substring($1;1;$2) --- tright --- // $1=testo // $2=lunghezza // $0=testo right If ($2=0) $0:="" End if $lunghezza:=Length($1) If ($lunghezza=0) $0:="" End if $lunghezza:=Length($1) $0:=Substring($1;$lunghezza-$2+1;$2) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Controllo Codice Fiscale
Questo metodo ritorna Vero se il codice fiscale passato è scritto correttamente, utilizzando il carattere di controllo finale. La procedura è un po' condensata: per l'algoritmo di controllo completo potete trovare il dettaglio sul sito del Ministero delle Finanze. `Metodo Controllo_CodiceFiscale `controlla il checksum del codice fiscale `Nexus srl 4-6-90 C_LONGINT($i;$n_l;$car_l;$cod_l) C_STRING(16;$cf_s;$1) C_STRING(43;$mysndcod_s) $cf_s:=$1 If (Length($cf_s)#16) $0:=False Else $n_l:=0 For ($i;2;14;2) $car_l:=Ascii($cf_s[[$i]]) Case of : (($car_l>=48) & ($car_l<=57)) $cod_l:=$car_l-48 : (($car_l>=65) & ($car_l<=90)) $cod_l:=$car_l-65 Else $cod_l:=0 End case $n_l:=$n_l+$cod_l End for $mysndcod_s:="BAFHJNPRTVUMBERTOBAFHJNPRTVCESULDGIMOQKWZYX" For ($i;1;15;2) $car_l:=Ascii($cf_s[[$i]])-47 $cod_l:=Ascii($mysndcod_s[[$car_l]])-65 $n_l:=$n_l+$cod_l End for $0:=((65+$n_l-(Int($n_l/26)*26))=Ascii($cf_s[[16]])) End if |
3 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Calcolo del codice fiscale
La funzione per il calcolo del codice fiscale : Nota : occorre il database con i comuni e relativi codici istat. ---- calcolocodicefiscale ---- // dati da passare per il calcolo // $1:Nome;$2:Cognome;$3:data in formato testo;$4:sesso M o F;$5:codice istat comune // ritorno il codice fiscale $nome:=$1 $cognome:=$2 $data:=$3 $sesso:=$4 $comune:=$5 $inome:="" $icognome:="" $icomune:="" $controllo:="" $temp:="" $letteracod:="" //prendi le iniziali del nome //ccc As int32=1 $lungnome:=0 For ($lungnome;1;Length($nome)) $temp:=Lowercase(Substring($nome;$lungnome;1)) Case of : $temp="b" $inome:=$inome+$temp : $temp="c" $inome:=$inome+$temp : $temp="d" $inome:=$inome+$temp : $temp="f" $inome:=$inome+$temp : $temp="g" $inome:=$inome+$temp : $temp="h" $inome:=$inome+$temp : $temp="j" $inome:=$inome+$temp : $temp="k" $inome:=$inome+$temp : $temp="l" $inome:=$inome+$temp : $temp="m" $inome:=$inome+$temp : $temp="n" $inome:=$inome+$temp : $temp="p" $inome:=$inome+$temp : $temp="q" $inome:=$inome+$temp : $temp="r" $inome:=$inome+$temp : $temp="s" $inome:=$inome+$temp : $temp="t" $inome:=$inome+$temp : $temp="v" $inome:=$inome+$temp : $temp="w" $inome:=$inome+$temp : $temp="x" $inome:=$inome+$temp : $temp="y" $inome:=$inome+$temp : $temp="z" $inome:=$inome+$temp End case End for If (Length($inome)>=4) $temp:=Lowercase($inome) $inome:=Substring($temp;1;1)+Substring($temp;3;1)+Substring($temp;4;1) End if //controlla la lunghezza delle iniziali If (Length($inome)>3) $inome:=Substring($inome;1;3) Else If (Length($inome)<3) For $lungnome(1;Length($nome)) $letteracod:=Substring($nome;$lungnome;1) Case of : $letteracod="a" $inome:=$inome+"a" : $letteracod="e" $inome:=$inome+"e" : $letteracod="i" $inome:=$inome+"i" : $letteracod="o" $inome:=$inome+"o" : $letteracod="u" $inome:=$inome+"u" End case End for If (Length($inome)>3) $inome:=Substring($inome;1;3) If (Length($inome)<3) For ($lungnome;Length($inome);3) $inome:=$inome+"x" End for End if End if End if End if // prendi lettere del cognome For ($lungnome;1;Length($cognome)) $temp:=Lowercase(Substring($cognome;$lungnome;1)) Case of : $temp="b" $icognome:=$icognome+$temp : $temp="c" $icognome:=$icognome+$temp : $temp="d" $icognome:=$icognome+$temp : $temp="f" $icognome:=$icognome+$temp : $temp="g" $icognome:=$icognome+$temp : $temp="h" $icognome:=$icognome+$temp : $temp="j" $icognome:=$icognome+$temp : $temp="k" $icognome:=$icognome+$temp : $temp="l" $icognome:=$icognome+$temp : $temp="m" $icognome:=$icognome+$temp : $temp="n" $icognome:=$icognome+$temp : $temp="p" $icognome:=$icognome+$temp : $temp="q" $icognome:=$icognome+$temp : $temp="r" $icognome:=$icognome+$temp : $temp="s" $icognome:=$icognome+$temp : $temp="t" $icognome:=$icognome+$temp : $temp="v" $icognome:=$icognome+$temp : $temp="w" $icognome:=$icognome+$temp : $temp="x" $icognome:=$icognome+$temp : $temp="y" $icognome:=$icognome+$temp : $temp="z" $icognome:=$icognome+$temp End case End for // controlla la lunghezza delle iniziali If (Length($icognome)>3) $icognome:=Substring($icognome;1;3) Else If (Length($icognome)<3) // minore di tre cifre prendi anche le vocali For ($lungnome;1;Length($cognome)) letteracod:=Substring($cognome;$lungnome;1) Case of : $letteracod="a" $icognome:=$icognome+"a" : $letteracod="e" $icognome:=$icognome+"e" : $letteracod="i" $icognome:=$icognome+"i" : $letteracod="o" $icognome:=$icognome+"o" : $letteracod="u" $icognome:=$icognome+"u" End case End for If (Length($icognome)>3) $icognome:=Substring($icognome;1;3) Else If (Length($icognome)<3) For ($lungnome;Length($icognome);3) $icognome:=$icognome+"x" End for End if End if End if End if // Dim idata, gg, mm, aa As String // temp=data // Dim tempn As string ARRAY TEXT($ddata;0) C_COLLECTION($detta) $detta:=Split string($data;"/") COLLECTION TO ARRAY($detta;$ddata) $gg:=$ddata{1} $mm:=$ddata{2} If (Length($ddata{3})=2) $aa:=$ddata{3} Else $aa:=Substring($ddata{3};3;2) End if $idata:=$aa //MsgBox("TEMP"+temp) Case of : $mm="01" $idata:=$idata+"a" : $mm="02" $idata:=$idata+"b" : $mm="03" $idata:=$idata+"c" : $mm="04" $idata:=$idata+"d" : $mm="05" $idata:=$idata+"e" : $mm="06" $idata:=$idata+"h" : $mm="07" $idata:=$idata+"l" : $mm="08" $idata:=$idata+"m" : $mm="09" $idata:=$idata+"p" : $mm="10" $idata:=$idata+"r" : $mm="11" $idata:=$idata+"s" : $mm="12" $idata:=$idata+"t" End case If ($sesso="M") $idata:=$idata+$gg Else If ($sesso="F") $idata:=$idata+String(Num($gg)+40) End if End if C_LONGINT($vdis) // codice parziale per calcolare ultima cifra $parz:=Lowercase($icognome+$inome+$idata+$comune) // trova il carattere di verificca For ($lungnome;1;15;2) $d:=Substring($parz;$lungnome;1) Case of : $d="0" $vdis:=$vdis+1 : $d="1" $vdis:=$vdis+0 : $d="2" $vdis:=$vdis+5 : $d="3" $vdis:=$vdis+7 : $d="4" $vdis:=$vdis+9 : $d="5" $vdis:=$vdis+13 : $d="6" $vdis:=$vdis+15 : $d="7" $vdis:=$vdis+17 : $d="8" $vdis:=$vdis+19 : $d="9" $vdis:=$vdis+21 : $d="a" $vdis:=$vdis+1 : $d="b" $vdis:=$vdis+0 : $d="c" $vdis:=$vdis+5 : $d="d" $vdis:=$vdis+7 : $d="e" $vdis:=$vdis+9 : $d="f" $vdis:=$vdis+13 : $d="g" $vdis:=$vdis+15 : $d="h" $vdis:=$vdis+17 : $d="i" $vdis:=$vdis+19 : $d="j" $vdis:=$vdis+21 : $d="k" $vdis:=$vdis+2 : $d="l" $vdis:=$vdis+4 : $d="m" $vdis:=$vdis+18 : $d="n" $vdis:=$vdis+20 : $d="o" $vdis:=$vdis+11 : $d="p" $vdis:=$vdis+3 : $d="q" $vdis:=$vdis+6 : $d="r" $vdis:=$vdis+8 : $d="s" $vdis:=$vdis+12 : $d="t" $vdis:=$vdis+14 : $d="u" $vdis:=$vdis+16 : $d="v" $vdis:=$vdis+10 : $d="w" $vdis:=$vdis+22 : $d="x" $vdis:=$vdis+25 : $d="y" $vdis:=$vdis+24 : $d="z" $vdis:=$vdis+23 End case End for C_LONGINT($vpar) For ($lungnome;2;14;2) $p:=Substring($parz;$lungnome;1) Case of : $p="0" $vpar:=$vpar+0 : $p="1" $vpar:=$vpar+1 : $p="2" $vpar:=$vpar+2 : $p="3" $vpar:=$vpar+3 : $p="4" $vpar:=$vpar+4 : $p="5" $vpar:=$vpar+5 : $p="6" $vpar:=$vpar+6 : $p="7" $vpar:=$vpar+7 : $p="8" $vpar:=$vpar+8 : $p="9" $vpar:=$vpar+9 : $p="a" $vpar:=$vpar+0 : $p="b" $vpar:=$vpar+1 : $p="c" $vpar:=$vpar+2 : $p="d" $vpar:=$vpar+3 : $p="e" $vpar:=$vpar+4 : $p="f" $vpar:=$vpar+5 : $p="g" $vpar:=$vpar+6 : $p="h" $vpar:=$vpar+7 : $p="i" $vpar:=$vpar+8 : $p="j" $vpar:=$vpar+9 : $p="k" $vpar:=$vpar+10 : $p="l" $vpar:=$vpar+11 : $p="m" $vpar:=$vpar+12 : $p="n" $vpar:=$vpar+13 : $p="o" $vpar:=$vpar+14 : $p="p" $vpar:=$vpar+15 : $p="q" $vpar:=$vpar+16 : $p="r" $vpar:=$vpar+17 : $p="s" $vpar:=$vpar+18 : $p="t" $vpar:=$vpar+19 : $p="u" $vpar:=$vpar+20 : $p="v" $vpar:=$vpar+21 : $p="w" $vpar:=$vpar+22 : $p="x" $vpar:=$vpar+23 : $p="y" $vpar:=$vpar+24 : $p="z" $vpar:=$vpar+25 End case End for // somma dei valori ottenuti dal dispari e dal pari $vdisparsomma:=$vdis+$vpar // --------------------- // vdisparsomma=148 // --------------------- // diviso 26, troviamo il resto $restov:=Mod($vdisparsomma;26) Case of $restov : $restov=0 $controllo:="a" : $restov=1 $controllo:="b" : $restov=2 $controllo:="c" : $restov=3 $controllo:="d" : $restov=4 $controllo:="e" : $restov=5 $controllo:="f" : $restov=6 $controllo:="g" : $restov=7 $controllo:="h" : $restov=8 $controllo:="i" : $restov=9 $controllo:="j" : $restov=10 $controllo:="k" : $restov=11 $controllo:="l" : $restov=12 $controllo:="m" : $restov=13 $controllo:="n" : $restov=14 $controllo:="o" : $restov=15 $controllo:="p" : $restov=16 $controllo:="q" : $restov=17 $controllo:="r" : $restov=18 $controllo:="s" : $restov=19 $controllo:="t" : $restov=20 $controllo:="u" : $restov=21 $controllo:="v" : $restov=22 $controllo:="w" : $restov=23 $controllo:="x" : $restov=24 $controllo:="y" : $restov=25 $controllo:="z" End case // fai il codice fiscale $codicefiscale:=Uppercase($parz+$controllo) $0:=$codicefiscale |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Cercafield : Query veloce lookup
// ritorna i dati da una tabella non correlata // $1 campo, $2 chiave, $3 tabella, $4 $filtro C_TEXT($campo) // è il campo che utilizzo per la ricerca C_TEXT($chiave) // è la chiave cioè il campo che voglio sia ritornato C_TEXT($tabella) // è il nome della tabella per la quale voglio effettuare la ricerca C_TEXT($filtro) // eventuale filtro WHERE C_TEXT($risultato) $campo:=$1 $chiave:=$2 $tabella:=$3 $filtro:=$4 SQL LOGIN(SQL_INTERNAL;"";"") C_LONGINT($ffiltro) $ffiltro:=Position($filtro;"%") If ($ffiltro>0) $filtro:=Char(Quote)+$filtro+Char(Quote) SQL EXECUTE("SELECT DISTINCT "+$chiave+" FROM "+$tabella+" WHERE "+$campo+" LIKE "+$filtro;$risultato) Else $filtro:=Char(Quote)+$filtro+Char(Quote) SQL EXECUTE("SELECT DISTINCT "+$chiave+" FROM "+$tabella+" WHERE "+$campo+" = "+$filtro;$risultato) End if SQL LOAD RECORD(SQL all records) SQL LOGOUT $0:=$risultato{0} |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Interaleave 2of5 codice per ottenere binario del codice
Il presente codice serve per ricavare il codice binario del codice 2 of 5 per poter poi disegnare il barcode in SVG (0) linea sottile, (1) linea spessa C_TEXT($K) C_TEXT($strCode) C_TEXT($strAux) C_TEXT($strExit) $strCode:=$1 $strAux:=$strCode If ($strCode="") $0:="" End if For ($K=1;(Length($strCode)) C_TEXT($codice) $codice:=Substring($strAux;$K;1) Case of : $codice="0" : $codice="1" : $codice="2" : $codice="3" : $codice="4" : $codice="5" : $codice="6" : $codice="7" : $codice="8" : $codice="9" : $codice="@" : $codice="§" // ok il codice non contiene caratteri non validi Else Alert("Errore il codice interleave 2 of 5 contiene caratteri non ammessi, sono ammessi solo numeri da 0-9) $0:="" End case End for For($K;1;length($strCode)) C_TEXT($codice) $codice:=Substring($strCode;$K;1) Case of : ="1" $strExit:=$strExit+"11010010010110" : ="2" $strExit:=$strExit+"11010101001100" : ="3" $strExit:=$strExit+"11001010100110" : ="4" $strExit:=$strExit+"11010010100110" : ="5" $strExit:=$strExit+"10110100100110" : ="6" $strExit:=$strExit+"10011010101100" : ="7" $strExit:=$strExit+"10110010101100" : ="8" $strExit:=$strExit+"10011001010110" : ="9" $strExit:=$strExit+"10110100101100" : ="0" $strExit:=$strExit+"11001010010110" : ="@" $strExit:=$strExit+"10110010110010" : ="§" $strExit:=$strExit+"11010000000000" End case // salto End for $0:=$strExit |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Ean2Bin
Funzione utile per ricavare una stringa come questa riferita al codice EAN 13 o EAN 8 : 00010100011010100111000110100100010100111010001101010111001011011001001110101110010100001101100101000 è possibile poi dividere la stringa e disegnare con SVG linee verticali di spessore normale (0) e spessore doppio (1) per ricavare l'immagine del barcode. $1 è il codice EAN ( se è lungo 12 o 7 caratteri inserire anche il metodo checkdigit, lo trovate in questo forum). C_LONGINT($K) C_TEXT($strAux) C_TEXT($strExit) C_TEXT($strCode) C_TEXT($strEANCode) $strAux:=$1 $strEANCode:=$1 // se ho passato il codice ean senza check digit lo calcolo If (Length($strAux)=12) $strEANCode:=Ean138CheckDigit ($strEANCode) Else If (Length($strAux)=7) $strEANCode:=Ean138CheckDigit ($strEANCode) End if End if $strAux:=$strEANCode If (Not(isnumeric ($strAux))) ALERT("Attenzione, il barcode contiene caratteri non validi") $0:="" End if If (Length($strAux)=13) // verifico che sia un EAN 13 // per prima cosa scarto la prima cifra che è lo stato di emissione(fare riferimento ad INDICOD ' $strAux:=Substring($strAux;2) C_LONGINT($numero) $numero:=Num(tleft ($strEANCode;1)) Case of : $numero=0 $strCode:="000000" : $numero=1 $strCode:="001011" : $numero=2 $strCode:="001101" : $numero=3 $strCode:="001110" : $numero=4 $strCode:="010011" : $numero=5 $strCode:="011001" : $numero=6 $strCode:="011100" : $numero=7 $strCode:="010101" : $numero=8 $strCode:="010110" : $numero=9 $strCode:="011010" End case Else $strCode:="0000" End if // //Il codice EAN inizia con un carattere iniziale // $strExit:="000101" // //Prima metà del codice // For ($K;1;Length($strAux)\2) C_TEXT($code) C_LONGINT($numero) $code:=Substring($strCode;$K;1) $numero:=Num(Substring($strAux;$K;1)) Case of : $numero=0 C_TEXT($temptext) If ($code="0") $temptext:="0001101" Else $temptext:="0100111" End if $strExit:=$strExit+$temptext : $numero=1 C_TEXT($temptext) If ($code="0") $temptext:="0011001" Else $temptext:="0110011" End if $strExit:=$strExit+$temptext : $numero=2 C_TEXT($temptext) If ($code="0") $temptext:="0010011" Else $temptext:="0011011" End if $strExit:=$strExit+$temptext : $numero=3 C_TEXT($temptext) If ($code="0") $temptext:="0111101" Else $temptext:="0100001" End if $strExit:=$strExit+$temptext : $numero=4 C_TEXT($temptext) If ($code="0") $temptext:="0100011" Else $temptext:="0011101" End if $strExit:=$strExit+$temptext : $numero=5 C_TEXT($temptext) If ($code="0") $temptext:="0110001" Else $temptext:="0111001" End if $strExit:=$strExit+$temptext : $numero=6 C_TEXT($temptext) If ($code="0") $temptext:="0101111" Else $temptext:="0000101" End if $strExit:=$strExit+$temptext : $numero=7 C_TEXT($temptext) If ($code="0") $temptext:="0111011" Else $temptext:="0010001" End if $strExit:=$strExit+$temptext : $numero=8 C_TEXT($temptext) If ($code="0") $temptext:="0110111" Else $temptext:="0001001" End if $strExit:=$strExit+$temptext : $numero=9 C_TEXT($temptext) If ($code="0") $temptext:="0001011" Else $temptext:="0010111" End if $strExit:=$strExit+$temptext End case End for // // Prosegue poi con un separatore di mezzo // $strExit:=$strExit+"01010" // // Seconda metà del codice // For ($K;Length($strAux)\2+1;Length($strAux)) C_LONGINT($numero) $numero:=Num(Substring($strAux;$K;1)) Case of : $numero=0 $strExit:=$strExit+"1110010" : $numero=1 $strExit:=$strExit+"1100110" : $numero=2 $strExit:=$strExit+"1101100" : $numero=3 $strExit:=$strExit+"1000010" : $numero=4 $strExit:=$strExit+"1011100" : $numero=5 $strExit:=$strExit+"1001110" : $numero=6 $strExit:=$strExit+"1010000" : $numero=7 $strExit:=$strExit+"1000100" : $numero=8 $strExit:=$strExit+"1001000" : $numero=9 $strExit:=$strExit+"1110100" End case End for // Il Codice EAN finisce con un separatore finale $strExit:=$strExit+"101000" $0:=$strExit |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Sconti composti
Gli sconti composti sono gli sconti commerciali ad esempio 50+20+3 oppure 50+20-3 ( applico lo sconto del 50+20 con un amento del 3% ). per l'utilizzo : $importoscontato:=scontocommerciale(126.34,"50+20+3") --- scontocommerciale --- // ricava lo sconto in base alla stringa // $1 importo // $2 sconto // ritorno l'importo scontato su $0 If ($2="") If ($1=0) $0:=0 Else $0:=$1 End if End if $scontotxt:=$2 $scontotxt:=Replace string($scontotxt;"+";"§+") $scontotxt:=Replace string($scontotxt;"-";"§-") C_COLLECTION($sconti) ARRAY TEXT($ssconti;0) C_REAL($importoscontato;$scontopercento) $sconti:=Split string($scontotxt;"§") COLLECTION TO ARRAY($sconti;$ssconti) $elementi:=Size of array($ssconti) $importoscontato:=$1 For ($contatore;1;$elementi) $scontopercento:=Num($ssconti{$contatore}) $sconto:=$importoscontato*$scontopercento/100 $importoscontato:=$importoscontato-$sconto End for $0:=$importoscontato |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
[v15] Limitazione automatica dei log
Con il comando SET DATABASE PARAMETER e il parametro Circular log limitation si può gestire il massimo numero di file di log dia tenere in rotazione automatica per tipo di log. Il numero passato limita il numero di file presenti, con la cancellazione automatica del più vecchio. Si applica a: - request logs (selectors 28 and 45), - debug log (selector 34), - events log (selector 79) - Web request logs and Web debug logs (selectors 29 and 84 of the WEB SET OPTION command). Il default è 0 che registra tutti i file senza limiti (finché c'è spazio su disco...) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
[v16] Sintassi alternativa dei 4d Tags
Per 4DTEXT, 4DHTML, 4DEVAL c'è una sintassi alternativa veramente comoda. Con la v16 è possibile usare per questi tag la forma con il $: $4dtag (espressione) al posto del solito Questo va bene solo per questi tag: 4DTEXT 4DHTML 4DEVAL Quindi ad esempio: $4DTEXT(UserName) invece di: <!--#4DTEXT UserName--> |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
[v16] 4D Tags
Questo è l'elenco aggiornato dei TAG da usare nelle pagine dinamiche ( o da Web o col comando PROCESS 4D TAGS) : 4DTEXT, inserisce variabili o espressioni di 4D come testo (se contengono un carattere come il < lo traducono in htmlencode per visualizzarlo cosi com'è) 4DHTML, inserisce variabili o espressioni di 4D come codice HTML, senza conversioni 4DEVAL, valuta espressioni di 4D, anche senza risultato ( tipo a:=1 ), nel caso ritorni lo considera come HTML senza sostituzioni di caratteri 4DSCRIPT, esegue un metodo 4D (in fase di preparazione della pagina, non arriva sul browser) con la sintassi <!--#4DSCRIPT/metodo/mioparametro--> : The method does not exist. Nota: il metodo deve essere flaggato come disponibile per il web, aver dichiarato come testo $0 e $1, e in $1 riceverà "/mioparametro" 4DINCLUDE, include un'altra pagina (in fase di preparazione della pagina, non arriva sul browser) 4DBASE, definisce da quel punto in avanti dove prendere le pagine con i 4DINCLUDE successivi 4DCODE, esegue blocchi di codici 4D anche su più righe, incluse finestre e il comando Trace: è eseguito lato server prima di servire la pagina 4DIF, 4DElse, 4DElseIF e 4DENDIF, per gestire condizioni, 4DLOOP and 4DENDLOOP, per fare cicli di codice. Adesso accetta: - array ( incluso array di puntatori) - tabella (la selezione corrente) - espressione, in cui esce dal ciclo per una condizione classica, del tipo: <!--#4DEVAL $i:=0--> <!--#4DLOOP ($i<4)--> <!--#4DEVAL $i--> <!--#4DEVAL $i:=$i+1--> <!--#4DENDLOOP--> |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
JSON e i caratteri da filtrare
Nelle stringhe JSON i caratteri da filtrare sono: virgolette (quote) -> \" barra a destra (slash) -> \/ barra a sinistra (backslash) -> \\ backspace -> \b formfeed -> \f nuova linea (new line, char(10) ) -> \n a capo (return, char(13) ) -> \r tabulatore (tab, char(9) ) -> \t tutti i caratteri da 0 a 31 esclusi quelli sopra devono diventare \x00-\x1F un qualsiasi carattere unicode -> \u+4 cifre esadecimale // web_jsonEncode $risultato:=$1 $risultato:=Replace string($risultato;"\\";"\\\\") $risultato:=Replace string($risultato;char(double quote);"\\\"") $risultato:=Replace string($risultato;"/";"\\/") $risultato:=Replace string($risultato;Char(Backspace);"\\b") $risultato:=Replace string($risultato;Char(FF ASCII code);"\\f") $risultato:=Replace string($risultato;Char(Line feed);"\\n") $risultato:=Replace string($risultato;Char(Carriage return);"\\r") $risultato:=Replace string($risultato;Char(Tab);"\\t") $0:=$risultato |
1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
[v14] Campi OBJECT e coppie chiavi-valore
E' un classico registrare in coppie di array impostazioni o valori da tenere in memoria. Tipicamente sono due array, si cerca nel primo e se si trova si prende il valore dal secondo, così: // PER REEGISTRARE ARRAY TEXT(preferenzeChiave;3) ARRAY TEXT(preferenzeValore;3) preferenzeChiave{1}:="Valuta" preferenzeValore{1}:="Euro" preferenzeChiave{2}:="Iva" preferenzeValore{2}:="22" preferenzeChiave{3}:="Spese" preferenzeValore{4}:="2,00" // PER RIPRENDERE $ce=Find in array(preferenzeChiave;"Iva") If ($ce>0) $0:= preferenzeValore{$ce} Else $0:="" End if Con il nuovo Tipo C_OBJECT le due cose si possono scrivere così: // PER REEGISTRARE C_OBJECT(oPreferenze) OB SET(oPreferenze;"Valuta";"Euro";"Iva";22;"Spese";2.00) // PER RIPRENDERE $iva:=OB GET(oPreferenze;"Iva") |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
[v15] Campi Object visualizzati come JSON
Nelle form impostando un oggetto di Variabile con il contenuto di un Object si ottiene: 1- la visualizzazione del Json corrispondente (senza dover usare JSON stringify) 2- il Json può essere modificato dall'utente e la variabile si aggiorna! |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
[v14] JSON e i campi Time
Quando si usa JSON Stringify o Selection to JSON i campi time vengono trasformati in un numero intero di millisecondi dalla mezzanotte. Quindi le 10 del mattino diventano 10*3600*1000 = 36 000 000 Per recuperare l'orario originale si possono fare due cose: $millisec:=36000000 Se mi serve una Stringa: $testo:=Time String($millisec/1000) -> $testo = "10:00:00" Se mi serve un Time: $ora:=Time($millisec/1000) -> $ora = ?10:00:00? |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
[v14] I comandi nativi JSON: Selection to JSON
Il comando Selection to JSON crea una stringa JSON con i campi della selezione corrente, ad esempio: $jsonString :=Selection to JSON([Anagrafica]) Il risultato sarà del tipo : [ {"cognome":"Rossi", "nome":"Mario"}, {"cognome":"Verdi", "nome":"Giuseppe"}, ... ] E' possibile caricare solo alcuni campi aggiungendoli alla sintassi: $jsonString :=Selection to JSON([Anagrafica], [Anagrafica]Cognome) [ {"Cognome":"Rossi"}, {"Cognome":"Verdi"}, ... ] Oppure si può impostare un "template" C_OBJECT($template) OB SET($template;"LastName";->[Anagrafica] Cognome) $jsonString :=Selection to JSON([Anagrafica];$template) [ {"LastName":"Rossi"}, {"LastName":"Verdi"}, ... ] |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
[v14] I comandi nativi JSON: JSON Stringify
Partendo da una variabile C_Object si ottiene l'equivalente in stringa JSON con il comando JSON Stringify ( value ; * ) -> ritorna una stringa compatta JSON Stringify ( value ; * ) -> modalità 'pretty print', ritorna una stringa indentata Esempio: C_OBJECT($Anagrafica;$Figli) OB SET($Anagrafica;"cognome";"Rossi";"nome";"Mario") OB SET($Figli;"nome";"Giovanni";"anni";"12") OB SET($Anagrafica;"figli";$Figli) $Uno:=JSON Stringify($Anagrafica) {"nome":"Mario","cognome":"Rossi","figli":{"nome":"Giovanni","anni","12"}} $Due:=JSON Stringify($Anagrafica;*) { "nome":"Mario", "cognome":"Rossi", "figli":{ "nome":"Giovanni", "anni","12" } } |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
[v14] I comandi nativi JSON: JSON Parse
Dalla versione v14 sono disponibili i comandi JSON, che permettono di passare da stringhe a oggetti 4d. Gli oggetti JSON sono circondati da graffe {} Gli array sono circondati da quadre [] I dati sono in formato "chiave":"valore" La sequenza di dati è separata dalle virgole Il valore può essere:
JSON Parse ( jsonString {; type} ) -> Function result Se viene passato il parametro il comando lo converte nel formato richiesto, altrimentii farà la conversione al meglio possibile. Due esempi: JSON Parse("{\"nome\":124}") -> ritorna un C_OBJECT con {nome = 124} JSON Parse("{\"nome\":124}", is longint) -> ritorna 124 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
Creare un documento Excel da 4D
Ecco un esempio di codice per la creazione di un foglio Excel usando il plugin free e opensource scritto da Miyako: https://github.com/miyako/4d-plugin-xls $text:=Unicode_sample //create a workbook $book:=XLS WORKBOOK Create $sheetName:=$text $sheet:=XLS WORKBOOK Create sheet ($book;$sheetName) //problem with Mac version of Excel 2010; OK on Windows XLS WORKSHEET SET COL WIDTH ($sheet;0;20*256) $row:=0 //zero-based $col:=0 //zero-based $format:=0 //NULL=default format (0x0F) $cell:=XLS WORKSHEET Set cell text ($sheet;$row;$col;$format;$text) XLS CELL RELEASE ($cell) //we don't need this reference any more, so release it. //create a range reference node $cell1:=XLS WORKSHEET Set cell real ($sheet;0;1;$format;1) $cell2:=XLS WORKSHEET Set cell real ($sheet;1;1;$format;2) $area:=XLS WORKBOOK Create area node ($book;$cell1;$cell2;XLS_CELL_ABSOLUTE_As1;XLS_CELLOP_AS_REFERENCE) XLS CELL RELEASE ($cell1) XLS CELL RELEASE ($cell2) //create a function node $fn:=XLS WORKBOOK Create fn1 node ($book;XLS_FUNC_SUM;$area) $cell:=XLS WORKSHEET Set cell fn ($sheet;2;1;$format;$fn) XLS NODE RELEASE ($fn) XLS NODE RELEASE ($area) XLS CELL RELEASE ($cell) XLS WORKSHEET RELEASE ($sheet) $success:=XLS WORKBOOK Save document ($book;System folder(Desktop)+$text+".xls") XLS WORKBOOK CLEAR ($book) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Privacy e cookies
COOKIE LAW 1) Che cosa sono i cookie? I cookie sono dei file di testo che i siti visitati inviano al browser dell'utente e che vengono memorizzati per poi essere ritrasmessi al sito alla visita successiva. 2) A cosa servono i cookie? I cookie possono essere usati per monitorare le sessioni, per autenticare un utente in modo che possa accedere a un sito senza digitare ogni volta nome e password e per memorizzare le sue preferenze. 3) Cosa sono i cookie tecnici? I cookie cosiddetti tecnici servono per la navigazione e per facilitare l'accesso e la fruizione del sito da parte dell'utente. I cookie tecnici sono essenziali per esempio per accedere a Google o a Facebook senza doversi loggare a tutte le sessioni. Lo sono anche in operazioni molto delicate quali quelle della home banking o del pagamento tramite carta di credito o per mezzo di altri sistemi. 4) I cookie Analytics sono cookie tecnici? In altri termini i cookie che vengono inseriti nel browser e ritrasmessi mediante Google Analytics o tramite il servizio Statistiche di Blogger o similari sono cookie tecnici?. Il Garante ha affermato che questi cookie possono essere ritenuti tecnici solo se "utilizzati a fini di ottimizzazione del sito direttamente dal titolare del sito stesso, che potrà raccogliere informazioni in forma aggregata sul numero degli utenti e su come questi visitano il sito. A queste condizioni, per i cookie analytics valgono le stesse regole, in tema di informativa e consenso, previste per i cookie tecnici." 5) Che cosa sono i cookie di profilazione? Sono cookie utilizzati per tracciare la navigazione dell'utente per creare profili sui suoi gusti, sulle sue preferenze, sui suoi interessi e anche sulle sue ricerche. Vi sarà certamente capitato di vedere dei banner pubblicitari relativi a un prodotto che poco prima avete cercato su internet. La ragione sta proprio nella profilazione dei vostri interessi e i server indirizzati opportunamente dai cookie vi hanno mostrato gli annunci ritenuti più pertinenti. 6) È necessario il consenso dell'utente per l'installazione dei cookie sul suo terminale? Per l'installazione dei cookie tecnici non è richiesto alcun consenso mentre i cookie di profilazione possono essere installati nel terminale dell'utente solo dopo che quest'ultimo abbia dato il consenso e dopo essere stato informato in modo semplificato. 7) In che modo gli webmaster possono richiedere il consenso? Il Garante per la Privacy ha stabilito che nel momento in cui l'utente accede a un sito web deve comparire un banner contenente una informativa breve, la richiesta del consenso e un link per l'informativa più estesa come quella visibile in questa pagina su che cosa siano i cookie di profilazione e sull'uso che ne viene fatto nel sito in oggetto. 8) In che modo deve essere realizzato il banner? Il banner deve essere concepito da nascondere una parte del contenuto della pagina e specificare che il sito utilizza cookie di profilazione anche di terze parti. Il banner deve poter essere eliminato solo con una azione attiva da parte dell'utente come potrebbe essere un click. 9) Che indicazioni deve contenere il banner? Il banner deve contenere l'informativa breve, il link alla informativa estesa e il bottone per dare il consenso all'utilizzo dei cookie di profilazione. 10) Come tenere documentazione del consenso all'uso dei cookie? È consentito che venga usato un cookie tecnico che tenga conto del consenso dell'utente in modo che questi non abbia a dover nuovamente esprimere il consenso in una visita successiva al sito. 11) Il consenso all'uso dei cookie si può avere solo con il banner? No. Si possono usare altri sistemi purché il sistema individuato abbia gli stessi requisiti. L'uso del banner non è necessario per i siti che utilizzano solo cookie tecnici. 12) Che cosa si deve inserire nella pagina informativa più estesa? Si devono illustrare le caratteristiche dei cookie installati anche da terze parti. Si devono altresì indicare all'utente le modalità con cui navigare nel sito senza che vengano tracciate le sue preferenze con la possibilità di navigazione in incognito e con la cancellazione di singoli cookie. 13) Chi è tenuto a informare il Garante che usa cookie di profilazione? Il titolare del sito ha tale onere. Se nel suo sito utilizza solo cokie di profilazione di terze parti non occorre che informi il Garante ma è tenuto a indicare quali siano questi cookie di terze parti e a indicare i link alle informative in merito. 14) Quando entrerà in vigore questa normativa? Il Garante ha dato un anno di tempo per mettersi in regola e la scadenza è il 2 Giugno 2015. COOKIE UTILIZZATI IN QUESTO SITO File di log: Come molti altri siti web anche questo fa uso di file di log registra cioè la cronologia delle operazioni man mano che vengono eseguite. Le informazioni contenute all'interno dei file di registro includono indirizzi IP, tipo di browser, Internet Service Provider (ISP), data, ora, pagina di ingresso e uscita e il numero di clic. Tutto questo per analizzare le tendenze, amministrare il sito, monitorare il movimento dell'utente dentro il sito e raccogliere dati demografici, indirizzi IP e altre informazioni. Tale dati non sono riconducibili in alcun modo all'identità dell'utente e sono cookie tecnici. COOKIE DI TERZE PARTI PRESENTI NEL SITO Cookie: www.sviluppo4d.it usa i cookie per memorizzare le informazioni sulle preferenze dei visitatori e sulle pagine visitate dall'utente e per personalizzare il contenuto della pagina web in basa al tipo di browser utilizzato e in funzione delle altre informazioni che appunto tale browser invia. 1) Cookie Google: tale cookie è stato introdotto da Google cinque anni fa e serve per pubblicare annunci Adsense su www.sviluppo4d.it in modo da mostrare all'utente della pubblicità più mirata in base alla loro cronologia. Gli utenti possono accettare tale cookie oppure disattivarlo nel loro browser visitando la pagina Privacy e Termini. Ulteriori informazioni sulle tipologie e sull'uso che fa Google dei cookie con finalità pubblicitarie possono essere trovate nella pagina web dei Tipi di cookie utilizzati. Anche alcuni partner pubblicitari di Google Adsense possono usare cookie e Web Beacons per tracciare gli utenti. 2) Cookie di Facebook: Questo sito ha alcuni plugin di Facebook che possono tracciare il comportamento dei lettori. Per avere maggiori informazioni si può consultare la pagina per la Politica della Privacy di Facebook. 3) Google+ attraverso lo script plusone.js potrà trattare i dati personali secondo queste line guida Google Cookie Policy Privacy In questo blog hanno accesso server di terze parti o di rete pubblicitarie che usano tale tecnologia per inviare gli annunci nel tuo browser attraverso www.sviluppo4d.it. Tramite il rilevamento del tuo indirizzo IP mostrano la pubblicità più pertinente con i tuoi interessi. Tecnologie simili (quali cookie, web bacons e javascript) possono essere utilizzati dalle reti pubblicitarie di terze parti per misurare l'efficacia dei loro messaggi pubblicitari e per personalizzare il contenuto di tali messaggi. Il sito www.sviluppo4d.it e il suo amministratore non hanno alcun controllo sui cookie che vengono utilizzati da terze parti quindi per approfondire il tema si consiglia di consultare le politiche della privacy di queste terze parti così come le opzioni per disattivare la raccolta di queste informazioni. L'amministratore di questo sito non può quindi controllare le attività degli inserzionisti di questo blog. È comunque possibile disabilitare i cookie direttamente dal proprio browser. Queste disposizioni del Garante della Privacy non sono solo italiane ma sono comuni a gran parte del paesi europei. Si possono conoscere le regole di ciascuna giurisdizione consultando il sito Your Online Choices nella propria lingua. UTILIZZO DI GOOGLE ANALYTICS IN QUESTO SITO Come detto i cookie analytics sono considerati tecnici se utilizzati solo a fini di ottimizzazione e se gli IP degli utenti sono mantenuti anonimi. Informiamo l'utente che questo sito utilizza il servizio gratuito di Google Analytics. Ricordiamo che i dati vengono usati solo per avere i dati delle pagine più visitate, del numero di visitatori, i dati aggregati delle visite per sistema operativo, per browser, ecc. Gli IP di Google Analytics sono stati anonimizzati. Questi parametri vengono archiviati nei server di Google che ne disciplina la Privacy secondo queste linee guida. Un utente può disattivare Google Analytics durante la navigazione utilizzando il componenete aggiuntivo disponibile per Chrome, Firefox, Internet Explorer, Opera e Safari. Si possono inoltre cancellare i cookie singolarmente per ciascun dominio, nascondere le ricerche. settare le impostazioni degli annunci di Google. NAVIGAZIONE ANONIMA Una navigazione senza l'utilizzo di cookie tecnici e di profilazione è possibile mediante quella che viene definita navigazione in incognito e che è fattibile con tutti i principali browser. Ulteriori informazioni sulla disabilitazione dei cookie su Firefox, in inglese. Ulteriori informazioni sulla disabilitazione dei cookie su Chrome, in inglese Ulteriori informazioni sulla disabilitazione dei cookie su Internet Explorer, in inglese Ulteriori informazioni sulla disabilitazione dei cookie su Safari , in inglese Ulteriori informazioni sulla disabilitazione dei cookie su Opera, in inglese. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Versioni di OpenSSL usate da 4D
Le librerie OpenSSL usate da 4d e 4d server e il corrispondente supporto a TLS sono i seguenti: 4D openSSL TLS supportato 12.x : 0.9.8j : TLS v1.0 13.x : 1.0.0.d : TLS v1.0 14.x : 1.0.0.d : TLS v1.0 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Posizione della cartella Preferenze di 4d
Dalla versione v12 queste sono le posizioni dei file di preferenza: WINDOWS C:\Users\ C:\Users\ MAC erano per la v12: /Users/ adesso sono: /Users/ Le posizioni delle finestre e altre dimensioni si trovano: WINDOWS C:\Users\Administrator\AppData\Roaming\4D\4D Window Bounds v14\ MAC /Users/ |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
4D v13.5 : non sono permessi campi unici senza indice
Dalla versione 13.5 4d non salverà più i record che hanno il flag di unico, ma che non hanno un indice assegnato. Questa procedura permette l'estrazione dalla struttura dei campi unici non indicizzati cfr http://kb.4d.com/assetid=77024 C_LONGINT($maxTableNumber_l;$currentTable_l) C_LONGINT($maxFieldCount_l;$currentField_l) C_LONGINT($dontCare_l) // Per valori GET FIELD PROPERTIES non usati. C_BOOLEAN($dontCare_f;$isIndexed_f;$isUnique_f) C_TEXT($logHeader_t;$logRecord_t;$logfile_t) C_TEXT($delim_t;$lf_t) C_TIME($logfile_h) C_TEXT($tableName_t;$fieldName_t;$note_t) $delim_t:=Char(Tab) $lf_t:=Char(Carriage return)+Char(Line feed) $logHeader_t:="Campi unici senza indice:"+$lf_t $logfile_t:=Get 4D folder(Logs Folder)+"UniciNonIndicizzati" $logfile_h:=Create document($logfile_t) If (OK=1) SEND PACKET($logfile_h;$logHeader_t) $maxTableNumber_l:=Get last table number For ($currentTable_l;1;$maxTableNumber_l) If (Is table number valid($currentTable_l)) $maxFieldCount_l:=Get last field number(Table($currentTable_l)) For ($currentField_l;1;$maxFieldCount_l) If (Is field number valid($currentTable_l;$currentField_l)) // Nota che la seguente riga è spezzata in due: GET FIELD PROPERTIES($currentTable_l;$currentField_l;$dontCare_l;\ $dontCare_l;$isIndexed_f;$isUnique_f;$dontCare_f) If (($isUnique_f) & (Not($isIndexed_f))) $tableName_t:=Table name(Table($currentTable_l)) $fieldName_t:=Field name(Field($currentTable_l;$currentField_l)) $logRecord_t:="["+$tableName_t+"]"+$fieldName_t+$lf_t SEND PACKET($logfile_h;$logRecord_t) End if End if End for End if End for CLOSE DOCUMENT($logfile_h) SHOW ON DISK($logfile_t) End if |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Web |
Header di risposta da Web
Quando si usa 4D come Web server, normalmente si risponde con le normali pagine come richieste dall'utente con un leader di default (= 200) Quando invece bisogna rispondere con una pagina che non è quella richiesta, la cosa migliore per rispondere ai casi eccezionali sarebbe quella di mettere il corretto header. Ad esempio, se l'url non è riconosciuto puoi mandare l'utente alla pagina che vuoi, dovresti impostare questo header ARRAY TEXT($atHeaders;2) ARRAY TEXT($atValues;2) $atHeaders{1}:="X-VERSION" $atValues{1}:="HTTP/1.1" $atHeaders{2}:="X-STATUS" $atValues{2}:="404 Not Found" WEB SET HTTP HEADER($atHeaders;$atValues) WEB SEND FILE("pagina_errore.html") Un altro header utile: "302 Moved Temporarily" (equivalente al redirect) cfr http://www.sviluppo4d.it/Detail_Faq_Display?ID=632&title=Alternativa+al+comando+SEND+HTTP+REDIRECT Per una funzione non disponibile si dovrebbe usare: "501 Not implemented" Da notare che usualmente si vedono due tipi di errore gestiti automaticamente da 4D Web Server: "500 Internal server error" : il codice ha incontrato una condizione non prevista, di solito errore puro "503 Service Unavailable" : hai superato il numero di richieste contemporanee accettate ( di solito legato ad un parametro di configurazione ) Qui l'elenco ufficiale: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novita' |
4d su Mac OS X 10.9
Su Mac OS X 10.9 Maverick le applicazioni che non sono davanti (in 'foreground') vengono automaticamente abbassate di priorità con la nuova funzione "App Nap". Questo è ovviamente un problema se il 4d Server viene usato su un 10.9: in questo caso basta andare nella finestra Info del Finder per l'app Server e impostare il flag "Impedisci App Nap" |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Testo di un pulsante su più righe
E' possibile scrivere il testo di un pulsante in modo che venga visualizzato su due righe. Non bisogna usare il classico Carriage Return, bensì il carattere "\" ("\\" nel code editor). Questa caratteristica è utilizzabile solo su 3D button, 3D radio button e 3D check box. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Ripristino della configurazione di backup
Se si sceglie di effettuare manualmente il backup con il metodo: CONFIRM("Eseguo il salvataggio automatico?";"Sì";"No") If (OK=1) BACKUP End if Se la destinazione non è disponibile (ad esempio una pen drive) 4D modifica il percorso di backup con la cartella della struttura. Se si salva in un file BackupSave.xml la copia della configurazione corretta, si può modificare il metodo precedente così: CONFIRM("Eseguo il salvataggio automatico?";"Sì";"No") If (OK=1) DELETE DOCUMENT(getPathname (Structure file)+"Preferences\\Backup\\Backup.xml") COPY DOCUMENT(getPathname (Structure file)+"Preferences\\Backup\\BackupSave.xml";u_PathnameOnly (Structure file)+"Preferences\\Backup\\Backup.xml") BACKUP End if |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
Impostare il livello di cifratura SSL
Il comando SET DATABASE PARAMETER con l'opzione 64 (SSL Cipher List) permette di impostare il livello di cifratura SSL. Ad esempio è possibile eseguire questo codice per disabilitare l'SSL2 e attivare solo l'SSL3 per la versione di 4d v11: STOP WEB SERVER SET DATABASE PARAMETER (SSL Cipher List;"HIGH:!SSLv2:!EXP:!ADH:!aNULL:!eNULL:!NULL") START WEB SERVER Alcune informazioni su come scrivere questo parametro si può leggere la documentazione del Comando Ciphers di OpenSSL. Nella v13.3 i valori di default sono: TLSv1/SSLv3, Cipher : AES256-SHA AES(256) Le altre cifrature accettate sono SSL2 ciphers: nessuno SSL3 ciphers: CAMELLIA256-SHA 256 bit AES256-SHA 256 bit DES-CBC3-SHA 168 bit SEED-SHA 128 bit CAMELLIA128-SHA 128 bit AES128-SHA 128 bit IDEA-CBC-SHA 128 bit RC4-SHA 128 bit RC4-MD5 128 bit DES-CBC-SHA 56 bit TLS1 ciphers: CAMELLIA256-SHA 256 bit AES256-SHA 256 bit DES-CBC3-SHA 168 bit SEED-SHA 128 bit CAMELLIA128-SHA 128 bit AES128-SHA 128 bit IDEA-CBC-SHA 128 bit RC4-SHA 128 bit RC4-MD5 128 bit DES-CBC-SHA 56 bit |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Posizione delle risorse locali *
Nelle installazioni Client/Server 4D registra in locale delle risorse che velocizzano i collegamenti successivi e che sono automaticamente aggiornati senza che l'utente debba intervenire. Dalla v11 la posizione di queste risorse è in cartelle registrate in queste posizioni: Windows XP: {Disco:}\Documents and Settings\{nome_utente}\Local Settings\Application Data\Nomeprogramma_indirizzo Windows Vista/7 {Disco:}\Users\{nome_utente}\AppData\Local\4D\Nomeprogramma_indirizzo Mac {Disco}Users\{nome_utente}\Libreria\Cache\4D\Nomeprogramma_indirizzo Nel caso in cui il client è incorporato nell'applicazione, le cartelle locali sono: Windows Vista/7 {Disk}:\Users\{nome_utente}\AppData\Local\Nomeprogramma Mac OS X {Disk}:Users:{nome_utente}:Library:Caches:Nomeprogramma Client Nel caso ci fossero problemi di accesso a queste cartelle è sempre possibile creare una cartella "ClientLocal" vicino al 4d usato come client Su installazioni Terminal Server/Citrix purtroppo le cartelle Local e Local Settings non possono essere inserite nel profilo, quindi ogni connessione richiederebbe di scaricare sempre le informazioni dal server. Se si vuole evitare questo è possibile integrare direttamente la cartella dell'applicazione (contenente una sottocartella ClientLocal) nel profilo di roaming. Ovviamente in questo caso deve esserci un 4d usato come client per ogni utente collegato. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Duplicazione RECORD con SUBRECORD
Le nuove versioni di 4D non duplicano piu' i subrecord all'interno del record ed il campo id_added_by_converter non e' editabile, ne avevo necessita' per cui ho fatto questa routine (spero esista un metodo piu' semplice) Occorre preventivamente creare un set del record da duplicare ed un set del record duplicato (ricordarsi di cancellarli al termine) poi : DuplicaSubrecords (->[TABLE];->[TABLE]Subrecord;->[TABLE_Subrecord];->[TABLE_Subrecord]id_added_by_converter) // DUPLICAZIONE SUBRECORDS $p_TABLErecord:=$1 // Puntatore alla Tabella RECORD $p_TABLEsubrecord:=$2 // Puntatore al campo SUBRECORD DEL RECORD $p_TABLENewsubrecord:=$3 // Puntatore alla Tabella NEW SUBRECORD $p_Id:=$4 // Puntatore al campo id_added_by_converter $NumeroTABLE:=Table($p_TABLENewsubrecord) USE SET("OLD") // Richiamo il record originale QUERY($p_TABLENewsubrecord->;$p_Id->=Get subrecord key($p_TABLEsubrecord->)) $NumeroSubrecords:=Records in selection($p_TABLENewsubrecord->) If ($NumeroSubrecords>0) USE SET("NEW") // Richiamo il record copia For ($i;1;$NumeroSubrecords) CREATE SUBRECORD($p_TABLEsubrecord->) // Creo l'aggancio al record End for SAVE RECORD($p_TABLErecord->) USE SET("OLD") $NumeroCampi:=Get last field number($p_TABLENewsubrecord) ARRAY POINTER($p_ElementoCampo;$NumeroSubrecords*$NumeroCampi) For ($i;1;$NumeroSubrecords) $P_RECORD:=($i-1)*$NumeroCampi For ($k;1;$NumeroCampi) $P_Vettore:=$P_RECORD+$k // Calcolo l'elemento del vettore $p_ElementoCampo{$P_Vettore}:=Get pointer("$var_"+String($k)) // Associo il puntatore $p_Campo:=Field($NumeroTABLE;$k) // Puntatore al campo da prelevare $p_ElementoCampo{$P_Vettore}->:=$p_Campo-> // Momorizzo il valore del campo sulla variabile End for NEXT RECORD($p_TABLENewsubrecord->) End for USE SET("NEW") QUERY($p_TABLENewsubrecord->;$p_Id->=Get subrecord key($p_TABLEsubrecord->)) $NumeroSubrecords:=Records in selection($p_TABLENewsubrecord->) ON ERR CALL("ErrorIdSubrecord") // Filtra Errore su assegnazione campo id_added_by_converter (Metodo ErrorIdSubrecord VUOTO) For ($i;1;$NumeroSubrecords) $P_RECORD:=($i-1)*$NumeroCampi For ($k;1;$NumeroCampi) $P_Vettore:=$P_RECORD+$k // Calcolo l'elemento del vettore $p_Campo:=Field($NumeroTABLE;$k) // Puntatore al campo da assegnare $p_Campo->:=$p_ElementoCampo{$P_Vettore}-> // Assegno il valore dalla variabile al campo End for SAVE RECORD($p_TABLENewsubrecord->) NEXT RECORD($p_TABLENewsubrecord->) End for UNLOAD RECORD($p_TABLENewsubrecord->) ON ERR CALL("") SAVE RECORD($p_TABLErecord->) // Forse non serve End if |
2 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Dove si trovano i file 4DLINK
Il file .4DLINK indica il percorso e le opzioni per aprire una struttura, sia per 4d Mono che Server. Vengono creati automaticamente da 4D per mostrarli nei recenti, ma si possono recuperare, riutilizzare direttamente ed eventualmente modificare. Per le versioni v11 e v12 il file si trovano 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/ Per la versione v13: • Windows: C:\Users\UserName\AppData\Roaming\4D\Favorites v13\ • Mac OS: /Users/UserName/Library/Application Support/4D/Favorites v13/ dove UserName è il nome dell'utente del sistema. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Adattare pagine web su Safari IOS
Quando predisponete una pagina web che deve essere visualizzata su device mobili con browser HTML5, tipo Safari Mobile su iPhone e iPad, è possibile utilizzare un metatag specifico che adatta il contenuto allo schermo. La riga va inserita sotto il tag <head> : <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"> Per ulteriori informazioni guarda la Safari Web Content Guide |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Percorso della cartella Documenti
Nella v13: $0:=System Folder(Documents folder) Nella v12: // Codice di Maurizio Zanni C_TEXT($_vt_Path) C_LONGINT($_vl_Type) $_vl_Type:=Desktop //Ritorna il Path del Desktop $_vt_Path:=System Folder($_vl_Type) //Elimina il Separatore alla fine del Path $i:=Length($_vt_Path) $_vt_Path:=Substring($_vt_Path;1;$i-1) //Ritorna il Path alla cartella Padre del Desktop $i:=Length($_vt_Path) While ($_vt_Path≤$i≥#Folder Separator) & ($i>0) $i:=$i-1 End while $_vt_Path:=Substring($_vt_Path;1;$i-0) //Aggiunge la Cartella Documents con il Separatore finale (Mac o Win) $_vt_Path:=$_vt_Path+"Documents"+Folder Separator $0:=$_vt_Path |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Caratteri non utilizzabili in un testo in modalità Unicode
A partire dalla versione 11 è possibile utilizzare il database in modalità Unicode. In questa modalità, tre caratteri non possono essere memorizzati all'interno di un testo della base dati, e sono: 0 65534 (FFFE) 65535 (FFFF) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Limite fisico degli indici B-Tree per i campi Text
È importante sapere che, quando si indicizza un campo di tipo testo, il limite fisico di un indice B-Tree è 1024 caratteri, e dunque se si indicizzano contenuti di lunghezza maggiore la ricerca può fallire. Nessun limite invece per quel che riguarda gli indici a keyword. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
La linea laterale del Method Editor
Sulla parte sinistra del nuovo Method Editor di 4D è possibile vedere, accanto al numero di linea, una piccola linea verticale colorata. Il colore è verde per indicare che la riga non è stata modificata dall'ultimo salvataggio, giallo se la riga è stata modificata. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Come utilizzare con 4d i lettori barcode per iPhone, iPod, iPad
I lettori di barcode della Infinite Peripherals, Linea Pro per iPhone e iPod e Infinea Tab per iPad, sono quelli usati da Apple nei propri AppleStore. Per utilizzarli con un nostro gestionale in 4d (a parte scrivere un'app nativa in IOS) potete usare una soluzione abbastanza semplice: - da 4d pubblicate via web le pagine con le funzioni che vi servono - scaricare l'app "Nexus Barcode" che è gia pubblicata su AppStore - nelle impostazioni dell'app mettete l'indirizzo della vostra pagina di 4d A questo punto quando aprite l'app si carica la pagina web del vostro gestionale: - fate click (ops tap) sul campo da inserire - premete il tasto del lettore di barcode che va a scrivere nel campo Oppure: - nella preparazione della pagina predisponete un javascript che si aspetta un solo parametro, tipo: function loadBarcode(codice) {} - nelle impostazioni dell'app scrivete il nome della funzione: loadBarcode In questa modalità non c'è bisogno di cliccare (tappare) il campo dove inserire il codice, basta usare il lettore del barcode; a parte la comodità di un passaggio in meno, l'altro vantaggio è che non serve far apparire la tastiera che sullo schermo dell'iPod significa guadagnare un bel po' di spazio Per l'hardware dei lettori ci si può rivolgere al distributore italiano dei lettori barcode per iPhone, iPod, iPad Cidroid, divisione della Nexus. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Limitare il numero di caratteri in una variabile alfanumerica
Una delle prime FAQ pubblicate su Sviluppo4D riguardava la limitazione del numero di caratteri inseribili in un campo Alpha. Eccone una versione aggiornata: Case of : (Form event=On After Edit) If (Length(Get edited text)>=vLength) $textvariable:=Substring(Get edited text;1;vLength) End if End case A vLength può essere sostituita la lunghezza del campo, nei casi in cui è possibile. A $textvariable potrebbe essere sostituito Self->, ma in questo caso il metodo non funziona ad esempio sugli elementi degli array di una listbox. |
1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Eseguire VB Script in 4D
Utilizzando il metodo di Keisuke Miyako per l'esecuzione di un VB script, vediamo un esempio di conversione di un file utilizzando MS Word. Ecco il testo di uno script che apre un file e lo salva in formato solo testo: Set objWord = CreateObject("Word.Application") Set objDoc = objWord.Documents.Open("C:\codici.doc") Const wdFormatText = 2 objDoc.SaveAs "C:\codici.txt", wdFormatText objWord.Quit Ecco il metodo (lievemente modificato) di Keisuke Miyako: C_TEXT($1;$0) C_BLOB($2) C_LONGINT($platform_l) PLATFORM PROPERTIES($platform_l) If ($platform_l=Windows) $script_folder_path_t:=Get 4D folder(Current Resources folder)+"vbs\\" $script_file_path_t:=$script_folder_path_t+Replace string($1;"/";"\\";*) If (Test path name($script_file_path_t)=Is a document) SET ENVIRONMENT VARIABLE("_4D_OPTION_HIDE_CONSOLE";"true") C_BLOB($standard_input_x;$standard_output_x;$standard_error_x) If (Count parameters=2) $standard_input_x:=$2 //patch to counter data loss caused by CRLF's in input stream SET BLOB SIZE($standard_input_x;BLOB size($standard_input_x)+8166;0) End if LAUNCH EXTERNAL PROCESS("cscript //Nologo //U \""+$script_file_path_t+"\"";$standard_input_x;$standard_output_x;$standard_error_x) $standard_output_t:=Convert to text($standard_output_x;"UTF-16LE") If (BLOB size($standard_error_x)#0) & (BLOB size($standard_output_x)=0) $0:=Convert to text($standard_error_x;"UTF-16LE") Else $0:=$standard_output_t End if End if End if |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Cosa fare se 4D si chiude all'avvio
Alcune istruzioni veloci su come intervenire nel caso in cui 4d si chiude all'avvio. Se si riesce ad entrare come Designer basterà verificare la procedura di startuo legata allo specifico user. Se non si riesce proprio ad entrare, provare una delle seguenti opzioni (una alla volta!) 1. Sei sicuro di essere entrato come Designer? Se per caso hai impostato un utente di default non fa andare in ambiente Designer e quindi potrebbe non intercettare eventuali errori. Per verificare tieni premuto il maiuscolo al lancio del programma, così ti appare la lista degli utenti. 2. provare a togliere temporaneamente i plugin 3. cancellare le preferenze di 4d (attento a tenere il file delle licenze) 4. fare una verifica della struttura con 4d tools 5. recuperare l'ultima copia della struttura funzionante 5. provare a verificare la struttura con un'utilitty tipo SanityCheck della Committedsoftware, che funziona fino alla versione 2004.5 http://www.committedsoftware.com/sanitycheck.html |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
4d e Mountain Lion
Ecco i risultati dei primi test con le versioni di 4d v12.4 e v13.1 su Mountain Lion. Restano aperti solo quattro problemi, che saranno sicuramente fissati nelle prossime versioni (subito nelle prossime versioni Hotfix per i Partner): 2 problemi importanti riguardano un crash dopo: - il cambio di stampante da codice - la stampa dagli editor di Etcihette o dal Quick Report 2 solo cosmetici riguardano: - il comando OBJECT SET ENABLE non mette in grigio il testo disabilitato - il colore della selezione di record nelle maschere di tipo Lista Inoltre 4d sas dovrà gestire in qualche modo la nuova gestione di Gatekeeper, per certificare le prossime versioni di 4d con Apple. Da segnalare un problema con il web server Apache integrato in OS X: se la condivisione web era attiva prima di aggiornare a Mountain Lion, 4d non pèotrà accedere alla porta 80 con il suo Web server. Purtroppo in Mountain Lion non c'è più la preferenza che stoppa Apache, per cui bisognerà interromperlo con il comando da terminale: sudo apachectl stop cfr http://www.4d.com/blog/information-4d-mountain-lion.html |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Come creare una plist per Mac OS X o IOS
Il formato XML plist è lo standard con cui sono scritte ad esempio le preferenze dei vari programmi su Mac OS X. Il formato è letto nativamente dalle applicazioni scritte in XCode, come ad esempio programmi per iPhone e iPad. L'esempio successivo mostra come creare una plist per ad esempio inviare dei dati strutturati ad un applicativo su iOS in modo semplice e veloce: infatti un xml generico andrebbe ogni volta interpretato, mentre la plist può essere letta direttamente come un NSDictionary. ` ---------------------------------------------------- ` User name (OS): Umberto Migliore ` Date and time: 08-02-11, 12:22:51 ` ---------------------------------------------------- ` Method: nx_crea_plist ` Description: `mostra come creare un documento plist: ` `<?xml version="1.0" encoding="UTF-8" standalone="no" ?> `<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> `<plist version="1.0"> ` <dict> ` <key>Author</key> ` <string>William Shakespeare</string> ` <key>Title</key> ` <string>Macbeth</string> ` <key>Lines</key> ` <array> ` <string>It is a tale told by an idiot,</string> ` <string>Full of sound and fury, signifying nothing.</string> ` </array> ` <key>Birthdate</key> ` <integer>1564</integer> ` </dict> `</plist> ` ` Parameters ` ---------------------------------------------------- C_TEXT($autore;$titolo) C_LONGINT($annonascita) ARRAY TEXT($citazione;0) `=== preparo i dati $autore:="William Shakespeare" $titolo:="Macbeth" $annonascita:=1564 APPEND TO ARRAY($citazione;"It is a tale told by an idiot,") APPEND TO ARRAY($citazione;"Full of sound and fury, signifying nothing.") `=== creo la plist $xml_ref:=DOM Create XML Ref("plist";"";"version";"1.0") `=== dict principale che contiene tutto $dict:=DOM Create XML element($xml_ref;"dict") $key:=DOM Create XML element($dict;"key") DOM SET XML ELEMENT VALUE($key;"Author") $value:=DOM Create XML element($dict;"string") DOM SET XML ELEMENT VALUE($value;$autore) $key:=DOM Create XML element($dict;"key") DOM SET XML ELEMENT VALUE($key;"Title") $value:=DOM Create XML element($dict;"string") DOM SET XML ELEMENT VALUE($value;$titolo) $key:=DOM Create XML element($dict;"key") DOM SET XML ELEMENT VALUE($key;"Lines") $array:=DOM Create XML element($dict;"array") For ($riga;1;Size of array($citazione)) $value:=DOM Create XML element($array;"string") DOM SET XML ELEMENT VALUE($value;$citazione{$riga}) End for $key:=DOM Create XML element($dict;"key") DOM SET XML ELEMENT VALUE($key;"Birthdate") $value:=DOM Create XML element($dict;"integer") DOM SET XML ELEMENT VALUE($value;$annonascita) `=== chiude l'xml, aggiunge lo header e ritorna un testo DOM EXPORT TO VAR($xml_ref;$testo) DOM CLOSE XML($xml_ref) $header:="<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" $testo:=Insert string($testo;$header;Position("<plist";$testo)) ALERT($testo) ` $0:=$testo |
1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
Indentazione XML
Quando si crea un XML, i comandi di 4d lo creano con tutta l'indentazione necessaria ad una più facile lettura. Però se l'xml è utilizzato per comunicazioni via wan (server to server, mobile to server, etc) in produzione è meglio risparmiare in dimensioni dei messaggi, ad esempio togliendo l'indentazione: su file complessi con molti livelli di indentazione il risparmio può essere notevole. Fino alla v11 si usava il secondo parametro del comando DOM SET XML OPTION Dalla v12 il comando è stato rinominato DOM SET XML OPTION -> DOM SET XML DECLARATION e invece per le opzioni più generiche si usa il comando più specifico XML SET OPTION Questo comando ha diverse opzioni, nel caso specifico la sintassi è: DOM SET XML OPTION($idRef; XML Indentation; XML No indentation) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Ruotare un'immagine usando SVG
Questo codice è un esempio di utilizzo del componente incluso in 4d per gestire i comandi SVG; lo scopo del metodo è di ruotare di 90 gradi un'immagine, ad esempio per raddrizzare una foto. // ---------------------------------------------------- // User name (OS): Umberto Migliore // Date and time: 14-02-11, 11:41:14 // ---------------------------------------------------- // Method: nx_svgRuotaQuartoDestra // Description // Ruota un immagine di un quarto di giro a destra // // Parameters // ---------------------------------------------------- C_PICTURE($immagine;$1;$0) $immagine:=$1 PICTURE PROPERTIES($immagine;$larga;$alta) $maggiore:=Choose($larga>$alta;$larga;$alta) $svg:=SVG_New ($alta;$larga) $img:=SVG_New_embedded_image ($svg;$immagine;0;0) SVG_SET_TRANSFORM_ROTATE ($svg;90;$maggiore/2;$maggiore/2) If ($larga>$alta) SVG_SET_TRANSFORM_TRANSLATE ($svg;0;$larga-$alta) End if $immagine:=SVG_Export_to_picture ($svg;0) SVG_CLEAR ($svg) $0:=$immagine |
1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Autenticazione SOAP
I servizi webservice possono richiedere l'autenticazione in diversi modi: 1. lo standard http BASIC -> si può usare il comando WEB SERVICE AUTHENTICATE ("nome", "password"; 1) 2. lo standard http DIGEST -> si può usare il comando WEB SERVICE AUTHENTICATE ("nome", "password"; 2) 3. uno dei due standard http, ma con un proxy http intermedio: -> si usa il doppio comando WEB SERVICE AUTHENTICATE ("nome", "password", 0) `può essere BASIC o DIGEST WEB SERVICE AUTHENTICATE ("nome2", "password2", *) `dati di accesso al proxy 4. può essere del tipo SOAP HEADER, cioè inclusa nel corpo della SOAP $xml:=DOM Create XML Ref("auth") $utente:=DOM Create XML element($xml;"username") DOM SET XML ELEMENT VALUE($utente;"nome") $password:=DOM Create XML element($xml;"password") DOM SET XML ELEMENT VALUE($password;"password") SET WEB SERVICE OPTION(Web Service SOAP Header,$xml) DOM CLOSE XML($xml) Sono eventualmente da verificare che i nodi siano "username" e "password" |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
InStrRev trova la prima posizione di una stringa partendo dalla fine
Come tutti sappiamo, la funzione Position() di 4D restituisce la posizione del primo carattere trovato, ma partendo da sinistra. In giro ho trovato questo ciclo per trovare la posizione della prima occorrenza di una stringa inclusa in un'altra a partire dalla destra della stringa. Un po come InStrRev di VB. C_INTEGER($Pos;$start;$lengthfound;$Result) C_TEXT($Temp) // Ricava la path della cartella preferenze // Replace string(... Aggiunge un Folder separator alla stringa ricavata: // Se Folder separator esiste, sostituisce i due Folder separator risultanti con una stringa vuota // Se Folder separator esiste, non fa' nulla // In ogni caso la stringa ricavata non terminerà con Folder separator ! $Temp:=Replace string(Get 4D folder(Active 4D Folder)+Folder separator;Folder separator+Folder separator;"") $Pos:=0 $start:=1 Repeat $Result:=Position(Folder separator;$Temp;$start;$lengthfound) If ($Result#0) $Pos:=$Result End if $start:=$start+$lengthfound Until ($Result=0) <>g_PathPreferences:=Substring($Temp;1;Length(Substring($Temp;1;$Pos)))+Folder separator Sicuramente funzionante ma, a mio avviso, un po' troppo 'contorta'. Si puo' semplificare cosi: C_TEXT($Temp) C_INTEGER($Conta) // Ricava la path della cartella preferenze $Temp:=Replace string(Get 4D folder(Active 4D Folder)+Folder separator;Folder separator+Folder separator;"") For ($Conta;Length($Temp);1;-1) If (Substring($Temp;$Conta;1)=Folder separator) $Temp:=Substring($Temp;1;$Conta) $Conta:=1 End if End for <>g_PathPreferences:=$Temp+Folder separator Oltre ad avere un codice piu' leggibile, abbiamo risparmiato tre righe di procedura (a parte le note) e dichiarato due variabili contro cinque della procedura precedente. Non è il massimo ...ma con la crisi che incombe, bisogna centellinare tutto. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Creare un file di testi UTF-8 con BOM
Il testo in 4d era in Mac ASCII fino alla versione 2004, dalla v11 è in UTF-16 (a meno che non abbiate lasciato la compatibilità Ascii del db) Quando si esporta un file in Unicode è necessario normalmente indicare in che formato sono i caratteri che occupano 2 byte (big-endian o little-endian) con un prefisso chiamato un BOM (Byte Order Mark). In realtà in UTF-8 si tende ad esportare i caratteri in byte singoli quindi in linea di massima non ci sono problemi di ordinamento dei byte, e non servirebbe. Però alcune applicazioni se lo aspettano comunque, quindi a volte è necessario aggiungerlo, come ad esempio con questa procedura: C_TEXT($1;$testo_t) C_BLOB($blob_b;$bom_b) $testo_t:=$1 SET BLOB SIZE($bom_b;3) $bom_b{0}:=239 ` EF $bom_b{1}:=187 ` BB $bom_b{2}:=191 ` BF CONVERT FROM TEXT($testo_t;"UTF-8";$blob_b) $doc_h:=Create document("") If (OK=1) SEND PACKET($doc_h;$bom_b) SEND PACKET($doc_h;$blob_b) CLOSE DOCUMENT($doc_h) End if |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
[v13] Nuova funzionalità dei comandi statistici
I comandi Average, Max, Min, Std deviation, Sum, Sum squares e Variance che storicamente si usavano solo nella stampa dei rapporti (dopo un comando Accumulate) adesso funzionano anche sulla selezione corrente o su un array. L'effetto sulla ottimizzazione del codice è immediato: dove prima ad esempio per avere la somma di un array occorreva ciclare sui suoi elementi adesso basta scrivere $totale:=Sum($array). |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Metodo alternativo per riempire una Popup Drop Down List
Uso questo metodo nell'oggetto Popup cmb_Cliente che risolve velocemente il problema del valore di default quando un database è completamente vuoto. Case of : (Form event=On Load) ARRAY LONGINT(cmb_CodCliente;0) ARRAY TEXT(cmb_Cliente;0) ALL RECORDS([Clienti]) SELECTION TO ARRAY([Clienti]Progressivo;cmb_CodCliente; [Clienti]Rag_Sociale;cmb_Cliente) If (Size of array(cmb_CodCliente)>0) If (Is new record([Stabilimenti])) //nuova scheda cmb_Cliente:=1 //mostra un valore di default cmb_CodCliente:=cmb_Cliente Else //se ci sono record, cerca il codice nel vettore cmb_CodCliente // Se Find in array ritorna -1 verrà generato un errore // Usando Abs(Find in array..... restituira -1 (quindi 1) cmb_CodCliente:=Abs(Find in array(cmb_CodCliente;[Stabilimenti]Cod_Cliente)) cmb_Cliente:=cmb_CodCliente End if End if : (Form event=On Clicked) If (cmb_Cliente#0) cmb_CodCliente:=cmb_Cliente [Stabilimenti]Cod_Cliente:=cmb_CodCliente{cmb_CodCliente} End if : (Form event=On Unload) CLEAR VARIABLE(cmb_CodCliente) CLEAR VARIABLE(cmb_Cliente) End case |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Data e ora in formato XML
Il formato XML di data e ora è il seguente AAAA-MM-GGTHH:MM:SS. Il vantaggio di questa stringa è che è ordinabile, contiene la coppia dei dati e quindi è più leggibile del timestamp (che rimane però più efficiente e consuma meno spazio su disco e in memoria come indice). Ecco alcuni trucchi per convertire una data in questo formato e viceversa (non documentati, mi sembra) in 4d 2004.3: Date("2006-01-24T00:00:00") -> ritorna effettivamente la data 24 gen 2006: Importante funziona solo se la stringa è lunga 19 caratteri e la data è seguita dal separatore "T". String(current date;8) -> ritorna la data nel formato XML completa di separatore = "2006-01-24T00:00:00" Per avere data e ora si può usare questa semplice riga: Replace string(String(Current date;8);"00:00:00";String(Current time;1)) |
1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Copiare negli appunti il contenuto di una listbox
Il seguente metodo prende come parametri il puntatore ad una listbox, il separatore fra le colonne e quello fra le righe per inserire negli appunti il contenuto della listbox stessa. C_POINTER($1;$lbPointer_p) C_TEXT($2;$columnSeparator_t) C_TEXT($3;$rowSeparator_t) C_LONGINT($i;$numRows_l) C_LONGINT($j;$numCols_l) C_TEXT($theData_t) ARRAY TEXT($colNames_at;0) ARRAY TEXT($headerNames_at;0) ARRAY POINTER($colVars_ap;0) ARRAY POINTER($headerVars_ap;0) ARRAY BOOLEAN($colsVisible_ab;0) ARRAY POINTER($styles_ap;0) $lbPointer_p:=$1 If (Count parameters>1) $columnSeparator_t:=$2 $rowSeparator_t:=$3 Else $columnSeparator_t:=Char(Tab) $rowSeparator_t:=Char(Carriage return) End if LISTBOX GET ARRAYS($lbPointer_p->;$colNames_at;$headerNames_at;$colVars_ap;$headerVars_ap;$colsVisible_ab;$styles_ap) $numRows_l:=Size of array($colVars_ap{1}->) $numCols_l:=Size of array($colNames_at) For ($i;1;$numRows_l) For ($j;1;$numCols_l) If ($colsVisible_ab{$j}=True) If ($j#1) $theData_t:=$theData_t+$columnSeparator_t End if $theData_t:=$theData_t+String($colVars_ap{$j}->{$i}) End if End for If ($i<$numRows_l) $theData_t:=$theData_t+$rowSeparator_t End if End for SET TEXT TO PASTEBOARD($theData_t) ----------- Da notare come: - il comando String può ricevere come parametro anche una stringa; - per testi grandi il testo potrebbe essere prima inserito il un BLOB. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Estrarre tutti gli URL da un testo
Col seguente metodo l'array URL_a viene popolato con gli URL che contiene myString: ARRAY LONGINT(posFound_a;0) ARRAY LONGINT(lengthFound_a;0) ARRAY TEXT(URL_a;0) C_LONGINT($start) C_TEXT($mySubstring;myString;$1) C_TEXT(stringNew; pattern) C_BOOLEAN($found) myString:=$1 $start:=1 $found:=False pattern:="(http|https|ftp)" ` http o https, o ftp. pattern:=pattern + "\\://" ` :// pattern:=pattern + "[a-zA-Z0-9\\-\\.]+" `la prima parte del dominio pattern:=pattern + "\\.[a-zA-Z]{2,4}" `la seconda parte pattern:=pattern + "(:[a-zA-Z0-9]*)?/?" `la porta e lo slash pattern:=pattern + "([a-zA-Z0-9\\-\\._?\\,'/\\+%\\$#\\=~\\:\\&])*" `Caratteri riservati pattern:=pattern + "[^\\.\\,\\)\\(\\s\\']" `Caratteri da escludere Repeat $found:=Match regex(pattern;myString;$start;posFound_a;lengthFound_a) stringNew:=Substring(myString;posFound_a{0};lengthFound_a{0}) If ($found) APPEND TO ARRAY(URL_a;stringNew) End if $start:=posFound_a{0}+lengthFound_a{0} Until (Not($found)) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Ottenere la lista di tutte le relazioni di un database
Utilizzando i comandi SQL è possibile interrogare la tabella di sistema _USER_CONSTRAINTS per ottenere in una listbox chiamata ListBox_Relations l'elenco di tutte le relazioni presenti in un database o loro proprietà. ----- Un primo esempio Begin SQL SELECT * FROM _USER_CONSTRAINTS WHERE CONSTRAINT_TYPE = 'P' INTO LISTBOX :miaListBox; End SQL per ottenere l'elenco di tutte le chiavi primarie utilizzate. ----- Un secondo esempio Begin SQL SELECT * FROM _USER_CONSTRAINTS WHERE CONSTRAINT_TYPE = 'R' INTO LISTBOX :miaListBox; End SQL per l'elenco delle chiavi esterne. ----- Per l'elenco completo Begin SQL SELECT * FROM _USER_CONSTRAINTS INTO LISTBOX :miaListBox; End SQL |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
Esempi di Replicate in Campi e in Array
Il comando Replicate eseguito su un 4d (Locale) permette di leggere da un 4d (Remoto) gli ultimi record modificati/cancellati dopo l'ultima lettura, per avere la "replica" aggiornata di alcune tabelle. La sintassi minima è la seguente: REPLICATE campoid, campo1, campo2, campo3 FROM tabellaRemota FOR REMOTE STAMP :vRemote_Stamp REMOTE OVER LOCAL LATEST REMOTE STAMP :vRiceviCorrenteUltimoStam INTO localTable(campoid, campo1, campo2, campo3); Da notare che in vRiceviCorrenteUltimoStam arriva l'ultimo Stamp corrente da conservare per usarlo nella prossima volta che si fa la stessa chiamata. Questa di seguito è la versione completa dei parametri opzionali, con una clausola WHERE per selezionare i record da tagliare, con la LIMIT e la conseguente OFFSET per tagliare l'esportazione in più parti REPLICATE campoid, campo1, campo2, campo3 FROM tabellaRemota WHERE tabellaRemota.campox=:vCondizione LIMIT :vLimit_Value OFFSET :vOffset_Value FOR REMOTE STAMP :vRemote_Stamp, LOCAL STAMP :vLocal_Stamp REMOTE OVER LOCAL /*oppure LOCAL OVER REMOTE*/ LATEST REMOTE STAMP :vRiceviCorrenteUltimoStam, LATEST LOCAL STAMP :vLatest_Local_Stamp INTO localTable(campoid, campo1, campo2, campo3); Da notare che posso leggere i dati senza doverli appoggiare su una tabella, ma solo in array. REPLICATE campoid, field1, field2, field3 FROM remoteTable FOR REMOTE STAMP :vRemote_Stamp REMOTE OVER LOCAL LATEST REMOTE STAMP :vRiceviCorrenteUltimoStam INTO :aID, :aCampo1, :aCampo2, :aCampo3; REPLICATE campoid, campo1, campo2, campo3 FROM tabellaRemota WHERE tabellaRemota.campox=:vCondizione LIMIT :vLimit_Value OFFSET :vOffset_Value FOR REMOTE STAMP :vRemote_Stamp, LOCAL STAMP :vLocal_Stamp REMOTE OVER LOCAL /*oppure LOCAL OVER REMOTE*/ LATEST REMOTE STAMP :vRiceviCorrenteUltimoStam, LATEST LOCAL STAMP :vLatest_Local_Stamp INTO :aID, :aCampo1, :aCampo2, :aCampo3; |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
[v13] Confronta due Immagini con Equal Pictures
Il comando Equal pictures confronta precisamente due immagini per dimensione e contenuto. Il comando accetta 3 parametri: i primi 2 sono le immagini da confrontare, nel terzo si troverà un'immagine maschera con a nero i pixel identici. Ritorna False se le dimensioni non sono uguali. Se le dimensioni sono uguali il confronto è a livello di pixel, e nella maschera viene 'acceso' in bianco il pixel che segna la differenza. Se non ci sono differenze neanche a livello di pixel il comando ritorna True. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Sintassi 4D SQL : INNER JOIN
Una inner join crea una griglia di dati combinando i valori delle due tabelle di partenza (A and B) basandosi su una certa regola di confronto: la query compara ogni riga della tabella A con ciascuna riga della tabella B cercando di soddisfare la regola di confronto definita. Esempio, date queste due tabelle di dati: Tabella Aziende
Tabella Contatti
Begin SQL SELECT Cognome,Aziende.Ragione_Sociale FROM Contatti INNER JOIN Aziende ON Contatti.ID_Azienda=Aziende.ID_Azienda INTO :ArrCognome,:ArrRagSociale; End SQL Risultato:
|
1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Sintassi 4D SQL : RIGHT OUTER JOIN
Una right outer join (o right join) semplicemente ricalca il funzionamento della left outer join, ma invertendo l'ordine delle tabelle interessate. Il risultato di una query right outer join per le tabelle A e B contiene sempre tutti i record della tabella di destra ("right") B, mentre vengono estratti dalla tabella di sinistra ("left") A solamente le righe che trovano corrispondenza nella regola di confronto della join. Questo significa che se la clausola ON trova 0 (zero) righe in A, la join mostrerà una riga risultante con valore NULL in tutte le colonne corrispondenti al risultato per le colonne di A. Esempio, date queste due tabelle di dati: Tabella Aziende
Tabella Contatti
Begin SQL SELECT Cognome,Aziende.Ragione_Sociale FROM Contatti RIGHT OUTER JOIN Aziende ON Contatti.ID_Azienda=Aziende.ID_Azienda INTO :ArrCognome,:ArrRagSociale; End SQL Risultato:
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Sintassi 4D SQL : LEFT OUTER JOIN
Il risultato di una query left outer join (o semplicemente left join) per le tabelle A e B contiene sempre tutti i record della tabella di sinistra ("left") A, mentre vengono estratti dalla tabella di destra ("right") B solamente le righe che trovano corrispondenza nella regola di confronto della join. Questo significa che se la clausola ON trova 0 (zero) righe in B, la join mostrerà una riga risultante con valore NULL in tutte le colonne corrispondenti al risultato per le colonne di B. Esempio, date queste due tabelle di dati: Tabella Aziende
Tabella Contatti
Begin SQL SELECT Cognome,Aziende.Ragione_Sociale FROM Contatti LEFT OUTER JOIN Aziende ON Contatti.ID_Azienda=Aziende.ID_Azienda INTO :ArrCognome,:ArrRagSociale; End SQL Risultato:
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
SIntassi 4D SQL : FULL OUTER JOIN
Una full outer join combina i risultati delle due tabelle A e B tenendo conto di tutte le righe delle tabelle, anche di quelle che non hanno corrispondenza tra di loro. Il risultato di una query full outer join per le tabelle A e B contiene sempre tutti i record della tabella di sinistra ("left") A, estraendo dalla tabella di destra ("right") B solamente le righe che trovano corrispondenza nella regola di confronto della join; inoltre verranno estratti tutti i record della tabella di sinistra ("left") A che non trovano corrispondenza nella tabella di destra ("right") B impostando a NULL i valori di tutte le colonne della tabella B e tutti i record della tabella di destra ("right") B che non trovano corrispondenza nella tabella di sinistra ("left") A impostando a NULL i valori di tutte le colonne della tabella A. Esempio, date queste due tabelle di dati: Tabella Aziende
Tabella Contatti
Begin SQL SELECT Cognome,Aziende.Ragione_Sociale FROM Contatti FULL OUTER JOIN Aziende ON Contatti.ID_Azienda=Aziende.ID_Azienda INTO :ArrCognome,:ArrRagSociale; End SQL Risultato:
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Evoluzione delle list box
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Sintassi 4D SQL : CROSS JOIN
Una cross join fornisce le basi attraverso cui tutti i tipi di inner join operano. Il risultato di una cross join è il prodotto cartesiano di tutte le righe delle tabelle che concorrono alla query di join. E' come dire che stiamo facendo una inner join senza impostare la regola di confronto o in cui la regola di confronto ritorna sempre vero. Esempio, date queste due tabelle di dati: Tabella Aziende
Tabella Contatti
Begin SQL SELECT Cognome,Aziende.Ragione_Sociale FROM Contatti CROSS JOIN Aziende ON Contatti.ID_Azienda=Aziende.ID_Azienda INTO :ArrCognome,:ArrRagSociale; End SQL Risultato:
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Verifica da codice se Quicktime è installato
Su Windows le librerie di Quicktime potrebbero non essere installate e alcune immagini registrate con un 4d precedente alla v11 potrebbero non vedersi: appare in questo caso un riquadro bianco con la scritta del tipo "Quicktime is required" ARRAY TEXT($identificativi_at;0) ARRAY TEXT($nomi_at;0) PICTURE CODEC LIST($identificativi_at;$nomi_at) If (Find in array($identificativi_at;".qtif")<0) // Tipo immagine QuickTime ALERT("QuickTime non è installato.") End if |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Convertire le immagini per non dipendere da Quicktime
A partire dalla v11 le immagini in 4D non sono più salvate come PICT, ma nel loro formato originale. Però se abbiamo convertito un db ci potrebbero essere delle immagini che richiedono Quicktime per essere viste su Windows. Per eliminare la necessità di questa installazione è possibile usare il comando CONVERT PICTURE, come ad esempio: ALL RECORDS([MieImmagini]) While (Not(End selection([MieImmagini]))) CONVERT PICTURE([MieImmagini]Immagine;".jpg") SAVE RECORD([MieImmagini]) NEXT RECORD([MieImmagini]) End while Dalla v12 questo comando permette anche la compressione del JPEG con questa sintassi: CONVERT PICTURE([MieImmagini]Immagine;".jpg"; 0.6) NOTA: Ovviamente per essere eseguita questa procedura richiede Quicktime, la volta in cui viene eseguita. cfr Verifica da codice se Quicktime è installato |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
iPad e 4D
Le alternative per utilizzare l'ipad o l'iphone collegandolo a 4d sono, partendo dalle più facili: 1. utilizzare un app tipo iSort pro: l'app costa veramente poco ed è subito disponibile, su 4d serve la licenza web contro: le possibilità di personalizzazione sono poche, e non si può programmare lato ipad (Apple vieta esecuzione di codice nelle app) 2. preparare delle pagine web servite da 4d, semplici senza usare ajax o framework pro: sviluppo semplice, il safari di iPad è un browser vero e completo, compatibile con html5, css e javascript contro: funziona bene se c'è sempre copertura, ad esempio usandolo in area coperta da wifi 3. preparare delle pagine web servite da 4d, utilizzando ajax o framework pro: puoi usare degli oggetti più completi, come griglie di dati, se perdi il collegamento potresti usare i dati offline contro: comunque serve la connessione internet attiva, una parte di programmazione si sposta su javascript 4. scrivere un programma in objective c pro: puoi scriverti un'applicazione completa registrando in locale i dati sui cui lavorare, scaricando e inviando solo ogni tanto gli aggiornamenti Il collegamento a 4d si può fare : - via web utilizzando l'url speciale 4DSYNC che sfrutta la funzionalità di sincronizzazione inclusa in v12 (cfr iPhone, iPad, Android e l'url 4DSYNC - via webservice o semplice chiamata GET (/4daction/metodo/parametro..); 4d può essere sia server che monoutenza con licenza web - via file: l'app può scaricare un file postato in una directory web con autenticazione, può inviare i dati in formato POST; si perde il realtime, ma non serve licenza web contro: è più lungo scrivere in obiettive e si devono valutare bene le modalità di distribuzione, che riporto: - app ad hoc: si installa su un massimo di 100 ipad/iphone per sviluppatore (l'elenco si può resettare solo 1 volta all'anno) - app enterprise: l'azienda cliente si registra come Enterprise a 299$ anno può installare su quanti ipad vuole - app su appstore: i limiti sono quelli delle regole di approvazione Apple, i tempi di rilascio sono di 5-10 giorni per ogni aggiornamento |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Cambiare un valore in più record con una solo Update SQL
Questo codice è un esempio di SQL con cui è possibile modificare un valore in diversi record con un unico comando. Presupponendo che abbiamo una Tabella in cui i record hanno un campo Codice e un campo Nome, il comando nel formato Begin SQL sarà così: Begin SQL update [Tabella] set Nome = CASE Codice when 1 then 'NomeUno' when 2 then 'NomeDue' when 3 then 'NomeTre' end where codice in (1,2,3) end sql In pratica: 1) il WHERE campo IN (n,n,..) mi seleziona i record il cui Codice è nella lista 2) il CASE ritorna il valore desiderato al variare del campo Codice |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Creazione manuale di uno "UserSet"
Lo "UserSet" è lo speciale set che contiene i record selezionati dall'utente nel form di output. Quando serve è comunque possibile popolarlo "manualmente": se abbiamo un array contenente dei record number, è possibile scrivere: CREATE SET FROM ARRAY([Table];$arrRecNum;"UserSet") per simulare la selezione dei record "manuale" da parte dell'utente. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Linee di codice su più righe
Come si può facilmente vedere, dalla 4D v12 è stato radicalmente modificato il method editor. Una delle modifche più utili riguarda la possibilità di poter mandare a capo le righe in modo da avere un'istruzione più facilmente leggibile (si pensi, ad esempio, alle righe infinite di estesi SELECTION TO ARRAY). Adesso basta far finire una riga col carattere "\" e ill testo della riga successiva verrà considerato come prosecuzione dell'attuale. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Attributo per Eseguire i metodi sul server
Utilizzando la nuova opzione "Execute in server" per i metodi, bisogna ricordare che: - il processo sul server non è creato al momento, ma usa il processo "gemello" che gira sul server - il metodo su server considera i record bloccati e le transazioni, ma non tiene conto dei valori delle variabili sul client e non mantiene la selezione corrente. - le variabili processo del metodo sul server persistono (con valore) anche dopo la conclusione del processo stesso sul server - se passi un puntatore ad una variabile o un array il valore puntato è inviato al server e ritornato al client se modificato Sul server non possono essere eseguiti alcuni comandi: se provi a farlo apparirà una finestra di dialogo. Alcuni comandi non funzionanti nei metodi sono: Comandi correlati all'interfaccia ADD RECORD ADD SUBRECORD DISPLAY SELECTION FILTER EVENT GRAPH TABLE Level ON EVENT CALL MODIFY RECORD MODIFY SELECTION MODIFY SUBRECORD Open external window QUERY BY EXAMPLE QR REPORT Comandi di struttura CHANGE LICENSES CREATE DATA FILE EDIT ACCESS OPEN DATA FILE CALL PROCESS Comandi sulle risorse SET PICTURE TO LIBRARY REMOVE PICTURE FROM LIBRARY SET PICTURE TO LIBRARY Comandi per la gestione dei menu APPEND MENU ITEM Count menu items Count menus DELETE MENU ITEM DISABLE MENU ITEM ENABLE MENU ITEM Get menu item Get menu item key Get menu item mark Get menu item style Get menu title INSERT MENU ITEM Menu selected SET MENU ITEM SET MENU ITEM SHORTCUT SET MENU ITEM MARK SET MENU ITEM STYLE SHOW MENU BAR Comandi per la stampa ACCUMULATE BREAK LEVEL PAGE BREAK PAGE SETUP PRINT SETTINGS Printing page Subtotal |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Scaricare le mail con IMAP
Dovendo scaricare da Gmail gli aggiornamenti del gruppo Sviluppo4D su Facebook inviati da Umberto in occasione del summit di Boston, ecco il codice utilizzato all'uopo. C_TEXT($msgText) READ WRITE([Posta]) $error:=0 $sslPOPPort:=995 $Errore_l:=IT_SetPort (13;$sslPOPPort) //12 is for 'SMTP with SSL' $error:=IMAP_Login ("pop.gmail.com";"indirizzo@gmail.com";"password";$imapID;1) $error:=IMAP_SetCurrentMB ($imapID; "4D Summit 2011"; $msgNber; $newMsgNber; $customFlags; $permanentFlags; $mbUID) For ($i;1;$msgNber) CREATE RECORD([Posta]) msgDataItem:="INTERNALDATE" $Err:=IMAP_MsgFetch ($imapID;$i;msgDataItem;$text) $position:=Position(" ";$text) $text:=Delete string($text;1;$position) $error:=IMAP_GetMessage ($imapID;$i;0;31000;2;$msgText;1) $datrovare:="nel gruppo Sviluppo4D" $position:=Position($datrovare;$msgText) $msgText:=Delete string($msgText;1;$position+Length($datrovare)+2) $datrovare:="Per commentare" $position:=Position($datrovare;$msgText) $msgText:=Delete string($msgText;$position-2;Length($msgText)) [Posta]msg_body:=$msgText [Posta]msg_ID:=$i SAVE RECORD([Posta]) UNLOAD RECORD([Posta]) End for $error:=IMAP_Logout($imapID) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Spostare i dati di una tabella in un database esterno
Nella v12 è possibile usare database esterni: ecco un esempio veloce per trasferire i dati da una tabella locale nell'equivalente tabella sul db esterno. ALL RECORDS([Tabella]) SQL EXPORT SELECTION([Tabella];$percorsoAppoggio) Begin SQL USE DATABASE DATAFILE :$percorsoDB; End SQL $importa:=$percorsoAppoggio+Folder separator+ importa:=importa+"SQLExport"+Folder separator importa:=importa+"Export.sql" SQL EXECUTE SCRIPT($importa;SQL On error abort) Begin SQL USE DATABASE SQL_INTERNAL; End SQL |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Salvare le modifiche alla Struttura
Sin dalla versione v11, anche la struttura di 4d è un database e gli aggiornamenti fatti in fase di sviluppo seguono le stesse regole delle modifiche ai dati. Se 4d si chiude inaspettatamente si potrebbero perdere le ultime modifiche fatti (modifiche al codice o ai form, ad esempio). Per forzare il salvataggio si può: - compilare - passare da Design mode ad Application mode (e viceversa) - eseguire il comando FLUSH BUFFERS |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Stampare una Rich Text Area
Ecco di seguito il codice di un pulsante che permette di stampare il contenuto di una Rich Text Area memorizzato nel campo [Tabella]MioTesto: Case of : (Form event=On Clicked) PRINT SETTINGS If (ok=1) OPEN PRINTING JOB If (ok=1) OPEN PRINTING FORM("Form1") vStampa:=OBJECT Get styled text([Tabella]MioTesto) $complete_b:=Print object(*;"vStampa") CLOSE PRINTING JOB End if End if End case |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
Comandi rinominati dalla v11 alla v12
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
Comandi rinominati dalla 2004 alla v11
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
[v12] Cut & Paste tra le strutture delle tabelle
Con la versione 12 è possibile copiare le definizioni dei campi da una tabella ad un'altra. Nella maschera "Structure" prendi la tabella di partenza, selezioni i campi che ti servono nella nuova tabella. Effettui il copia (mela+c o ctrl+c). Selezioni la tabella di destinazione ed effettui incolla (mela+v o ctrl+v). 4D ti genera nella nuova tabella i campo con nomi e proprietà identiche ai campi selezionati nella tabella di partenza. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Porte TCP per la connessione ad un 4d Server
Per il collegamento da un Client a 4D Server le porte TCP di default sono: 19813 - Application server 19814 - DB4D server 19812 - SQL server Sulla porta DB4D sono veicolate tutte le chiamate al database, un socket per ogni processo divise poi sul server in thread differenti. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
[v12.2] Comando FORM SCREENSHOT
Dalla versione 12.2 è disponibile il nuovo comando FORM SCREENSHOT che accetta due sintassi: FORM SCREENSHOT ( formPict ) Crea una schermata del form corrente al momento FORM SCREENSHOT ( {aTable ;} formName ; formPict {; pageNum} ) Crea una schermata di un form del database come vista nel form editor |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
La posizione attuale in un array di grandi dimensioni
La variabile che indica la posizione attuale in un array è automaticamente dichiarata come Integer, tipo che ha il limite di 32767. Questo significa che il codice: ARRAY TEXT($largeArray_at;33000) For ($i;1;33000) $largeArray_at{$i}:=String($i) End for $largeArray_at:=32768 $element:=$largeArray_at{$largeArray_at} `errore produce errore poiché la variabile $largeArray_at non è stato dichiarato. La soluzione è quindi dichiarare come Longint le variabili da usare come indici di puntatori ad array di grandi dimensioni. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
Reindirizzare l'output di LAUNCH EXTERNAL PROCESS
I parametri aggiuntivi di LAUNCH EXTERNAL PROCESS permettono di riempire una variabile $output con lo standard output del comando lanciato. Ecco un esempio. C_TEXT($input;$error;$output) $input:=Char(34)+$percorsoprogramma+Char(34)+" "+$altriparametri+Char(13)+Char(10) SET ENVIRONMENT VARIABLE("_4D_OPTION_HIDE_CONSOLE";"true") LAUNCH EXTERNAL PROCESS("cmd.exe";$input;$output;$error) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Utilizzare SVG per trovare la dimensione di un testo
E' possibile usare i comandi SVG per conoscere la dimensione di un testo. Analizziamo il seguente codice: C_PICTURE(immagine) C_TEXT(root;ref) C_LONGINT(larghezza;altezza) root:=DOM Create XML Ref("svg";"http://www.w3.org/2000/svg") ref:=DOM Create XML element(root;"text";\ //crea il testo "font-family";"Arial";\ //set font "font-size";"11";\ //set size "font-weight";"bold";\ //set style "y";"1em") //set Y coordinate DOM SET XML ELEMENT VALUE(ref;"TESTO DI ESEMPIO") SVG EXPORT TO PICTURE(root;immagine;Get XML Data Source) DOM CLOSE XML(root) PICTURE PROPERTIES(immagine;larghezza;altezza) Il codice crea l'XML che corrisponde a un SVG che possiamo poi trasformare in immagine e conoscerne la dimensione. In larghezza e altezza avremo quindi la dimensione del testo. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Modificare la cella di una listbox con un solo clic
Per modificare l'elemento di una list box è necessario cliccarci due volte: il primo clic seleziona l'elemento, il secondo lo rende modificabile. Per fare in modo che un clic renda direttamente modificabile l'elemento si può uasre il seguente codice: Case of : (Form event=On Clicked ) ` mi asssicuro che non stia facendo una selezione mutipla If (Not(Shift down | Windows Ctrl down)) LISTBOX GET CELL POSITION(*;"ListBox";col;row;colVar_p) EDIT ITEM(colVar_p->;row) End if End case |
1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Nomi di variabili riservati
I seguenti nomi di variabili sono riservati a 4D: C1, C2, C3, C4, C5, ecc. (usate nei report) OK Document Error KeyCode Modifiers MouseDown MouseProc MouseX MouseY FldDelimit RecDelimit Non devono dunque essere usate se non nel contesto cui si riferiscono: ad esempio Document contiene il percorso del documento dopo aver usato Open document, Create document o Append document ed è stato scelto un file mostrando la dialog di sistema per l'apertura o il salvataggio di un file. |
1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
4D v12: help tip automatici per i metodi
Il method editor di 4D nella v12 è stato completamente riscritto. Tra le novità, una molto utile è la possibilità di visualizzare un help tip per i comandi di 4D, con definizione e una breve descrizione. Possiamo però fare la stessa cosa anche con i nostri metodi: infatti, portando il mouse su un nostro metodo, non abbiamo bisogno di aprirlo per vedere cosa faceva perché come help tip vengono visualizzate tutte le righe iniziali del metodo che siano commento (e che non siano quindi codice). Prendendo quindi l'abitudine di commentare i metodi nella loro parte iniziale con la loro definizione e descrizione, diventerà agevole conoscere le info sul nostro codice. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
SVG: conoscere gli attributi di un oggetto
Per conoscere tutte le proprietà legate (e quindi configurabili) di un oggetto in un'area SVG si usa il comando SVG_GET_ATTRIBUTES. Esso popola due array con i nomi e i valori degli attributi. Se $ref è l'ID dell'oggetto, utilizzeremo: ARRAY TEXT($arrNames;0) ARRAY TEXT($arrValues;0) SVG_GET_ATTRIBUTES ($ref;->$arrNames;->$arrValues) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Visualizzare interamente le variabili testo in fase di debug
Volevo solo segnalarvi un modo per poter vedere il contenuto di variabili testo molto grosse durante il debug. Io mi sono trovato molto spesso in condizioni simili e devo dire che era molto difficile vedere il contenuto dopo un certo numero di caratteri. Molti usavano (io compreso) la save su disco per poterla aprire poi con un altro programma e controllarne il contenuto. Io mi sono trovato spesso a dover vedere il contenuto di una variabile che era un file xml, ed era molto frustante dover interrompere il debug per mettere codice per salvare il file. Un metodo semplice ed efficace è quello di usare il comando : SET TEXT TO PASTEBOARD ( text ) Quindi quando siete fermi sul vostro break nel riquadro delle variabili inserite il comando, sostituite "text" con la vostra variabile e a quel punto avrete il contenuto nel clipboard. Facendo incolla su textedit avrete il contenuto della variabile ben leggibile. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
SVG: inserire un testo con vari formati
Se all'interno della stessa area di testo SVG devo inserire diversi stili (ad esempio una parola in tondo, una seconda in grassetto e una terza in corsivo), il comando da utilizzare è SVG_New_tspan. A differenza della gran parte dei comandi SVG, SVG_New_tspan prende come parametro l'ID dell'area di testo (definita da un precedente SVG_New_text o SVG_New_tspan) a cui il nuovo testo deve essere collegato. Quindi: $textID:=SVG_New_text($SVG;"Scrivere ";10;10;"arial";12) SVG_SET_FONT_SIZE(SVG_New_tspan($textID;"con ");14) SVG_SET_FONT_SIZE(SVG_New_tspan($textID;"SVG ");18) SVG_SET_FONT_SIZE(SVG_New_tspan($textID;"è ");24) SVG_SET_FONT_SIZE(SVG_New_tspan($textID;"facile");36) definisce l'area di testo, quindi inserisce il testo aggiuntivo, modificandone al volo la dimensione. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
SVG: inserire un testo semplice
Il modo più agevole per inserire un testo in un'area SVG è il comando SVG_New_text. Il suo uso più semplice è: $SVG:=SVG_New $textID:=SVG_New_text($SVG;"Test SVG") che crea un'area SVG e scrive il testo desiderato. I parametri aggiuntivi utilizzabili sono svariati e permettono di impostare posizione del testo, dimensione, allineamento, stile e tipo del carattere, rotazione e spaziatura. La sintassi completa è: SVG_New_text ( parentSVGObject ; text {; x {; y {; font {; size {; style {; alignment {; color {; rotation {; lineSpacing {; stretching}}}}}}}}}} ) Il comando restituisce l'ID dell'elemento inserito. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Standard supportati da 4D
Ecco un elenco dei vari standard:
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Macro |
[4D Pop] Macro : Incolla Speciale
Fra i vari strumenti della palette 4dPop (inclusa nell'ambiente di sviluppo di 4d) ce n'è uno tanto pieno di funzioni quanto poco notato dai programmatori: 4DPop Macros. Oggi parliamo della macro Incolla Speciale, che elabora un testo prima di incollarlo nel codice. Richiamandola, ci sono diverse opzioni da scegliere e un'area di anteprima: String Incolla il testo fra apici e sostituendo i caratteri speciali (return, tab, etc) con gli equivalenti per le stringhe (\r, \t, etc) Comments Incolla il testo già commentato HTML Incolla il testo spezzandolo in diverse righe e aggiungendolo ad una variabile testo (utile per generare via codice una pagina web) Regex Pattern Incolla il testo sostituendo i caratteri sinificativi per le regex con l'equivalente con lo slash (ad esempio * diventa \*) Code from 4D v11 FR Incolla il testo traducendolo dal codice di 4d in francese, utile ad esempio per utilizzare un metodo inviato sul forum di 4d da un francese. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Macro |
[4D Pop] Macro : Dichiarazioni
Fra i vari strumenti della palette 4dPop (inclusa nell'ambiente di sviluppo di 4d) ce n'è uno tanto pieno di funzioni quanto poco notato dai programmatori: 4DPop Macros. Oggi parliamo della sola macro Dichiarazioni, che scrive automaticamente le dichiarazioni per le variabili locali in un metodo. Richiamandola, appare una maschera dove compare la lista delle variabili: - In grassetto quelle riconosciute - In grassetto sottolineato gli array riconosciuti - In corsivo le variabili da identificare Alla destra della lista sono elencati i tipi da assegnare alle variabili non riconosciute, con la possibilità di usare la tastiera per velocità. In realtà, se si usa una nomenclatura delle variabili coerente, esiste la possibilità che questa macro assegni automaticamente i tipi senza il nostro intervento. Usando il tasto Options si accede ad un pannello dove è possibile indicare lo schema usato nei propri programmi per assegnare i nomi, ad esempio: Lon_* = indica le variabili che iniziano per "Lon_" *Lon_* = indica le variabili che contengono "Lon_" *A(\d\d)_* = indica le variabili che iniziano per A seguita da 2 cifre |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Come aggiungere un campo di ricerca ad un form
Con la v12 sono disponibili degli oggetti (chiamati widget) che sono predisposti per essere riutilizzati nelle maschere di 4d. Ad esempio si può trovare il campo di ricerca (con stile differente su Mac e su Windows) che si chiama SearchPicker. Per utilizzarlo si può: - sceglierlo dalla libreria degli oggetti (nella v12 icona dei libri nella barra superiore del form editor) oppure - creare un subform e assegnarli il tipo "Detail" col nome "SearchPicker" Il subform avrà una variabile che è quella che contiene il valore inserito; il pulsantino di cancellazione è automatico, mentre il testo in grigio (il suggerimento) che sparisce appena si scrive viene definito con il comando SearchPicker SET HELP TEXT. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Farsi avvisare da 4d se un backup non ha avuto successo
Il backup di solito viene lanciato in ore notturne o quando non ci sono normalmente utenti online; oppure il server non è facilmente accessibile... come fare a controllare che il backup sia andato a posto? E' possibile utilizzare il metodo Database che si chiama "On Backup Shutdown Database Method"; questo metodo viene chiamato automaticamente alla fine del processo di backup, con parametro $1 = 0 se tutto è andato a posto o # 0 se ci sono stati problemi. C_LONGINT($1;$backupStatus) C_DATE($data) C_TIME($ora) C_REAL($num) C_TEXT($status) $backupStatus:=$1 If ($backupStatus#0) GET BACKUP INFORMATION(Last Backup Date ;$data;$ora) GET BACKUP INFORMATION(Last Backup Status ;$num;$status) $messaggio:="Errore nel backup numero "+string($backupStatus)+"\r\r" $messaggio:=$messaggio+"Ultimo Backup: "+String($data)+" alle "+String($ora)+"\r" $messaggio:=$messaggio+"Stato: "+$status $res:=smtp_quickSend(<>serverSmtp ; <>mailMittente ; <>mailDestinatario ; "Errore durante il backup"; $messaggio) End if |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
[12.2] Nuovi tag HTML
Per maggior chiarezza e miglior controllo, alcuni tag HTML sono stati modificati in 4d v12.2:
Note: - Adesso 4DTEXT non accetta più il char(1) come primo carattere per interpretarlo come HTML, che era il primo vecchio meccanismo per supportare le due varianti di 4DVAR. - Le vecchie varianti sono ancora supportate, ma essendo dichiarate obsolete dalla 12.2 sarà meglio cominciare ad usare la nuova nomenclatura |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Componenti |
[v12] Come utilizzare il componente RichTextArea
Occorre innanzitutto installare il componente "RichTextArea.4dbase" nella cartella Components a livello della struttura .4db o nella cartella Components all'interno dell'applicativo 4d. Nel form dove si vuole modificare un campo testo va creata una subform, impostando tipo TEXT e una variabile, ad esempio txtMioWord. Nel metodo legato al form carico la variabile con il contenuto del campo: Case of : (Form event=On Load) txtMioWord:=[Tabella]CampoTesto End case Mentre nel metodo della subform, aggiorno il campo con la variabile: Case of : (Form event=On Data Change) [Tabella]CampoTesto:=txtMioWord End case |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Errore 10509 alla connessione con un Client
Quando si tenta di connettere un client a un server v11 e successivi e appaiono questi errori: -10509 Can't open database 1024 Cannot open structure of database 1211 Cannot create connection 4 <<Localizator is not available.>> Vuol dire che la porta precedente e quella successiva alla porta di comunicazione client/server non sono accessibili, normalmente a causa di un firewall- La porta di default è la 19813: anche la 19812 e la 19814 dovrebbero essere aperte. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Usare Match Regex per estrarre i numeri da un indirizzo IP
Ecco un esempio di utilizzo di Match regex per verificare un indirizzo tcp/ip ed estrarne le diverse cifre. Si basa su: - il simbolo \d = una cifra - gli operatori {min,max} indicano quante ripetizioni cercare - gli operatori () isolano i diversi gruppi trovati // ---------------------------------------------------- // User name (OS): Umberto Migliore // Date and time: 01-03-11, 23:48:44 // ---------------------------------------------------- // Method: regex // Description // // // Parameters // ---------------------------------------------------- ARRAY LONGINT($arrayPosizioni;0) ARRAY LONGINT($arrayLunghezze;0) C_BOOLEAN(isTcpCorretto) C_TEXT($stringa;$1) $stringa:=$1` per esempio "192.168.0.1" isTcpCorretto:=Match regex("(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})";$stringa;1;$arrayPosizioni;$arrayLunghezze) If (isTcpCorretto) $numero1:=Substring($stringa;$arrayPosizioni{1};$arrayLunghezze{1}) $numero2:=Substring($stringa;$arrayPosizioni{2};$arrayLunghezze{2}) $numero3:=Substring($stringa;$arrayPosizioni{3};$arrayLunghezze{3}) $numero4:=Substring($stringa;$arrayPosizioni{4};$arrayLunghezze{4}) End if |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
Un compendio per usare Match regex [2]
Continuiamo ad analizzare i pattern possibili per il comando Match regex. - {...} definiscono un numero di ripetizioni della espressione regolare precedente. Può essere usato nella forma: {n} l'espressione regolare deve essere ripetuta n volte {min,} l'espressione regolare deve essere ripetuta almeno min volte {min, max} l'espressione regolare deve essere ripetuta almeno min volte e massimo max volte - | (la pipe) definisce più opzioni (il classico OR). Quindi:
- (...) definiscono i gruppi. È possibile infatti ottenere sia delle stringhe di corrispondenza che delle sottostringhe, quelle che corrispondono ai pattern fra parentesi. Quindi:
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
[v11 SQL] Il comando SET QUERY AND LOCK
Il nuovo comando SET QUERY AND LOCK, che prende come parametro semplicemente True o False, permette di richiedere il blocco dei record risultanti da una query. Ciò garantisce che i risultati di una certa ricerca non possano essere modificato da un altro processo che non sia quello attuale. Il comando può essere usato solo all'interno di una transazione (altrimenti restituisce errore), e i record restano bloccati finché la transazione viene terminata: a quel punto i record vengono comunque rilasciati. Basta comunque chiamare SET QUERY AND LOCK(False) per rilasciarli. Ecco un esempio di cancellazione controllata da SET QUERY AND LOCK: START TRANSACTION SET QUERY AND LOCK(True)`così mi assicuro che i record trovati siano locked per gli altri QUERY([Clients];[Clients]Category=“C”) DELETE SELECTION([Clients]) SET QUERY AND LOCK(False) VALIDATE TRANSACTION |
1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
[v12] Stampare su PDF con SET PRINT OPTION su Windows
Con la v12 è ora possibile usare SET PRINT OPTION per stampare su PDF anche sotto Windows (su Mac il PDF è nativo). Per farlo è necessario installare il driver gratis (OpenSource) PDFCreator sotto la licenza AFPL (Aladdin Free Public License). Per maggiori informazioni fare riferimento a questo link: Licenza PDFCreator La versione attualmente certificata è la 0.9.9 che si scarica da qui: PDFCreator 200.9.9. E' necessario avere i diritti di Amministratore: verrà creata una nuova stampante virtuale chiamata di default "PDFCreator" . |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
Un compendio per usare Match regex [1]
Il comando Match regex permette di fare operazioni particolari sulle stringhe. La forma base del comando è: Match regex (pattern; aString) dove aString è la stringa dove effettuiamo la ricerca, pattern è una speciale stringa che contiene "cosa" cercare. Se pattern si trova all'interno di di aString il comando ritorna True. Ecco cosa si può inserire all'interno di pattern. - il caso più ovvio: se pattern:="mytext" e aString:="mytext", il comando ritorna True - . (il punto) corrisponde a "qualsiasi carattere" tranne new line (a meno che ciò non venga espressamente specificato nelle opzioni inseribili in pattern). Quindi:
- [ ... ] definisce classi di caratteri. Come: "[a-z]" corrisponde a qualsiasi lettera minuscola Se la classe inizia con "^", la classe viene negata, cioè esiste corrispondenza se i caratteri non sono nella classe. - * (asterisco) corrisponde a zero o più operatori. Quindi:
- + (il segno più) corrisponde a uno o più operatori. Quindi:
? - corrisponde a zero o un operatore. Quindi:
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
[v12] Ricevere mail dal server POP di GMail
Ecco, per finire, un estratto di codice per ricevere mai da GMail dal server POP. $tempFolder:=Temporary folder $error:=0 $sslPOPPort:=995 $Errore_l:=IT_SetPort (13;$sslPOPPort) //13 is for 'POP with SSL' $error:=POP3_SetPrefs (-1;$tempFolder;$tempFolder) $error:=POP3_BoxInfo ($pop3ID;$msgCount;$msgSize) ARRAY LONGINT($aMsgSize;0) ARRAY LONGINT($aMsgNum;0) ARRAY TEXT($aMsgID;0) $error:=POP3_MsgLstInfo ($pop3ID;1;$msgCount;$aMsgSize;$aMsgNum;$aMsgID) For ($msgNumber;1;Size of array($aMsgNum)) `....... `scarica la mail con POP3_Download `cancellala con POP3_Delete `scarica il messaggio con MSG_GetBody `....... End for $error:=POP3_Logout ($pop3ID) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
Cambiare il set di caratteri usando i comandi SQL
Quando si fanno dei collegamenti a server SQL esterni ci potrebbero essere dei problemi di transcodifica del set di caratteri. Il comando che permette di definire il charset corretto è SQL SET OPTION(SQL Charset ;<charset>) Il valore del parametro charset è di default 106 che sta per UTF-8 Gli altri codici si trovano nella tabella di questa pagina : http://www.iana.org/assignments/character-sets A volte però non è semplice identificare quale codice usare, per via delle varie combinazioni ad esempio di client usato da mac o da windows: una soluzione è usare il parametro -2 che si adatta alla piattaforma ( e cioè iso-8859-1 su windows e MacRoman su mac). SQL SET OPTION(SQL Charset ;-2) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
[v12] Ricevere mail dal server IMAP di GMail
Ecco di seguito la parte di codice necessaria per autenticarsi al server IMAP di GMail e ricevere l'elenco dei messaggi di posta in entrata. C_INTEGER($error;$sslIMAPPort) C_LONGINT($smtp_id) $tempFolder:=Temporary folder $sslIMAPPort:=993 $error:=IT_SetPort (14;$sslIMAPPort) //14 is for 'IMAP with SSL' $error:=IMAP_SetPrefs (-1;$tempFolder) // $error:=IMAP_Login ("imap.gmail.com";"mymail@gmail.com";"mypassword";$imapID;1) ARRAY LONGINT($aMsgSize;0) ARRAY LONGINT($aMsgNum;0) ARRAY LONGINT($aMsgID;0) $error:=IMAP_SetCurrentMB ($imapID;"INBOX") $error:=IMAP_MsgLstInfo ($imapID;1;$msgCount;$aMsgSize;$aMsgNum;$aMsgID) $error:=IMAP_Logout ($imapID) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
[v12] Inviare mail utilizzando il server SMTP di GMail
Grazie alle nuove funzionalità SSL degli Internet Command di 4D v12, è adesso possibile inviare messaggi attraverso il server smtp.gmail.com. Vediamo il metodo: C_INTEGER($error;$sslSMTPPort) C_LONGINT($smtp_id) C_TEXT($smtpHost) C_TEXT($gmailUser;$gmailPass;$replyTo;$sendEmailTo) C_TEXT($msg;$subject) $sslSMTPPort:=465 // port used for SSL SMTP - gmail wants 465 $smtpHost:="smtp.gmail.com" // smtp host for gmail $gmailUser:="mymail@gmail.com" // gmail user $gmailPass:="mypass" // gmail password $replyTo:="mymail@gmail.com" // have replies sent here $sendEmailTo:="test@sendmail.it" // send email here $subject:="An example from sviluppo4d" // subject for email $msg:="It works fine" // email body $error:=IT_SetPort (12;$sslSMTPPort) //12 is for 'SMTP with SSL' $error:=SMTP_New ($smtp_id) $error:=SMTP_Host ($smtp_id;$smtpHost;0) $error:=SMTP_Auth ($smtp_id;$gmailUser;$gmailPass;0) $error:=SMTP_AddHeader ($smtp_id;"Importance";"Normal";0) $error:=SMTP_From ($smtp_id;$gmailUser;1) $error:=SMTP_ReplyTo ($smtp_id;$replyTo;0) $error:=SMTP_To ($smtp_id;$sendEmailTo;0) $error:=SMTP_Subject ($smtp_id;$subject;0) $error:=SMTP_Body ($smtp_id;$msg;0) $error:=SMTP_Attachment ($smtp_id;"c:\\aPDFdoc.pdf";7) $error:=SMTP_Send ($smtp_id;1) //1 to use ssl $error:=SMTP_Clear ($smtp_id) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Come sapere il giorno in cui cade Pasqua per un certo anno
// ---------------------------------------------------- // User name (OS): Umberto Migliore // Date and time: 09-02-11, 23:55:55 // ---------------------------------------------------- // Method: nx_giornoPasquaPerLAnno // Description // Ritorna il giorno di Pasqua per l'anno // // Parameters // $1 = anno // ---------------------------------------------------- c_longint($anno;$1) C_LONGINT($dopo21marzo) C_DATE($pasqua;$0) $anno:=$1 $phpok:=PHP Execute("";"easter_days";$dopo21marzo;$anno) $pasqua:=Add to date(!00-00-00!;$anno;3;21+$dopo21marzo) $0:=$pasqua |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
[v12] CALL SUBFORM CONTAINER
La v12 integra un comando molto utile per gestire le subform. CALL SUBFORM CONTAINER(event) invia un evento event (un longint) all'object method del "contenitore" della subform. Il comando può trovarsi nel form method della subform o in uno degli oggetti della stessa. L'evento event può essere o uno dei valori delle costanti 4D per i form events o un qualsiasi valore definito dall'utente (che viene gestito sempre nel metodo del contenitore). Tale commistione di valori rende consigliabile l'uso di valori negativi per gli eventi "user defined" in modo che non vadano in conflitto con quelli predefiniti 4D. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
[v12] RESTORE
Il comando RESTORE accetta adesso due parametri, entrambi opzionali: - l'archivio da ripristinare; - la cartella di destinazione per il ripristino. Se il ripristino viene eseguito correttamente, la variabile OK viene settata ad uno e la variabile Document conterrà il percorso della cartella di ripristino; in caso contrario OK va a 0 e Document avrà come valore una stringa vuota. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
[v12] I manuali in PDF
4D v12 installa automaticamente i manuali in versione HTLM. Per i fan ("duri a morire" recita il sito di 4D) dei PDF, ecco dove trovare la documentazione nel formato Adobe: Doc Center homepage FTP site In realtà, non si tratta di una reimpaginazione dei manuali: sono esattamente le pagine html in pdf. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Ottenere info sulla memoria
` ---------------------------------------------------- ` User name (OS): Umberto Migliore ` Date and time: 02-02-11, 10:51:05 ` ---------------------------------------------------- ` Method: nx_GetMemory ` Description ` se non passi parametri mostra un alert con tutti i valori correnti ` se passi una delle seguenti stringhe ritorna il valore specifico in KB ` ` es. nx_GetMemory ` es. $memoriadisponibile:=nx_GetMemory("Free Memory") ` ` $1 può essere: ` "cacheSize" ` "usedCacheSize" ` "Physical Memory Size" ` "Free Memory" ` "Used physical memory" ` "Used virtual memory" ` ---------------------------------------------------- ARRAY TEXT($arrNomi;0) ARRAY REAL($arrValori;0) ARRAY REAL($arrOggetti;0) GET CACHE STATISTICS(1;$arrNomi;$arrValori;$arrOggetti) If (Count parameters=0) C_TEXT($testo) $testo:="" For ($i;1;Size of array($arrValori)) $testo:=$testo+$arrNomi{$i}+" : "+String($arrValori{$i}/1024;"### ### ### KB")+Char(13) End for ALERT($testo) Else `Count parameters>0 C_TEXT($1;$parametro) $pos:=Find in array($arrNomi;$parametro) If ($pos>0) $0:=$arrValori{$pos}/1024 `i valori sono in bytes Else $0:=-1 End if End if |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Esportazione della struttura usando _USER_COLUMNS
Ecco un esempio di utilizzo della tabella interna _USER_COLUMNS per esportare la struttura del database corrente. ARRAY TEXT($nomeTabella;0) ARRAY TEXT($nomeCampo;0) ARRAY LONGINT($tipoCampo;0) ARRAY LONGINT($lunghezzaCampo;0) ARRAY BOOLEAN($accettaNULL;0) ARRAY LONGINT($idTabella;0) ARRAY LONGINT($idCampo;0) Begin SQL SELECT * FROM _USER_COLUMNS INTO :$nomeTabella, :$nomeCampo, :$tipoCampo, :$lunghezzaCampo, :$accettaNULL, :$idTabella, :$idCampo End SQL // ordina per tabella e in secondo livello per idCampo MULTI SORT ARRAY ($nomeTabella;>;$nomeCampo;$tipoCampo;$lunghezzaCampo;$accettaNULL;$idTabella;$idCampo;>) $doc:=Create document($System folder(Desktop) +"struttura.text") $ultimaTabella:="" For ($i;1;Size of array($nomeTabella)) If ($ultimaTabella#$nomeTabella{$i}) SEND PACKET($doc;"\r"+$nomeTabella{$i}+"\t"+String($idTabella{$i})+"\r") $ultimaTabella:=$nomeTabella{$i} End if $tipo:=Choose($tipoCampo{$i};"-";"Boolean";"-";"Integer";"Longint";"Integer 64bits";"Real";"Float";"Date";"Time";"Alpha/Text";"-";"Picture";"-";"-";"-";"-";"-";"BLOB") SEND PACKET($doc;$nomeTabella{$i}+"\t"+$nomeCampo{$i}+"\t"+String($tipoCampo{$i})+"\t"+$tipo+"\t"+String($lunghezzaCampo{$i})+"\t"+String($accettaNULL{$i};"True;;False")+"\t"+String($idCampo{$i})+"\r") End for CLOSE DOCUMENT($doc) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Esempio di uso di SVG
In 4d è presente l'engine di visualizzazione delle immagini SVG, creabili con i comandi XML e alla fine trasformati in picture con il comando SVG EXPORT TO PICTURE. Ecco un esempio: C_PICTURE(miaPicture) $svg:=DOM Create XML Ref("svg";"http://www.w3.org/2000/svg") ref:=DOM Create XML element(root;"text";\ //oggetto di tipo testo "font-family";"Arial";\ //con questo font "font-size";"26";\ //questa dimensione "font-weight";"bold") //questo stile DOM SET XML ATTRIBUTE($ref;"fill";"red") // posso aggiungere un attributo anche dopo DOM SET XML ATTRIBUTE($ref;"y";"1em") // imposto la posizione y DOM SET XML ELEMENT VALUE($ref;"Ecco un esempio") SVG EXPORT TO PICTURE($svg;miaPicture;Copy XML Data Source) DOM CLOSE XML($svg) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Invio e ricezione mail con protocollo SSL
Dalla versione 12.1 è possibile inviare e ricevere mail utilizzando l'SSL come protocollo di scambio dati. L'uso del protocollo non richiede nessuna configurazione particolare: basta passare il nuovo parametro a 1 nei seguenti comandi:
Invece il comando IT_SetPort ora accetta 3 nuovi valori per l'impostazione delle porte: 12 = SMTP SSL 13 = POP3 SSL 14 = IMAP SSL |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
Le sintassi del parametro sorgente dati di SQL LOGIN
Il comando SQL LOGIN accetta 3 parametri: la fonte dati, user e password. La fonte dati può essere espressa in diversi modi: - IP address Sintassi: IP:<Indirizzo>{:<PortaTCP>}{:ssl} In questo caso il comando apre una connessione diretta al 4D Server eseguito sulla macchina indicata dall'IP. Se non passi la porta TCP, verrà usata la porta standard 19812. NOTA: se vuoi aprire una connessione in SSL, bisogna aggiungere ":ssl" - nome pubblicato sulla rete del database 4D Sintassi: 4D:<Nome_pubblicato> In questo caso il comando apre una connessione diretta al 4D Server con il nome indicato. La porta TCP del server deve essere impostata allo stesso modo in entrambi i server. - il nome di una data source ODBC Sintassi: ODBC:<UserDSN> or <SystemDSN> E' possibile indicare il nome di una sorgente dati impostata con l'amministratore ODBC. Il prefisso non è obbligatorio per compatibilità con le versioni precedenti, ma è consigliato. - stringa vuota Sintassi: "" Richiede la visualizzazione di una finestra di dialogo dove è possibile utilizzare vari pannelli per scegliere la connessione - costante SQL_INTERNAL Syntax: SQL_INTERNAL In questo caso, il comando redireziona le richieste SQL al database interno. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
[v12] Il terzo parametro del comando String
Quando converti una data in testo, si usa il comando stringa che accetta come secondo parametro una delle seguenti costanti: Blank if null date ritorna "" invece di 0 Date RFC 1123 Mon, 24 Jan 2011 23:00:00 GMT Internal date abbreviated Jan 25, 2011 Internal date long January 25, 2011 Internal date short 25/01/2011 Internal date short special 25/01/11 (ma anche 25/01/1811) ISO Date 2011-01-25T00:00:00 ISO Date GMT 2011-01-24T23:00:00Z System date abbreviated 25/gen/2011 System date long martedì 25 gennaio 2011 System date short 25/01/11 E il terzo parametro? Serve per le costanti di tipo RFC o ISO per aggiungere anche l'ora; ad esempio: String(Current date;Date RFC 1123;Current time) Tue, 25 Jan 2011 07:07:12 GMT String(Current date;ISO Date;Current time) 2011-01-25T08:07:12 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Aggiungere l'icona nel Dock del Mac
Ecco un metodo per aggiungere l'icona del bundle dell'app nel Doc di Mac, ripreso dalla kb di 4d ( http://kb.4d.com/search/assetid=44532 ). In pratica usa launch external process per modificare le impostazioni dell'applicazione Dock e poi la rilancia forzando la chiusura del processo. ` --------------------------------------------------- ` Project method: AddToDock ` Example: AddToDock("myApp";"/Applications/myApp.app") ` --------------------------------------------------- ` Programmer: Jeremy Sullivan ` Created: Mon, Mar 13, 2006 8:00 AM ` --------------------------------------------------- ` Description: Aggiunge un'applicazione al Dock di Mac OS X ` --------------------------------------------------- ` Parameters ` Passed: ` $1 TEXT - Il nome dell'applicazione come dovrebbe comparire nel Dock ` $2 TEXT - Percorso in formato Posix al bundle (inclusa l'estensione .app) ` --------------------------------------------------- C_TEXT($1;$2;$applicationName_t;$applicationPath_t) C_TEXT($command_t;$inputStream_t;$outputStream_t;$errorStream_t) $applicationName_t:=$1 ` miaApp $applicationPath_t:=$2 ` percorso posix, ad esempio: /Applications/miaApp.app $command_t:="defaults write com.apple.dock persistent-apps -array-add " $command_t:=$command_t+"'tile-data" $command_t:=$command_t+"file-data" $command_t:=$command_t+"_CFURLString" $command_t:=$command_t+""+$applicationPath_t+"" $command_t:=$command_t+"_CFURLStringType0" $command_t:=$command_t+"file-label"+$applicationName_t+"" $command_t:=$command_t+"file-type41" $command_t:=$command_t+"tile-typefile-tile'" LAUNCH EXTERNAL PROCESS($command_t;$inputStream_t;$outputStream_t;$errorStream_t) LAUNCH EXTERNAL PROCESS("killall -HUP Dock";$inputStream_t;$outputStream_t;$errorStream_t) ` rilancia il Dock |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
Percorso in formato Posix
Per avere il percorso della cartella dove si trova il database in formato Unix (Posix) si può usare il comando GET 4D FOLDER con questa sintassi, disponibile dalla versione 4D 2004.5: Database Folder Unix Syntax Il risultato sarà del tipo: /Users/Documents/MioDatabase/ Questa caratteristica è utile soprattutto usando LAUNCH EXTERNAL PROCESS, che su Mac OS X accetta un percorso Unix (Posix). |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
[v12] Esempio di comando PHP per estrarre stringhe in un array
Nella v12 è integrato un interprete PHP v 5.3.2 che può essere utilizzato come estensione al linguaggio di 4d. E' possibile lanciare script php creati al momento, usare i comandi nativi di php, dei moduli preinstallati o installarne di altri. La sintassi é PHP Execute ( percorsoScript {; funzione {; risultato {; param1} {; param2 ; ... ; paramN}}} ) -> Function result Riportiamo un paio di esempi semplice di uso del comando, con percorsoScript="" perché passiamo una funziona nativa del php, explode. ARRAY TEXT($arrayTesto;0) $p1 :="," $p2 :="11,22,33,44,55" $isOk :=PHP Execute("";"explode";$arrayTesto;$p1;$p2) - $arrayTesto conterrà le stringhe "11", "22", "33", etc. Invece passando come parametro per il risultato un array numerico, sempre con la stessa stringa di input: ARRAY LONGINT($arrayNumerico ;0) $p1 :="," $p2 :="11,22,33,44,55" $isOk :=PHP Execute("";"explode";$arrayNumerico;$p1;$p2) - $arrayNumerico conterrà i numeri 11, 22, 33, etc. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
[v12] Carattere di separazione fra cartelle
Per indicare il separatore fra cartelle nella v12 è stata introdotta una nuova costante che varia in funzione della piattaforma su cui è eseguito il codice, la Folder separator. Quindi, il seguente codice avrà un risultato diverso su Mac e Windows: $Percorso_T:=Get 4D folder(HTML Root Folder) $Percorso_T:=$Percorso_T+"Immagini"+Folder separator+"Articoli"+Folder separator $0:=Percorso_T |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
[v11 SQL] Le tabelle di sistema di 4D: _USER_SCHEMAS
La tabella che si occupa di regolamentare gli accessi al database via SQL. _USER_SCHEMAS SCHEMA_ID - INT32 - Numero SCHEMA_NAME - VARCHAR - Nome READ_GROUP_ID - INT32 - Numero del gruppo in sola lettura READ_GROUP_NAME - VARCHAR - Nome del gruppo in sola lettura READ_WRITE_GROUP_ID - INT32 - Numero del gruppo in scrittura READ_WRITE_GROUP_NAME - VARCHAR - Nome del gruppo in scrittura ALL_GROUP_ID - INT32 - Numero del gruppo con tutti i diritti (anche modifica della struttura) ALL_GROUP_NAME - VARCHAR - Nome del gruppo con tutti i diritti |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
[v11 SQL] Le tabelle di sistema di 4D: _USER_CONSTRAINTS e _USER_CONS_COLUMNS
Ecco un'altra coppia di tabelle di sistema accessibili via SQL, con l'elenco delle relazioni, dei campi definiti come chiave primaria e delle regole di integrità referenziale (se cancello la testata cancello le righe, oppure non posso cancellare un record finché ci sono record in relazione. _USER_CONSTRAINTS CONSTRAINT_ID - VARCHAR - Numero identificativo della regola CONSTRAINT_NAME - VARCHAR - Nome CONSTRAINT_TYPE - VARCHAR - Tipo TABLE_NAME - VARCHAR - Nome della tabella dove si trova la regola TABLE_ID - INT64 - Numero della tabella con la regola DELETE_RULE - VARCHAR - Regola di cancellazione con regola di integrità referenziale – CASCADE or RESTRICT RELATED_TABLE_NAME - VARCHAR - Nome della tabella in relazione RELATED_TABLE_ID - INT64 - Numero della tabella in relazione Tipi di Constrain (o Regole): P=chiave primaria o primary key R= integrità referenziale - foreign key 4DR=relazione 4D _USER_CONS_COLUMNS CONSTRAINT_ID - VARCHAR - Numero identificativo della regola CONSTRAINT_NAME - VARCHAR - Nome TABLE_NAME - VARCHAR - Nome della tabella dove si trova la regola TABLE_ID - INT64 - Numero della tabella con la regola COLUMN_NAME - VARCHAR - Nome del campo con la regola COLUMN_ID - INT64 - Numero del campo con la regola COLUMN_POSITION - INT32 - Posizione del campo RELATED_COLUMN_NAME - VARCHAR - Nome del campo in relazione RELATED_COLUMN_ID - INT32 - Numero del campo in relazione Da notare che le relazioni Molti a uno di 4d non sono la stessa cosa delle relazioni creati via SQL Primary Key e Foreign Key; nella Struttura anche dal punto di vista grafico sono rappresentate in maniera diversa. Relazioni 4d: Primary Key e Foreign Key SQL: |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
[v11 SQL] Le tabelle di sistema di 4D: _USER_INDEXES e _USER_IND_COLUMNS
La seguente coppia di tabelle accessibili da SQL contengono le informazioni sugli indici: _USER_INDEXES INDEX_ID - VARCHAR - Numero identificativo dell'indice INDEX_NAME - VARCHAR - Nome (potrebbe essere vuoto) INDEX_TYPE - INT32 - Tipo TABLE_NAME - VARCHAR - Nome della tabella dove si trova l'indice TABLE_ID - INT64 - Numero della tabella dove si trova l'indice UNIQUENESS - BOOLEAN - Vero se l'indice prevede l'unicità I Tipi di indice sono: 1 BTree / Composite 3 Cluster / Keyword 7 Auto _USER_IND_COLUMNS INDEX_ID - VARCHAR - Numero identificativo dell'indice INDEX_NAME - VARCHAR - Nome (potrebbe essere vuoto) TABLE_NAME - VARCHAR - Nome della tabella dove si trova l'indice COLUMN_NAME - VARCHAR - Nome del campo dove si trova l'indice COLUMN_POSITION - INT32 - Posizione del campo TABLE_ID - INT64 - Numero della tabella COLUMN_ID - INT64 - Numero del campo Ecco per esempio il codice per cancellare tutti gli indici di un db: ARRAY TEXT($identificativi;0) Begin SQL select Index_Id from _User_Indexes into :$identificativi; End SQL For ($i;1;Size of array($identificativi)) $id:=$identificativi{$i} $tablenum:=0 $fieldnum:=0 Begin SQL select table_id, column_Id from _User_Ind_Columns where Index_ID = :$id limit 1 into :$tablenum, :$fieldnum; End SQL If (($tablenum#0) & ($fieldnum#0)) $puntCampo:=Field($tablenum;$fieldnum) DELETE INDEX($puntCampo;*) End if End for |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
[v11 SQL] Le tabelle di sistema di 4D: _USER_COLUMNS
Questa tabella accessibile da SQL dà un elenco dei campi divisi per le tabelle del database: _USER_COLUMNS TABLE_NAME - VARCHAR - Nome della tabella COLUMN_NAME - VARCHAR - Nome del campo DATA_TYPE - INT32- Tipo del campo DATA_LENGTH - INT32- Lunghezza del campo NULLABLE- BOOLEAN - Vero se il campo accetta valori NULL TABLE_ID - INT64 - Numero della Tabella COLUMN_ID - INT64 - Numero del campo Il campo Tipo contiene: 1 - Boolean 3 - Integer 4 - Long Integer 5 - Integer 64 Bits 6 - Real 7 - Float 8 - Date 9 - Time 10 - Alpha (DATA_LENGTH = ((dimensione del campo)*(2))+4 10 - Text (Lo distingui perché ha DATA_LENGTH = 0 ) 12 - Picture 18 - BLOB |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
[v12] Rimuovere i tag nel rich text format
Con la v12 è possibile avere testo formattato, utilizzando nel campo testo i tag HTML. Per rimuovere i tag è possibile usare il comando OBJECT Get plain text. Interessante ad esempio per fare una ricerca all'interno di campi con testi con all'interno i tag html. Cercando ad esempio "Apple iPhone" potresti non trovare il campo con scritto: "<SPAN> STYLE="font-size:13.5pt">Apple</SPAN> iPhone" La soluzione è usare : QUERY BY FORMULA([articoli];OBJECT Get plain text([articoli]descrizione)="@Apple iPhone@") |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
iphone, ipad o android e l'url 4DSYNC
Una delle funzioni aggiunte nella versione v12 è la gestione della replica dei dati, utile per sincronizzare più database in modo automatico a basso livello. (cfr il comando Replicate su 4d ) La cosa interessante è che è possibile utilizzare questo comando anche sfruttando il protocollo HTTP: dovendo realizzare degli applicativi su piattaforma mobile la cosa semplifica di molto la comunicazione. La modalità è di chiamare il nuovo URL specifico di 4d : /4DSYNC E' possibile chiamarlo sia in lettura che in scrittura utilizzando stringhe costruite con la modalità JavaScript Objet Notation (JSON), abbastanza semplici sia da ottenere che interpretare. La sintassi del comando è : GET /4DSYNC/$catalog Ritorna la lista delle tabelle per cui è attiva la replica e il numero di record che contengono. GET /4DSYNC/$catalog/NomeTabella Ritorna la descrizione della tabella. GET /4DSYNC/NomeTabella/NomeCampo1{,NomeCampo2},... Ritorna i dati dei campi indicati nella tabella. POST /4DSYNC/NomeTabella/NomeCampo1{,NomeCampo2},... Invia le modifiche fatte in locale al 4d. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novita' |
Tempo consigliato per il Flush Cache
Mentre fino alla versione 4d 11 il tempo consigliato per la flush cache era di default 15 minuti. Dalla versione v12 il tempo consigliato è 20 secondi, grazie alle nuove ottimizzazioni del funzionamento della cache. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
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 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
[v11 SQL] Le tabelle di sistema di 4D: _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 ri-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/hosts e inserire la seguente riga: 192.168.1.1 www.sviluppo4d.it dove l'ip è quello interno del web server. Individuare poi il file: /etc/host.conf che si occupa del lookup e che deve contenere la riga: order hosts,bind Infine, nel file: /etc/nsswitch.conf inserire 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.3 che è 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:=$risultato |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
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 record 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. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
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 |
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 ridimensiona al vertice in alto a sinistra If (False) ` $1 = Puntatore alla variabile contenente il Logo ` $2 = Altezza del campo che si vuole ottenere ` $3 = Larghezza del campo che si vuole ottenere ` $4 = Object Name della variabile ` Inserire il richiamo a questo metodo nell'oggetto del form AdeguaLogo (->var_Logo;114;0;"Logo") ` con evento "On printing detail" - "On display detail" ` Sembra che funzioni solo su Variabili End if C_INTEGER($AltezzaPrevistaInPixel;$LarghezzaPrevistaInPixel;$SizeOrizzontale;$SizeVerticale) $AltezzaPrevistaInPixel:=$2 $LarghezzaPrevistaInPixel:=$3 PICTURE PROPERTIES($1->;$Larghezza;$Altezza) Case of : ($AltezzaPrevistaInPixel>0) $Coefficiente:=$Altezza/$AltezzaPrevistaInPixel : ($LarghezzaPrevistaInPixel>0) $Coefficiente:=$Larghezza/$LarghezzaPrevistaInPixel Else $Coefficiente:=1 End case $SizeOrizzontale:=($Larghezza/$Coefficiente $SizeVerticale:=$Altezza/$Coefficiente GET OBJECT RECT(*;$4;$left;$top;$right;$bottom) MOVE OBJECT(*;$4;$left;$top;$SizeOrizzontale+$left;$SizeVerticale+$top;*) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Rendere maiuscole tutte le prime lettere
Il metodo che segue permette di rendere maiuscole la prima lettera di un campo alfa e tutte quelle di tutte le altre parole della stringa, considerando come separatore di parola lo spazio. `$1 è il testo a cui applicare il metodo `$0 il risultato C_STRING(30;$risultato_s;$0;$vch_s) C_LONGINT($pos_l) $risultato_s:=$1 $risultato_s:=Uppercase(Substring($risultato_s;1;1))+Lowercase(Substring($risultato_s;2;80)) $pos_l:=Position(" ";$risultato_s) While ($pos_l>0) $vch_s:=" "+Substring($risultato_s;$pos_l+1;1) $risultato_s:=Replace string($risultato_s;$vch_s;Uppercase($vch_s);1) $pos_l:=Position(" ";$risultato_s;$pos_l+1) End while $0:=$risultato |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novita' |
4D 2004 - Spostamento automatico degli oggetti
Disegnando un form, è stato sempre possibile spostare gli oggetti di 10 punti nelle varie direzioni usando insieme alle frecce il maiuscolo. Dalla versione 2004, fra le preferenze (in "Preferences - Design Mode - Form Editor"), è stata inserita la possibilità di modificare il numero di punti per questo tipo di spostamento ("Step using keyboard"). |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novita' |
Customizer e 2004: dimensione della finestra di avvio
Con la versione 2004 le funzionalità del Customizer Plus sono state integrate in 4th Dimension. Una opzione che è "scomparsa" è quella riguardante la dimensione della finestra di avvio (nelle "Preferences" si può scegliere solo se mostrarla o no). A ciò si può facilmente ovviare da linguaggio di programmazione: ad esempio, se usavamo una dimensione costante per la finestra di avvio, basta eseguire SET WINDOW RECT(left;top;right;bottom) nello Startup method per ottenere lo stesso risultato. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
La compressione dei Blob
I blob (Binary Large OBjects) sono tipi di dati, quindi campi o variabili, che possono contenere fino a 2GB di informazioni. Per gestire blob di grosse dimensioni è possibile usare il comando Compress Blob con eventualmente 2 opzioni, per scegliere fra una maggiore compressione o una maggiore velocità. Ecco i due esempi: COMPRESS BLOB(blob_blb;Compact compression mode) COMPRESS BLOB(blob_blb;Fast compression mode) Il comando per riportare il blob alle dimensioni originali è il seguente: EXPAND BLOB(blob_blb) Attenzione: se il blob contiene meno di 255 caratteri la compressione non ha luogo. Questo vuol dire che il successivo EXPAND BLOB potrebbe dare un errore. La modalità corretta di usarlo per evitare problemi è la seguente: BLOB PROPERTIES(blob_blb;$compressione_l;$dim_espanso_l;$dim_corrente_l) If ($compressione_l#Is not compressed) EXPAND BLOB(blob_blb) End if |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Entry filter per i dati di tipo orario AM/PM
Ecco un entry filter interessante, da usare per i valori di tipo time inglesi, cioè con la sigla AM/PM in fondo: !0&"0;1"#&9#:&"0-5"#&9# ~"A;P"#M |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Importare numeri negativi da Excel o FileMaker
Il comando Num di 4D non riconosce come negativi i numeri passati racchiusi tra parentesi, mentre alcuni programmi come FileMaker o Excel possono utilizzare questo formato per l'esportazione di tali numeri, senza dunque la presenza del segno "-". Ecco dunque un frammento di codice che consente di ottenere il numero corretto a partire da un testo passato come parametro: C_TEXT($1;$tNumText_t) C_REAL($0) C_LONGINT($iLen:l) $tNumText_t:=$1 $iLen_l:=Length($tNumText_t) If ($tNumText_t[[1]]=Char(40)) & ($tNumText_t[[$iLen_l]]=Char(41)) ` il numero è negativo $tNumText_t:=Replace string($tNumText_t;"(";"-") $tNumText_t:=Replace string($tNumText_t;")";"") End if $0:=Num($tNumText_t) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Falso bug della tastiera sulla 2004
Molti sviluppatori hanno segnalato un baco della versione 2004 riguardante la tastiera su Windows: in certi casi i caratteri mostrati usando Shift+numero risultavano non coincidenti al risultato desiderato. Il problema in realtà non esiste, in quanto si presenta solo perché la combinazione dei tasti che permette di passare in modalità User (Alt+Shift+Clic, per altre info vedere questa faq) è la stessa utilizzata dal sistema operativo per modificare in automatico, nei Servizi di testo e lingue di input, la lingua di keyboard input. Basta dunque rimuovere le altre lingue o modificare/cancellare la combinazione di tasti di Windows per risolvere il "baco". |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Operatori binari: esempi
Vediamo qualche esempio di operatori binari, a partire dalla faq che ne descrive l'uso: Quando si esegue un AND fra bit il risultato segue queste regole: 1 & 1 --> 1 0 & 1 --> 0 1 & 0 --> 0 0 & 0 --> 0 cioè, il risultato è 1 solo se entrabi i bit valgono 1. Esempio: 0x0000FFFF & 0xFF00FF00 è uguale a 0x0000FF00 L'OR (inclusive) usa la seguente tabella: 1 | 1 --> 1 0 | 1 --> 1 1 | 0 --> 1 0 | 0 --> 0 cioè, il risultato è 1 se uno dei bit vale 1. Esempio: 0x0000FFFF | 0xFF00FF00 è uguale a 0xFF00FFFF. L'OR esclusivo invece si comporta così: 1 ^| 1 --> 0 0 ^| 1 --> 1 1 ^| 0 --> 1 0 ^| 0 --> 0 cioè, il risultato è 1 solo se UNO SOLO dei bit confrontati vale 1. Esempio: 0x0000FFFF ^| 0xFF00FF00 restituisce 0xFF0000FF Lo Shift a sinistra/destra sposta i bit verso sinistra/destra di un numero N di posti. I bit mancanti vengono rimpiazzati da zeri. Ciò significa che se il numero di bit da shiftare passato è maggiore di 31 il risultato dello shift sarà sempre 0x00000000 poiché tutti i bit vengono persi. Lo Shift a sinistra/destra corrisponde a moltiplicare/dividere il numero passato per 2^N (con N numero di posti dello shift) Esempi: Bit Shift a sx: 0x0000FFFF << 8 restituisce 0x00FFFF00 Bit Shift a dx: 0x0000FFFF >> 8 restituisce 0x000000FF Altri esempi sui bit operators: Bit Set: 0x00000000 ?+ 16 restituisce 0x00010000 Bit Clear: 0x00010000 ?- 16 restituisce 0x00000000 Bit Test: 0x00010000 ?? 16 restituisce True |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
Connessione ODBC con i comandi della 2004
A differenza delle versioni precedenti, in cui era necessario l'uso del plugin apposito per connettersi a database ODBC, con la versione 2004 del tool i comandi basilari per la connessione a data source esterni sono direttamente disponibili nel linguaggio di programmazione. I comandi ODBC LOGIN e ODBC LOGOUT permettono di accedere (e di disconnettersi) direttamente alle fonti di dati esterne, passando al primo comando solo nome dell'origine dati, user e password. Se, come con le versioni precedenti, fosse necessario ottenere un ID di connessione (ad esempio per connettersi contemporaneamente a più di una origine dati), bisogna allora utilizzare il plugin 4D ODBC Pro, che opzione a pagamento. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
Operatori Binari
Nei casi in cui è necessario lavorare a livello binario, cioè dei Bit, 4d fornisce una serie di operatori che lavorano con numeri interi o longint. AND = & = Numero & Numero OR = | = Numero | Numero XOR = ^| = Numero ^| Numero Per spostare il numero binario verso sinistra o verso destra di un numero di posti: Left Bit Shift = << = Numero << diQuantiBit Right Bit Shift = >> = Numero >> diQuantiBit Per controllare e modificare un singolo bit all'interno di un numero Attiva Bit = ?+ = Numero ?? qualeBit Azzera Bit = ?- = Numero ?? qualeBit Controlla Bit = ?? = Numero ?? qualeBit |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novita' |
Generare il metodo che crea un Report
Nell'ultima pagina del wizard del Quick Report della 2004 l'ultimo pulsante di opzione, Build 4D Code permette di generare il codice corrispondente al report appena definito e di incollarlo negli Appunti. Questa funzione è molto utile perché permette di modificare via linguaggio un report Build 4D Code è disponibile solo in ambiente User |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Stampare un campo testo in variable frame
Per stampare un campo testo in modalità "Variable frame" bisogna utilizzare alcuni accorgimenti. Intanto la variabile o il campo debbono essere alti almeno due righe (basta ridimensionare verso il basso la variabile) e usare questo piccolo frammento di codice: Case of : (Form event=On Printing Detail) If ([Tabella]CampoTesto="") [Tabella]CampoTesto:=" " `senza salvare! End if End case oppure Case of : (Form event=On Printing Detail) vTesto_T:=[Tabella]CampoTesto End case |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
Impostare l'handshake della porta seriale
Usando i comandi per la gestione della seriale su 4D è possibile scegliere fra le varie opzioni il protocollo Hardware: questo imposta sia il DTR che il CTS. Potrebbe esserci qualche raro caso in cui la seriale si aspetta solo il DTR attivo e non il CTS: in questo caso si può usare plug-in Serial Toolkit Pro, distribuito da Deep Sky Technologies. La funzione STK_HShake permette di impostare il metodo di handshake con queste opzioni: err := STK_HShake(refNum; handShakeType; xOnChar; xOffChar) dove il valore di handShakeType può essere: 0 = no handshake 1 = Xon/Xoff 2 = CTS 3 = DTR 4 = CTS/DTR |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Calcolo del checksum per il protocollo MODBUS
Ecco un metodo utilizzabile per calcolare il CRC per il protocollo industriale MODBUS. Il CRC è un valore di 16 bit calcolato in base a tutti i byte che compongono il pacchetto (il parametro che riceve il metodo), a partire dal byte alto ed esclusi i byte del CRC. Se il CRC non è corretto la macchina slave ignora il pacchetto. La procedura usa due array, arrHi e arrLow, dove sono memorizzati i valori necessari al calcolo del CRC. Viene inoltre utilizzato il metodo u_EsadecimaleToDec il cui testo si trova nella faq Conversione da esadecimale a decimale. $reg_Hi:=0x00FF $reg_Low:=0x00FF $test:=$1 C_STRING(80;$1;$0) For ($i;1;Length($test);2) C_LONGINT($index) $deci:=u_EsadecimaleToDec ($test[[$i]]+$test[[$i+1]]) $index:=$reg_Hi ^| $deci $reg_Hi:=$reg_Low ^| arrHi{$index+1} $reg_Low:=arrLow{$index+1} End for $risultatoA:=$reg_Hi << 8 $risultato:=$risultatoA ^| $reg_Low $0:=Substring(String($risultato;"&x");3) Il metodo di calcolo è utilizzabile anche per il calcolo del CRC del protocollo J-Bus. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Come controllare il il numero di licenze dei Plug-in di 4D Server
(da un'idea di Massimo Giannessi) Il problema si pone quando si installa un numero inferiore di licenze di Plug-in rispetto al numero di licenze 4D Client con l'istruzione ' Is license available(4d view license) ' ritorna vero se ho almeno una licenza, ma non mi dice quante licenze sono già impegnate dai vari 4D client ` Procedura in StartUp vErrView:=False ON ERR CALL("ErrView") QLV_StartUp ON ERR CALL("") ` Procedura ErrView vErrView:=True ` Procedura QLV_StartUp `procedura che iniziallizza i component Italsoftware con plug-in 4D View La variabile flag vErrView posso utilizzarla prima di fare le chiamate alle procedure che utilizzano i Plug-in (in questo caso di 4D View) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
Collegarsi ad un SQL Server via ADO
Nella 2004, 4D presenta un nuovo plugin "4D for ADO" con cui è possibile dialogare e scambiare dati con la maggior parte dei database relazionali sui sistemi Windows. Ecco un esempio che mostra il collegamento ad un database utilizzando il nuovo plugin ADO attraverso ODBC. C_TEXT($ConnStr) C_LONGINT($ConnID_l) ` --- ADO usando ODBC--- $ConnStr:="Driver={nome_driver};" $ConnStr:=$ConnStr+"Server=server_DNS;" $ConnStr:=$ConnStr+"Database=nome_database;" $ConnStr:=$ConnStr+"Uid=utente;" $ConnStr:=$ConnStr+"Pwd=password" ` Mi collego al database identificato nella stringa preparata come sopra $ConnID_l:=DBGateway_Connect ("server_DNS";$ConnStr) `Comando di chiusura della connessione DBGateway_Close ($ConnID_l) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
Creare una selezione da valori multipli
Nel caso in cui si abbia la necessità di fare un ricerca per valori multipli su un campo indicizzato, piuttosto che accodare diverse query, è meglio usare QUERY WITH ARRAY che crea la selezione di record in modo molto più veloce. Ecco un esempio, per selezionare tutti i clienti di Milano, Roma, Napoli: ARRAY STRING (2;Province_at;2) Province_at{1}:="MI" Province_at{2}:="RM" Province_at{3}:="NA" QUERY WITH ARRAY ([Clienti]Provincia; Province_at) Nota: non è necessario passare la tabella perchè il comando cambia la selezione relativa al campo indicizzato passato come primo parametro. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Le impostazioni per gli oggetti nelle maschere
Il form editor della 2004 presenta molte funzioni interessanti; eccone una molto utile quando si lavora su un database disegnando o modificando molte maschere. Quando si usa un oggetto esso presenta alcune impostazioni predefinite, come ad esempio lo stile del testo negli oggetti Label. Per cambiare queste impostazioni è possibile usare il comando "Use as Template" nel menu contestuale (control clic su Mac o tasto destro su Windows) che appare sull'oggetto che è stato definito a proprio piacere. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novizi |
I tre ambienti di 4D
4D può lavorare in te modalità differenti: - Design: è quella usata dal programmatore per sviluppare il database, dove si può accedere alla struttura delle tabelle, all'editor dei metodi, delle maschere, etc; - User: è la modalità di inserimento diretto dei dati nelle tabelle; cioè in pratica è possibile navigare con gli strumenti standard di 4d all'interno di tutto il database; utilizzato in genere solo dal programmatore e dall'amministratore di sistema. - Custom: è la modalità visibile all'utente finale (per capirci, quella che si vede utilizzando semplicemente 4D Runtime); l'utilizzo del programma è deciso dal programmatore con i menu personalizzati. Per scegliere la modalità con cui si apre una applicazione, dal Design basta andare nel menu Edit-Preferences (o Mela-Preferences) e selezionare l'ambiente desiderato. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
Cercare un elemento in un indice: Find Index Key
Con il comando Find Index Key(campo_indicizzato;termine) è possibile cercare direttamente una voce all'interno di un indice, senza toccare la selezione corrente. Ad esempio, è estremamente utile dall'interno di una maschera d'inserimento per controllare che una voce non sia già presente nella base dati, senza perdere il record corrente. La funzione ritorna -1 se la voce non è nell'indice, altrimenti se la trova ritorna il numero di record corrispondente. Da notare che il termine da cercare deve essere necessariamente una variabile perché il comando la riempie con il valore trovato: in questo modo si possono fare le ricerche sui campi Alpha usando la "@". |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
Controllo Ortografico Integrato
Il comando SPELL CHECKING avvia il controllo della correttezza dei termini usati nel campo o variabile di tipo testo in cui si trova il cursore nella maschera corrente. Se il termine non viene trovato appare la relativa finestra di dialogo dove è possibile correggere, ignorare o aggiungere il termine nel proprio dizionario personale. 4th Dimension usa il dizionario corrente, corrispondente alla lingua dell'applicativo usato; quindi normalmente in Italia avremo preimpostato l'Inglese. Con il comando SET DICTIONARY è possibile scegliere fra Inglese, Francese, Spagnolo e Tedesco con una serie di loro varianti. Al momento (settembre 2005) l'Italiano non è disponibile. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
Linee a colori alternati nelle liste di record
Il comando Displayed line number è uilizzabile solo all'interno dell'evento On Display Detail; ecco un esempio di utilizzo per colorare un campo in modo diverso in funzione della riga selezionata. If (Form event=On Display Detail) If (Displayed line number % 2 = 0) `Nero su bianco per le righe pari SET RGB COLORS([Tabella]Campo; -1; 0x00FFFFFF) Else `Nero su celeste per righe pari SET RGB COLORS([Tabella]Campo; -1; 0x00E0E0FF) End if End if |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Creare la finestra di Informazioni (About)
Con il comando SET ABOUT puoi specificare il nome del comando da menu e il corrispondente metodo da eseguire per la finestra di Informazioni standard sull'applicazione corrente. Nel metodo si può usare il comando DIALOG; 4D aggiungerà in cima alla finestra altre informazioni come l'icona di 4D, il numero di versione di 4D e del compilatore. Per non mostrare queste informazioni aggiuntive, basta mostrare la finestra di dialogo in un processo a parte. Se hai già il metodo che mostra la Dialog, basta aggiungere queste righe di codice: Case of : (Count parameters=0) $Processo_l:=New process(Current method name;Maxint;Current method name;"ProcessoAParte") Else `Codice Originale $w:=Open Form Window([Tabella];"MiaAbout") DIALOG([Tabella];"MiaAbout") CLOSE WINDOW End case |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Modificare le preferenze Database da Runtime
Con la versione 2004 è possibile modificare le preferenze di Database anche dall'ambiente Runtime: è possibile creare un elemento di menu e scegliere come azione automatica associata (Associated Standard action) "Preferences". Da notare che i comandi da menu associati alle azioni Quit e Preferences sono automaticamente spostati nelle posizioni standard per il sistema operativo in cui ci si trova. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Convertire un metodo per eseguirlo su Server
Alcune procedure eseguite su Client sarebbero eseguite in maniera molto più veloce su Server, ad esempio se si modificano tanti record e non ci sono legami all'interfaccia. Ora supponiamo di avere una procedura fatta così: `MioMetodo C_REAL($0;Tot_l) Tot_l:=0 ALL RECORDS([Tabella]) APPLY TO SELECTION([Tabella];Tot_l:=Tot_l+([Tabella]Prezzo*[Tabella]Quantità)) $0:=Tot_l Per evitare di modificare tutte le procedure che chiamano MioMetodo, interveniamo sullo stesso premettendo una chiamata a se stessa come stored procedure aggiungendo un parametro; poi aspettiamo il risultato dal server e lo ritorniamo come valore, mantenendo così invariato il funzionamento di MioMetodo dal punto di vista delle altre procedure. `MioMetodo C_REAL($0;Tot_l) C_TEXT($1;$Parametro_t) C_LONGINT($Processo_l) C_BOOLEAN(Pronto_b;HoLetto_b) Case of : (Count parameters=0) $Processo_l:=Execute on server(Current method name;Maxint;Current method name;"SulServer") `Questo ciclo aspetta che la Stored Procedure sia Pronta a darmi il valore Pronto_b:=False Repeat DELAY PROCESS(Current process;60) IDLE GET PROCESS VARIABLE($Processo_l;Pronto_b;Pronto_b) Until (Pronto_b) GET PROCESS VARIABLE($I_Process;Tot_l;Tot_l) `E poi avverto la Stored Procedure che ho letto, così si chiude HoLetto_b:=True SET PROCESS VARIABLE($I_Process;HoLetto_b;HoLetto_b) `Ritorno il valore $0:=Tot_l Else `Questa parte viene eseguita sul server come Stored Procedure Pronto_b:=False `CODICE ORIGINALE Tot_l:=0 ALL RECORDS([Tabella]) APPLY TO SELECTION([Tabella];Tot_l:=Tot_l+([Tabella]Prezzo*[Tabella]Quantità)) `avverto che il risultato è pronto Pronto_b:=True `aspetto che il client abbia letto e poi chiudo HoLetto_b:=False Repeat DELAY PROCESS(Current process;3) IDLE Until (HoLetto_b) End case |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novizi |
Le estensioni dei file 4D
Ecco un elenco delle estensioni dei vari tipi di file usati da 4th Dimension: - .4db : la struttra del database; - .rsr : risorse della struttura, quando si sposta una struttura bisogana spostare sia il file .4db che il file .rsr; - .4dd : file dei dati, è indipendente dalla struttura; - .4dr : file di risorse del file di dati, da spostare sempre insieme al .4dd; - .4dc : database compilato; - .4df : ricerca salvata (nel query editor); - .4dl : file log; - .4ds : data segment, i file dati "aggiuntivi" al file dati principale; - .4dx : external package; - .4fi : filtro ASCII; - .4fr : formula; - .4lb : etichette salvate nel label editor; - .4qr : quick report salvati; - .4st : set salvati; - .4ug : utenti e gruppi; - .4vr : varialbili; - .tfr: formule (salvate ad esempio nel quick report o nell'order by); Su Mac le risorse sono inserite nei file struttura e dati, la struttura non ha quindi estensione, mentre il file dati ha estensione ".data". |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Disabilitare il Range checking solo in una parte di codice
Compilando con l'opzione Range Checking 4d verifica ogni singolo riferimento o impostazione di valore delle variabili e dei campi. E' ad esempio utile quando si tenta di usare/assegnare un elemento di un array oltre la dimensione dichiarata (il quinto elemento di un array di size 4, ad esempio): in questo caso senza range checking il programma compilato potrebbe dare errori di qualsiasi tipo, anche chiudersi inaspettatamente (perchè accede ad una zona di memoria protetta). Con il range checking attivo 4d intercetta l'errore e avverte l'utente. Questo pero' potrebbe rallentare in modo significativo un programma compilato in punti dove ci sono molti calcoli e cicli annidati; in questi casi è possibile disabilitare per quella parte di codice il Range Checking e riabilitarlo subito dopo con queste istruzioni: `%R- ... qui va il codice che può girare senza range checking, perchè ben controllato e sicuro `%R+ Quindi: il primo %R- disabilita il Range checking, il secondo %R+ lo riabilita. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Disabilitare alcuni Warning in compilazione
Quando si effettua una compilazione del codice, alcune condizioni particolari potrebbero essere mostrate al programmatore come Warning. Per disabilitare all'interno di un certo codice un determinato tipo di Warning è sufficiente aggiungere una riga di commento con questa sintassi `%W-(numero del warning) Ad esempio, per disabilitare questi Warning 1: Pointer in an array declaration (518.5) si può scrivere, magari in uno dei metodi chiamati COMPILER_xxx (che vengono compilati per primi): `%W-518.5 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Lanciare un'applicazione esterna
Dalla versione 2004 il comando LAUNCH EXTERNAL PROCESS permette di eseguire applicativi esterni a 4D. Nelle versioni precedenti si può usare il comando AP Sublaunch del plugin gratuito 4D Pack. Ad esempio, è possibile cambiare i privilegi di accesso di un file usando il comando da Terminale su Mac: LAUNCH EXTERNAL PROCESS ("chmod +x /cartella/documento") Su Windows è possibile nascondere la finestra della Console DOS usando anche il comando SET ENVIRONMENT VARIABLE. Ecco un esempio: SET ENVIRONMENT VARIABLE("_4D_OPTION_CURRENT_DIRECTORY";"C:\\4D") SET ENVIRONMENT VARIABLE("_4D_OPTION_HIDE_CONSOLE";"true") LAUNCH EXTERNAL PROCESS("mycommand") |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Evidenziare un elemento al passaggio del Mouse
Ecco un esempio di uso di un paio di nuovi eventi introdotti nella versione 4D 2004. Basta incollare questo codice nel metodo di un oggetto (di tipo testuale): quando ci si passa sopra con il mouse il testo contenuto viene evidenziato, un po' come quando con il browser si passa su un link. Case of : (Form event=On Mouse Enter ) FONT STYLE(Self->;Underline ) : (Form event=On Mouse Leave ) FONT STYLE(Self->;Plain ) End case |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
I Parametri e la funzione Massimo
In 4D è possibile chiamare un metodo passando un certo numero di parametri non necessariamente prefissato. I parametri all'interno del metodo vengono usati direttamente con la sintassi $1, $2, $3, etc o indirettamente con la sintassi ${num}: il metodo può sapere quanti parametri sono stati passati usando la funzion e Count parameter. Il tipo dei parametri può essere comunque dichiarato usando la sintassi C_XXX(${n}) dove n indica che da quel parametro in poi sono tutti di tipo C_XXX. Ecco un esempio di funzione che sfrutta queste caratteristiche: ` Metodo Massimo ` Massimo ( Valore { ; Valore2... ; ValoreN } ) -> ritorna il numero massimo C_REAL ($0;${1}) ` Tutti i parametri sono dichiarati numeri Reali $0:=${1} For ($param_l;2;Count parameters) If (${$param_l}>$0) $0:=${$param_l} End if End for Quindi sono valide tutte le seguenti chiamate: maggiore:= Massimo (numero1;numero2) maggiore:= Massimo (n1;n2;n3;n4;n5;n6;n7;n8;n9;n10;n11;n12;n13;n14;n15;n16) maggiore:= Massimo ((current date-$datanascita_1)/365,25;(current date-$datanascita_2)/365,25) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Metodo di controllo dell'Input da tastiera
Usando l'evento On Before Keystroke si riesce ad intercettare cosa viene scritto nella corrente area di testo (dove si trova il cursore), prima che sia accettato come nuovo valore del campo o della variabile corrispondente. Il metodo Handle keystroke utilizza una seconda variabile utilizzabile per gestire quello che si sta inserendo. I parametri sono il puntatore all'area e il puntatore ad una variabile secondaria. Il metodo ritorna il nuovo valore dell'area nella variabile e ritorna Vero se il testo è cambiato. ` Handle keystroke ` Handle keystroke ( Pointer ; Pointer ) -> Boolean ` Handle keystroke ( -> areaIns ; -> valoreCorrente ) -> E' un valore nuovo C_POINTER ($1;$2) C_TEXT ($nuovoValore_t) GET HIGHLIGHT ($1->;$inizio_l;$fine_l) ` Prendi l'intervallo selezionato nell'area $nuovoValore_t:=$2->` Inizia a lavorare con il valore corrente Case of ` Controlla il tasto premuto ` E' stato premuto il tasto Backspace (Delete) : (Ascii (Keystroke)=Backspace ) ` Cancella i caratteri selezionati o il carattere a sinistra $nuovoValore_t:=Substring ($nuovoValore_t;1;$inizio_l-1-Num($inizio_l=$fine_l))+Substring($nuovoValore_t;$fine_l) ` E' stato premuto un carattere accettato : (Position (Keystroke;"abcdefghjiklmnopqrstuvwxyz -0123456789")>0) If ($inizio_l#$fine_l) ` Se c'è una seleziona il carattere la sostituisce tutta $nuovoValore_t:=Substring($nuovoValore_t;1;$inizio_l-1)+Keystroke+Substring($nuovoValore_t;$fine_l) Else ` Non c'è selezione, solo il cursore... Case of ` .. all'inizio : ($inizio_l<=1) $nuovoValore_t:=Keystroke+$nuovoValore_t ` ... alla fine : ($inizio_l>=Length($nuovoValore_t)) $nuovoValore_t:=$nuovoValore_t+Keystroke Else ` ... in mezzo al testo $nuovoValore_t:=Substring($nuovoValore_t;1;$inizio_l-1)+Keystroke+Substring($nuovoValore_t;$inizio_l) End case End if ` E' stata premuta una Freccia, accetta comunque il tasto : (Ascii(Keystroke)=Left Arrow Key ) : (Ascii(Keystroke)=Right Arrow Key ) : (Ascii(Keystroke)=Up Arrow Key ) : (Ascii(Keystroke)=Down Arrow Key ) ` Else ` E' un carattere non accettato, lo filtra del tutto FILTER KEYSTROKE ("") End case ` Il valore è cambiato? $0:=($nuovoValore_t#$2->) ` Ritorna comunque il valore $2->:=$nuovoValore_t Clic qui per un esempio di utilizzo del metodo, per mascherare l'inserimento delle password |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
4D Open e i Network Component
Dalla versione di 4D 2003, i componenti non-TCP/IP non sono più usati, per cui il comando OP Load Network Component è obsoleto. L'ID del TCP/IP è 29 su Mac OS e 2 su Windows. Quindi quando viene richiesto un componente in un comando di 4D, bisogna usare direttamente la costante, come nell'esempio: PLATFORM PROPERTIES($sistema_l) If($sistema_l<3) netCompID:=29 `sono su Mac Else netCompID:=2 `sono su Windows End if $error:=OP Select 4D Server (netCompID;$NomeServer;$IDServer;True) |
1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
Delay Process e il processo User/Custom Menus
Il comando Delay process ha una particolarità: non funziona nel processo "User/Custom Menus", cioé non lo rallenta. Questo è normamente causa di confusione quando una procedura che contiene un Delay Process viene testata in ambiente User: la soluzione è di ricordarsi di selezionare il pulsante "New Process" nella finestra di Execute Method (in modo da lanciare la procedura in un processo separato). Oppure è possibile usare un metodo alternativo: `Metodo Pausa `Aspetta 2 secondi o il numero di secondi che gli passi come parametro `funziona anche in User/Runtime C_LONGINT($sec_l) C_TIME($inizio_h) If (Count parameters>0) $sec_l:=$1 Else $sec_l:=2 End if $inizio_h:=Current time While (Abs(Current time-$inizio_h)<$sec_l) DELAY PROCESS(Current process;30) End while |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
I parametri di OC Set login option e OC Get login option
In 4d Odbc 2003 i comandi OC Set login option e OC Get login option permettono di impostare o leggere i parametri di una connessione ad un database ODBC-compatibile. I parametri a disposizione, con il relativo valore della costante, sono: SQL_ACCESS_MODE 101 SQL_AUTOCOMMIT 102 SQL_LOGIN_TIMEOUT 103 SQL_OPT_TRACE 104 SQL_OPT_TRACEFILE 105 SQL_TRANSLATE_DLL 106 SQL_TRANSLATE_OPTION 107 SQL_TXN_ISOLATION 108 SQL_CURRENT_QUALIFIER 109 SQL_ODBC_CURSORS 110 SQL_QUIET_MODE 111 SQL_PACKET_SIZE 112 Vediamo alcuni dei valori che impostabili/leggibili: SQL_ACCESS_MODE 0 = Read/Write 1 = Read Only Imposta il tipo di accesso (lettura scrittura/sola lettura) SQL_LOGIN_TIMEOUT Integer tempo per la disconnessione: se posto a 0 il timeout viene disabilitato SQL_OPT_TRACE 0 = Trace off 1 = Trace on abilita/disabilita il trace delle operazioni su un file di log SQL_OPT_TRACEFILE File name Se SQL_OPT_TRACE è 1, il log verrà scritto su questo file (il file di default è SQL.LOG) SQL_QUERY_TIMEOUT Integer 0=No timeout E' il tempo di timeout di esecuzione di una query prima che venga cancellata |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Lanciare 4d 6.8 o 4d 2003 come root
Su Mac OS X per accedere alla porta 80 (come web server) o alla 443 (come web con SSL) occorre lanciare l'applicazione 4D da utente root (per le versioni 6.8 e 2003, la 2004 lo fa da sola) Ecco il comando da eseguire: sudo -b /System/Library/Frameworks/Carbon.framework/Versions/Current/Support/LaunchCFMApp Ma in realtà il file da lanciare non è il package esterno, ma il file dell'applicativo vero e proprio all'interno; puoi usare il comando "Mostra Contenuto Pacchetto" su un'applicazione Mac OS X per esplorarne il contenuto. Quindi il comando sopra sarà, posto di avere 4D 6.8 nella cartella Applicazioni: sudo -b /System/Library/Frameworks/Carbon.framework/Versions/Current/Support/LaunchCFMApp /Applications/4th\ Dimension/Contents/MacOS/4th\ Dimension Oppure nel caso di 4D 2003 sempre nella cartella Applicazioni: sudo -b /System/Library/Frameworks/Carbon.framework/Versions/Current/Support/LaunchCFMApp /Applications/4th\ Dimension/Contents/MacOSClassic/4th\ Dimension Un suggerimento: non state a scrivere il pathname a mano, ma con la finestra del Terminale aperta potete trascinare dentro un file qualsiasi e il pathname verrà compilato completo di tutti i caratteri ben formattati. Ecco ad esempio il pathname della mia personale posizione di 4D 2003, il cui percorso è 4D:4D 2003.6:4th Dimension 2003.6 /4D/4D\ 2003.6/4th\ Dimension\ 2003.6.app/Contents/MacOSClassic/4th\ Dimension |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Scelta della chiave primaria
Un punto critico nell'ideare lo schema concettuale di un database è la scelta degli attributi caratteristici dei set di entità che sono in definitiva le tabelle. Un attributo o un insieme di attributi i cui valori identifichino in modo univoco ogni entità del set (record) è chiamato chiave. In linea di principio ogni tabella dovrebbe avere una chiave, in modo che ogni record sia distinguibile dall'altro. Anche se il mondo reale offre a volte delle chiavi naturali, in molti casi è preferibile usare un dato a parte che non possa cambiare per nessun motivo: i programmatori 4D hanno a disposizione per tale fine la funzione Sequence number che genera un numero univoco per ogni record creato per ogni tabella. D'altro canto l'uso di Sequence number ha degli svantaggi da considerare, dovuti proprio alla propria unicità e al legame diretto con la struttura. Per esempio: - in caso di danneggiamento del file dati, quando l'unica soluzione è esportare i dati e ricrearli in un nuovo file; - in caso di esportazione/importazione di dati per il passaggio ad una nuova versione (vedi la faq Rapido Trasferimento Dati); - unione dei dati provenienti da strutture distinte, anche se uguali. Per ovviare a questi inconvenienti è meglio usare dei contatori creati in proprio. Ecco un esempio in cui la tabella [MieiContatori] ha un campo per ogni contatore che voglio tenere: C_POINTER($1;$PuntaAlCampo) C_LONGINT($0) $PuntaAlCampo:= $1 READ WRITE([MieiContatori]) If (Records in table([MieiContatori])=0) CREATE RECORD([MieiContatori]) SAVE RECORD([MieiContatori]) End if ALL RECORDS([MieiContatori]) While (Locked([MieiContatori])) ` controllo se è bloccato DELAY PROCESS(Current process;10) LOAD RECORD([MieiContatori]) End while $PuntaAlCampo-> := $PuntaAlCampo->+1 $0 := $PuntaAlCampo-> SAVE RECORD([MieiContatori]) UNLOAD RECORD([MieiContatori]) READ ONLY([MieiContatori]) |
2 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Dove sono registrati gli ultimi server
Quando si apre il 4D Client è possibile scegliere fra un elenco un degli ultimi server a cui si è fatto accesso. Questi server vengono registrati in un file che è possibile copare o eliminare da ogni singola macchina client (ad esempio eliminando quelli non più disponibili se diventano troppi). Nella versione 2003 e 6.8 questa cartella si trovava nella cartella 4D principale, mentre nella 2004 si trova nella cartella 4D dell'utente corrente. Windows C:\documents and settings\(nome utente)\Application Data\4D\Favorites 2004 Mac MacHD:Users/(nome utente)/Library/Application/4D/Favorites 2004 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Macro |
Una macro per il form di output
Ecco il testo di una macro da utilizzare per riempire in automatico un form di output o una lista: Case of :(Form event=On Load) :((Form event=On Display Detail)|(Form event=On Printing Detail)) :((Form event=On Printing Break)|(Form event=On Printing Footer)) End case |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Macro |
Una macro per il form di input
Ecco il testo di una macro da utilizzare per creare in automatico gli eventi più usati da utilizzare nei form di input: Case of :(Form event=On Load) :(Form event=On Data Change) :(Form event=on Validate) :(Form event=On Unload) End case |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Backup della cartella MAC4DX ed i file .bundle
Ciao a tutti. Voglio allegare nel backup del database anche la cartella MAC4DX La cartella può contenere 2 tipi di plugin : - come files con suffisso .4CX - come pacchetti con suffisso .bundle Il comando 'Select folder' ed il successivo comando 'DOCUMENT LIST' non permettono di riconoscere nella lista dei documenti contenuti i file con suffisso .bundle, che si comportano in realtà come delle cartelle. E' necessario per cui introdurre anche un successivo controllo sulle cartelle contenute nella cartella MAC4DX, con il comando 'FOLDER LIST'. Per implementare il backup dell'intera cartella MAC4DX da un bottone 'Seleziona Cartella' inserito nella finestra di impostazioni del Backup è possibile utilizzare le seguenti 3 procedure: Nel Bottone 'Seleziona Cartella':------------------------------------------- C_TEXT($tPath) ARRAY TEXT($aDocuments;0) $tPath:=Select folder("Scegli una Cartella da allegare") If ($tPath#"") DOCUMENT LIST($tPath;$aDocuments) FOLDER LIST($tPath;$aDirectories) For ($i;1;Size of array($aDocuments)) If (Find in array(IncludesFiles;$tPath+BKP_GetDirGlyph +$aDocuments{$i})=-1) INSERT ELEMENT(IncludesFiles;Size of array(IncludesFiles)+1) IncludesFiles{Size of array(IncludesFiles)}:=$tPath+BKP_GetDirGlyph +$aDocuments{$i} End if End for If (Size of array($aDirectories)#0) For ($i;1;Size of array($aDirectories)) BKP_XML_GetBundle ($tPath+BKP_GetDirGlyph +$aDirectories{$i}) End for End if End if ` Method: BKP_XML_GetBundle------------------------------------------- $tPath:=$1 DOCUMENT LIST($tPath;$aDocuments) FOLDER LIST($tPath;$aDirectories) For ($i;1;Size of array($aDocuments)) If (Find in array(IncludesFiles;$tPath+BKP_GetDirGlyph +$aDocuments{$i})=-1) INSERT ELEMENT(IncludesFiles;Size of array(IncludesFiles)+1) IncludesFiles{Size of array(IncludesFiles)}:=$tPath+BKP_GetDirGlyph +$aDocuments{$i} End if End for If (Size of array($aDirectories)#0) For ($i;1;Size of array($aDirectories)) BKP_XML_GetBundle ($tPath+BKP_GetDirGlyph +$aDirectories{$i}) End for End if ` Method: BKP_GetDirGlyph------------------------------------------- C_LONGINT($platform) C_TEXT($0) PLATFORM PROPERTIES($platform) If ($platform=3) $0:="/" Else $0:=":" End if (PROVATO SOLO SU MAC) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Ricezione dati via porta seriale
I due comandi che permettono di leggere dati via porta seriale sono RECEIVE PACKET e RECEIVE BUFFER. La differenza sostanziale sta nel fatto che RECEIVE PACKET legge sempre lo stesso numero di caratteri o fino ad un certo carattere di stop, ma il tutto con un limite di 32.000 caratteri, mentre RECEIVE BUFFER legge fino a 10Kb di buffer: quindi è necessario svuotare continuamente il buffer con una serie di comandi del tipo: While (IP_Listen_Serial_Port) RECEIVE BUFFER($vtBuffer) If ((Length($vtBuffer)+Length(vtBuffer))>MAXTEXTLEN) vtBuffer:="" End if vtBuffer:=vtBuffer+$Buffer End while |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Gli oggetti cliccabili
Gli oggetti cliccabili, quelli cioè su cui è possibile utilizzare gli eventi On Clicked e On Double Clicked, sono: - Campi e variabili di tipo boolean - Button, default button, radio button, check box, button grid - 3D Button, 3D radio button, 3D check box - Pop-up menu, hierarchical pop-up menu, picture menu - Drop-down list, menus/drop-down list - Scrollable area, liste gerarchiche, list box - Invisible button, highlight button, radio picture - Termometri, ruler - Tab control - Splitter |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Creare un Quick Report da programma
Ecco un esempio su come creare un quick report da programma: 1. viene creata un'area di appoggio offscreen (cioè non visibile all'utente) 2. viene impostata la tabella corrente 3. vengono inserite le colonne 4. si scelgono le colonne per l'ordinamento 5. si sceglie la destinazione, si esegue il Quick Report 6. si cancella l'area Il codice stampa le colonne cognome e nome da una tabella Anagrafica e li ordina per cognome. `Metodo: SempliceListaQR C_LONGINT(mioQR) mioQR:=QR New offscreen area ` 1 QR SET REPORT TABLE(mioQR;Table(->[Anagrafica])) ` 2 QR INSERT COLUMN(mioQR;1;->[Anagrafica]Cognome) `3, prima colonna QR INSERT COLUMN(mioQR;2;->[Anagrafica]Nome) `3, seconda colonna ARRAY REAL($colonne_ar;1) 4, preparo gli array $colonne_ar{1}:=1 `4, ordina solo per la prima colonna ARRAY REAL($ordinamento_ar;1) $ordinamento_ar{1}:=-1 ` 4, -1 in ordine decrescente e 1 in ordine crescente. QR SET SORTS(mioQR;$colonne_ar;$ordine_ar) ` 4 QR SET DESTINATION(mioQR;qr printer ) ` 5. ALL RECORDS([Anagrafica]) ` 5. QR RUN(mioQR) `5. questo esegue il report impostato! QR DELETE OFFSCREEN AREA(mioQR) ` 6. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Web |
4DScript e il limite dei 32K
Con il tag 4dscript puoi inserire in una pagina html il contenuto della variabile testo ritornata in $0. Come fare se si vuole mandare più di 32K di testo? Bisogna usareun 4DHTMLVAR dopo il 4DSCRIPT. Per esempio: <!--#4DSCRIPT/MioMetodoGetHTML/Mio_blob--> <!--4DHTMLVAR Mio_blob--> Nel metodo "MioMetodoGetHTML" Method, potresti ottenere il puntatore alla variabile blob passata in $1. Se il puntatore è valido puoi riempire il Blob con fino a 2GB di dati (troppi per una pagina Html, cerca di metterne di meno :) Successivamente i dati verranno mostrati dalla successiva 4DHTMLVAR. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
Il comando BLOB size
Comando: BLOB size (blob) -> Longint Categoria: BLOB Versione: 6.0 Parametri: blob è una variabile o un campo di tipo BLOB Risultato: Long Integer - Valore numerico indicante la dimensione del BLOB passato come parametro. Descrizione: BLOB size ritorna la dimensione di un BLOB espressa in byte. Esempio: il seguente frammento di codice aggiunge 100 byte al BLOB mioblob_bl SET BLOB SIZE(BLOB size(mioblob_bl)+100) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Macro |
Incollare testo commentato
La seguente macro permette di inserire il contenuto degli appunti come testo commentato in un metodo: Ed ecco il metodo Macro_Paste_Comment $text_t:=Get text from clipboard If (Length($text_t)>0) $text_t:="`"+Replace string($text_t;Char(13);Char(13)+"`")+Char(13) TEXT TO BLOB($text_t;_blobReplace;Text without length ) _action:=2 End if |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Register Client at Startup
L'opzione Register Client at Startup è impostata per default nella pagina Client/Server delle preferenze di 4d. Ma se non si deve usare il comando EXECUTE ON CLIENT, è meglio togliere questa opzione che migliora le prestazioni del Client e riduce il numero di processi sul server, specialmente nel caso di molti utenti contemporanei. Un altro suggerimento per migliorare le performance è di tenere nascosta la finestra dei processi del 4d Server che viene continuamente aggiornata con l'elenco dei sigoli processi dei singoli utenti, anche se in realtà nessuno la sta guardando. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Usare i numeri di tabella e campo
Quando si rende necessario passare una tabella o un campo come parametro si può utilizzare la forma MioMetodo(3;5) che indicherebbe la terza tabella e il quinto campo. Il codice diventa però molto più leggibile (nonché trasportabile tranquillamente con l'Insider in altri progetti) se utilizziamo i comandi Table e Field che, quando ricevono come parametro un puntatore, ritornano i numeri di tabella e di campo rispettivamente. La forma da utilizzare diventa allora: MioMetodo(Table(->[Tabella3]);Field(->[Tabella3]Campo5)) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Individuare il tipo di formato della data
E' possibile capire il tipo di data utilizzato dal sistema su cui sta girando 4D usando questa unica riga di codice: <>DateFormat:=Replace string(Replace string(Replace string(String(!10/20/99!;MM DD YYYY );"10";"M");"20";"D");"99";"Y") Quando viene valutata su un computer che usa il sistema mese/giorno/anno, la variabile <>DateFormat conterrà il valore M/D/Y. Eseguita su un computer che usi invece il sistema giorno/mese/anno, la variabile <>DateFormat conterrà il valore D/M/Y. Si può usare un Case per gestire le possibilità. Un sistema del genere è assai utili quando, ad esempio, risulta necessario inserire una costante di tipo data: possiamo determinare quindi se inserire 13/4/06 o 4/13/06. Fonte: 4D Today |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
Stampa di un'area 4D Chart
Per stampare un'area di un grafico realizzato con 4D Chart si utilizza il comando CT PRINT, che corrisponde esattamente alla scelta della voce di menu "File" - "Print" della finestra/area Chart. Il comando mostra di default la finestra di richiesta impostazioni per la stampa. Se non si desidera far comparire tale finestra, basta passare come terzo parametro (dopo l'id dell'area e un parametro che indica la posibilità di annullare la stampa) uno "0", che serve appunto a sopprimere la dialog di impostazione stampa. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Cancellazioni multiple nelle list box
Il concetto base è che l'oggetto ListBox corrisponde ad un array di valori booleani che diventano veri se l'utente seleziona una o più righe. Uno dei vantaggi delle list box è quello di consentire cancellazioni multiple in base alla selezione. Ecco il semplice metodo che le realizza: `lbarray è il nome della List Box C_LONGINT($pos) $pos:=0 Repeat $pos:=Find in array(lbarray;True;$pos) If ($pos>0) DELETE LISTBOX ROW(*;"lbarray";$pos) $pos:=0 End if Until ($pos<0) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Calcolo del checksum di un codice a barre EAN13 *
EAN13 è uno dei tipi di barcode più usati (il suo equivalente negli Stati Uniti è il codice UPC-A,che è un sottoinsieme di EAN13, ma dal 2005 i negozi americani devono accettare anche EAN13, eliminando di fatto la differenziazione). Il tredicesimo carattere di un codice EAN13 è il codice di controllo del codice a barre, che viene calcolato utilizzando questo sistema: - Si sommano le cifre del codice di posto pari - Si aggiunge la somma delle cifre di posto dispari, ma moltiplicata per tre. - Il checksum sarà il numero da aggiungere a questa somma per ottenere il primo multiplo di 10 immediatamente superiore. Esprimiamo l'algoritmo di formato 4th Dimension: $check:=0 For ($i;12;1;-1) If (($i/2)#($i\2)) $check:=$check+(Num($String_to_encode[[$i]])) Else $check:=$check+(Num($String_to_encode[[$i]])*3) End if End for $check_S:=String($check) $check:=10-Num(Substring($check_s;Length($check_s))) Fonte: 4D Knowledgebase |
2 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Contare il numero di elementi di un file XML
Ecco un esempio di uso dei comandi Get First XML element e Get Next XML element per contare il numero di elementi di un file XML: `Metodo ContaElementi C_TEXT($1;$radice_t) C_LONGINT($0;$2;$quanti_l) $radice_t:=$1 $quanti_l:=$2+1 C_TEXT($subalterno_t) $subalterno_t:=Get First XML element($radice_t) While (OK=1) $quanti_l:=ContaElementi ($subalterno_t;$quanti_l) `chiamata ricorsiva $subalterno_t:=Get Next XML element($subalterno_t) End while $0:=$quanti_l |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
Il comando ARRAY TO SELECTION
Il comando ARRAY TO SELECTION, la cui sintassi è: ARRAY TO SELECTION (array; field{; array2; field2; ...; arrayN; fieldN}) dove array[n] sono gli array da copiare nella selezione; filed[n] sono i campi che ricevono i dati (tutti appartenenti alla stessa tabella) copia il contenuto di uno o più array in una selezione di record. Il primo degli array passati determina il numero di record che verranno creati. E' importantissimo ricordare che il comando SOVRASCRIVE LA SELEZIONE della tabella: se si vuol essere sicuri di non incappare in inconvenienti può essere utile eseguire un REDUCE SELECTION prima di ARRAY TO SELECTION. Se invece si vuole intenzionalmente sovrascrivere la selezione, è bene controllare se qualche record è bloccato, guardando il contenuto del set del processo chiamato LockedSet, che contiene i record bloccati: i record bloccati non vengono sovrascritti da ARRAY TO SELECTION. Il comando è ottimizzato per l'uso con 4D Server. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Il tasto Control su Mac e Win
I comandi Windows Ctrl down e Macintosh control down permettono di controllare se il tasto Control viene premuto sulle due piattaforme, ritornando True se il tasto è premuto. Il problema è che se in un software Mac si usa Windows Ctrl down, ritornerà True solo se è premuto il tasto Command, mentre Macintosh control down su Win non ha equivalenti e dunque ritorna sempre False. Per effettuare un controllo corretto si può allora utilizzare questo metodo: C_LONGINT($platform) C_BOOLEAN($0) PLATFORM PROPERTIES($platform) If ($platform=3) $0:=Windows Ctrl down Else $0:=Macintosh control down End if |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Convertire un ottale in decimale
La conversione di un numero ottale in un decimale non è assai ricorrente, ma ecco comunque il metodo: C_LONGINT($0;$decimal_l) C_TEXT($1;$octal_t;$number_t;$octalStr_t) $octalStr_t:=$1 $decimal_l:=0 `imposta un valore di ritorno While (Length($octalStr_t)>0) $number_t:=Substring($octalStr_t;0;1) $octalStr_t:=Substring($octalStr_t;2) $decimal_l:=($decimal_l*8)+Num($number_t) End while $0:=$decimal_l |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Risolvere i crash causati dal DEP di Windows Server
Se le applicazioni realizzate con 4D 2003.x appena lanciate si chiudono improvvisamente potrebbe essere colpa del DEP di Windows Server 2003 Service Pack 1. La causa è il DEP (Data Execution Prevention) del Win 2003 SP1. La soluzione: 1. Click su Start, click su Run, scrivere sysdm.cpl, e quindi click su OK. 2. Click sul tab Advanced, click su Performance, e quindi click su Settings. 3. In Performance Options, click sul tab Data Execution Prevention, e quindi click su Add. 4. Nella dialog box "Apri", scegliere il programma (4D Server). 5. Click su Open, click su Apply, e quindi click su OK. Quando viene richiesto di riavviare il computer, click su OK. Tech note di MS agli indirizzi: http://support.microsoft.com/default.aspx?scid=kb;en-us;875351 http://support.microsoft.com/kb/875351/it http://support.microsoft.com/kb/899298/ |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Modifica della porta 4D WebServer
Per motivi di sicurezza si può rendere necessaria la modifica della porta utilizzata da 4D per i servizi Web, la 443. Per modificarla, nelle Preferenze di 4D 2004, andare in "Configuration" sotto "Web" e in "Web Server Publishing" è possibile modificare il numero di porta utilizzata. L'elenco completo delle porte TCP utilizzate da Internet Command si trova qui. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Teoria della normalizzazione: dipendenze funzionali *
Cos’è una dipendenza funzionale? Analizziamo il seguente esempio: [CAP] CAP Città Provincia Abbreviazione_nome_regione Nome_Regione Il CAP è un codice univoco di 5 caratteri. Cosa lo rende una chiave? Il fatto che esso determina tutti gli altri campi. Poiché per ogni CAP esistono una singola Città, una singola Provincia, ecc., questi campi sono in dipendenza funzionale rispetto al campo CAP. Osserviamo poi gli ultimi due campi: l’Abbreviazione determina esattamente la Regione, cioè la regione è in dipendenza funzionale rispetto all’Abbreviazione, che ne fa dunque le veci di una chiave. Ma allora, se Abbreviazione_nome_regione è una chiave, questo campo deve appartenere ad un’altra tabella. Ecco, la Terza Forma Normale (3NF) ci dice proprio che dobbiamo allora creare una tabella [Regioni] che avrà come campi Abbreviazione_nome_regione (chiave primaria) e Nome_Regione Consulta da questo link l’indice delle faq sulla normalizzazione |
2 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
4d come WebService client
Per utilizzare 4d come client di un qualsiasi web service server, anche non un 4d ws, basta seguire questi passi: 1. cerca sul sito del web service server l'indicazione del corrispondente WSDL (Web Service Description Language); per i siti fatti con 4d è automaticamente http://dominio.it/4DWSDL. 2. in ambiente Design scegli il comando "Web Service Wizard" dal menu Tools 3. incolla l'url del WSDL del sito che interessa e clicca su Discover 4. scegli nell'elenco delle procedure quella che serve e fai clic su create 5. 4d genera il codice di consultazione del sito e lo mette in un metodo chiamato "proxy_nome" con l'indicazione dei parametri da passare e i dati ricevuti La differenza (in parole molto povere) fra i server RPC e i server DOC è che i primi ritornano i parametri in modo semplice, mentre i secondi ritornano un documento XML da cui bisogna estrarre i dati che servono. La versione 2004 rispetto alla 2003 cerca di interpretare anche i server DOC e di estrarre i parametri: in entrambi i casi potrebbe sempre servire analizzare l'XML di risposta con i comandi forniti da 4D. Riferimenti e altre info nella faq 4d come webservice server |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
4d come WebService server *
Per realizzare un web service server con 4d basta: 1. attivare il web server (start web server da User o Publish Server at Startup nelle preferenze). Senza licenza web resta attivo per un'ora e poi bisogna chiudere e riaprire. 2. scegliere il Metodo che si vuole pubblicare e nelle proprietà attivare il flag "Allow Web Services Requests" 3. se si vogliono rendere i parametri in Input e in Output più facili da capire per l'utilizzatore usare il comando SOAP DECLARATION 4. l'utilizzatore usa il proprio client webservice (che sia 4d o un altro) interrogando il web service server attraverso il documento automaticamente generato all'url http://tuoserver/4DWSDL Riferimenti da consultare: 4d e PHP Client Soap su web Un 4D web service server |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Il file .4DA e i form modificabili dall'utente
Dalla versione 2004 è possibile rendere alcuni form modificabili in parte dall'utente finale. Quando un form viene segnalato come "Editable by user", questo diventa bloccato nel Design environment. Ciò significa che lo sviluppatore deve esplicitamente "sbloccare" il form per poterlo utilizzare. Tale operazione rende però obsolete le modifiche effettuate dall'utente al form, che dovranno essere ricreate. Le mofiche che l'utente apporta ad un form vengono memoorizzate in un file di tipo .4DA che si troverà allo stesso livello della struttura. Tale approccio permettere di rendere "non obsoleti" i possibile aggiornamenti alla struttura installati dal programmatore. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Ripristinare gli indici
Ecco un semplice metodo per ricostruire gli indici: READ WRITE(*) C_POINTER($table;$field) C_LONGINT($i;$j;$type;$length) C_BOOLEAN($indexed) For ($i;1;Count tables) $table:=Table($i) For ($j;1;Count fields($table)) $field:=Field($i;$j) GET FIELD PROPERTIES($field;$type;$length;$indexed) If ($indexed) SET INDEX($field->;False) SET INDEX($field->;True) FLUSH BUFFERS End if End for End for Alcune annotazioni: - il metodo dovrebbe essere eseguito senza che altri utenti siano connessi e senza che se ne possano connettere prima del suo completamento; - è possibile che la reindicizzazione necessiti di molto tempo; - le subtable devono essere indicizzate a parte. Se la reindicizzazione non andasse a buon fine, bisogna controllare quale campo comporta tale problema. Si potrebbe, ad esempio, prima della reindicizzazione di ogni campo, scrivere in un file su quali campi stiamo agendo, in modo da poter sapere quale dato ha portato al crash. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Tutte le faq sulla normalizzazione
Per rendere più semplice la consultazione dell'argomento, ecco un "indice" per le faq sulla normalizzazione: Teoria della normalizzazione Teoria della normalizzazione: l'abbiamo sempre usata Teoria della normalizzazione: progettare o implementare? Teoria della normalizzazione: dipendenze funzionali Teoria della normalizzazione: la chiave primaria Teoria della normalizzazione: pro e contro Teoria della normalizzazione: denormalizzare Teoria della normalizzazione: ridondanze e storicizzazione dei dati Teoria della normalizzazione: Prima Forma Normale [1NF] Teoria della normalizzazione: Seconda Forma Normale [2NF] Teoria della normalizzazione: Terza Forma Normale [3NF] Teoria della normalizzazione: Forma Normale di Boyce-Codd [BCNF] |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Trovare un elemento in un documento XML usando XPath
4D 2003 introduce un set di comandi XML per scorrere la gerarchia "DOM" di un documento XML. Per trovare un elemento specifico occorre ciclare su tutti i nodi, e identificare i songoli elementi uno per uno. In 4D 2004, il nuovo comando DOM Find XML element permette di trovare l'elemento usando la notazione XPath. Per esempio, poniamodi avere un documento XML con questa struttura: <a> <b> <c> <d/> <e/> </c> </b> </a> Per trovare l'elemento "b" basterà scrivere: $a:=DOM Parse XML source("mio.xml") $b:=DOM Find XML element($a;"/a/b") Allo stesso modo, per trovare l'elemento "e" a partire dall'elemento "a": $e:=DOM Find XML element($a;"/a/b/c/e") Oppure partendo dall'elemento "b": $e:=DOM Find XML element($b;"/b/c/e") |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Creare un'immagine lampeggiante *
Per creare un immagine lampeggiante in una maschera, segui questi passi:: 1. Crea un nuova aimmagine nella Picture library. 2. Imposta l'immagine a 2 colonne e 1 riga 3. Incolla l'immagine nel secondo frame, lasciando il primo vuoto. 4. Trascina l'immagine così creata su un form per craere un picture button, chiamato ad esempio PulsanteImmagine. 5. Aggiungi il seguente codice nel metodo del form: If (Form event=On Load) Set Timer(tickCount) `60esimi di secondo, da impostare secondo la velocità desiderata End if If (Form event=On Timer ) If (PulsanteImmagine=0) PulsanteImmagine:=PulsanteImmagine +1 Else PulsanteImmagine:= PulsanteImmagine -1 End if End if |
1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Stampa di un subform con molti record
Ci sono tre opzioni "Print Frame" per stampare un subform, cioè una maschera a lista contenuta all'interno di un altra maschera (form), come ad esempio le righe all'interno della fattura. L'opzione "Fixed (Truncation)" stampa il form una volta sola, e stampa il massimo numero di elementi correlati nella subform che rientrano nello spazio definito. Il resto degli elementi non viene stampato; questo serve ad avere un numero di pagine stampate fisso per ogni record, a prescindere dal numero dei record in relazione collegati. L'opzione "Fixed (Multiple Records)" non modifica la dimensione del subforn in stampa, ma ristampa l'intera form tante volte quanto sia necessario a stampare tutti i record correlati mostrati nella subform. Per esempio, se nella subform si possono mostrare 5 righe per volta e il record padre ha collegati 20 record, in stampa si avranno 4 pagine con 5 sotto-record differenti; questo permette di avere tutte le informazioni del record padre ristampate in ogni pagina. L'opzione "Variable" ridimensiona il subforn in stama in modo tale da mostrare tutti i record correlati. Il form padre è stampato una volta solo, il subform viene esteso fino alla fine della pagina e può riprendere nelle pagine successive, finché necessario a stampare tutti i record. Questa opzione serve a stampare tutti i record quando non si ha bisogno di ripetere le stesse informazioni del record padre su ogni pagina, |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Stampa dei campi negli header, break e footer
Quando si stampa utilizzando una maschera di un archivio, i record della tabella corrente vengono caricati dopo aver stampato l'area identificata dallo header (testata), dentro l'area detail (dettaglio), ripetutamente finché ci sono record in selezione. In fondo alla pagina viene ripetuto il footer (piede). Stampando ad esempio delle fatture si potrebbe avere la seguente situazione: i campi del form della tabella corrente (ad esempio Modalità_pagamento o Totale) non vengono stampati nelle zone al di fuori del "Detail", ma i campi di altre tabelle (ad esempio i dati dell'archivio Clienti, che è in relazione) vengono visualizzati. Così, risulta necessario visualizzare i dati relativi alla tabella corrente negli header, break e footer usando delle variabili. Gli assegnamenti possono essere effettuati, ad esempio, nel pulsante che genera la stampa. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Lanciare applicazioni senza mostrare le finestra
Nella 4D 2004, è stato introdotto il comando LAUNCH EXTERNAL PROCESS per eseguire applicazioni esterne in un processo separato e distinto da quello di 4d. Su Windows, appare una finestra di terminale quando lanci un applicativo basato sulla console. Nella 2004.1, il comando SET ENVIRONMENT VARIABLE è stato aggiornato per nascondere la finestra. Ecco come: SET ENVIRONMENT VARIABLE("_4D_OPTION_HIDE_CONSOLE";"True") LAUNCH EXTERNAL PROCESS("dir.exe";$input;$output) Per rivedere la finestra basta lanciare di nuovo un LAUNCH EXTERNAL PROCESS senza il comando SET ENVIRONMENT VARIABLE o impostandolo a "False." |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Chiedere la data all'utente
Solitamente l'utente che si vede davanti una finestra di Request che gli chieda l'inserimento di una data è costretto ad inserire 6,8,10 caratteri (con i separatori), con conseguente perdita di tempo, soprattutto se la data da inserire è (relativamente alla data attuale) sempre la stessa: se, ad esempio, l'utente inserisce solitamente la data di inizio del mese corrente o della settimana corrente, possiamo generare delle scorciatoie per avere un vantaggio dalla possibilità di inserire una stringa. Ecco allora un metodo che gestisce una serie di scorciatoie da tastiera per le date. Le scorciatoie sono: 1) M : la prima data del mese 2) U : l'ultima data del mese 3) A : il primo giorno dell'anno 4) F : l'ultimo giorno dell'anno 5) L : il primo giorno della settimana 6) D : l'ultimo giorno della settimana 7) + : domani 8) - : ieri 9) O : oggi 10) Se l'utente inserisce un numero, viene ritornata la data con il mese e l'anno correnti 11) Se l'utente inserisce un numero, un separatore e un numero, viene ritornata la data con l'anno corrente 12) Altrimenti viene ritornato il risultato della funzione "Date" di 4th Dimension. Ecco il metodo. C_TEXT($1) C_DATE($0) $currentMonthString_S:=String(Month of(Current date(*))) $currentYearString_S:=String(Year of(Current date(*))) $firstDateOfThisMonth_D:=Date("01/"+$currentMonthString_S+"/"+$currentYearString_S) Case of : ($1="O") ` oggi $0:=Current date(*) : ($1="A") ` primo giorno dell'anno $0:=Date("01/01/"+$currentYearString_S) : ($1="F") ` ultimo giorno dell'anno $0:=Date("31/12/"+$currentYearString_S) : ($1="M") ` primo giorno del mese $0:=$firstDateOfThisMonth_D : ($1="U") ` ultimo giorno del mese $0:=Add to date($firstDateOfThisMonth_D;0;1;-1) ` ho aggiunto un mese e tolto un giorno : ($1="L") ` primo giorno della settimena. Lunedì $data_D:=Current date(*) $miogiorno_L:=((Day number($data_D))-1)+(7*(Num(((Day number($data_D))=1))) $0:=Current date(*)-($miogiorno_L-1) `se si vuole Domenica usare direttamente `$0:=Current date(*)-(Day number(Current date(*))-1) : ($1="D") ` ultimo giorno della settimana. Domenica. $data_D:=Current date(*) $miogiorno_L:=((Day number($data_D))-1)+(7*(Num(((Day number($data_D))=1))) $0:=Current date(*)+(7-$miogiorno_L) ` se si vuole Sabato usare direttamente ` $0:=Current date(*)+(7-Day number(Current date(*))) : ($1="+") `domani $0:=Current date(*)+1 : ($1="-") `ieri $0:=Current date(*)-1 Else `nessuno dei casi precedenti $testDate_D:=Date($1) If ($testDate_D=!00/00/00!) `se non è una data completa la riempio io $1:=$1+"/"+$currentYearString_S $testDate_D:=Date($1) If ($testDate=!00/00/00!) $1:=$1+"/"+$currentMonthString_S+"/"+$currentYearString_S $testDate_D:=Date($1) End if ` ($testDate_D=!00/00/00!) End if ` ($testDate_D=!00/00/00!) $0:=$testDate_D End case |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Teoria della normalizzazione: la chiave primaria
Il concetto di “primary key” è fondamentale nella teoria dei database. Il concetto è semplice: ogni record deve avere qualcosa che lo identifichi univocamente. La chiave primaria di una tabella serve inoltre come punto di partenza per la gestione delle relazioni con le altre tabelle: per esempio una fattura è un relazione con un unico e ben determinato cliente, come un impiegato è assegnato ad un unico e ben determinato ufficio. Una chiave primaria deve avere un valore per ogni record. La chiave primaria può essere formata da un campo o dalla combinazione di più campi. Questo dato dei database relazionali ha bisogno di una discussione a parte per quanto riguarda 4th Dimension: se molti sistemi di sviluppo per database usano esplicitamente il concetto di chiave primaria formata da più campi, ciò non avviene in 4D. In realtà è quasi banale bypassare questo limite aggiungendo alla tabella un campo che memorizzi la concatenazione dei campi che compongono la chiave primaria. Una chiave del genere può essere molto facilmente gestita utilizzando i trigger. Una chiave primaria deve essere unica, obbligatoria e immodificabile: un classico errore è quello di attribuire il valore di chiave primaria a campi “volatili”. Ad esempio, per la tabella: [Clienti] Nome Indirizzo il campo Nome sembrerebbe un buon candidato come chiave primaria: sbagliato! Cosa succede se Nome cambia, ad esempio per correggere un semplice errore di inserimento? Dovremo cambiare tutti i record delle fatture di quel cliente. Risulta molto più corretto usare un valore “esterno” ai dati reali, come Sequence number, o qualsiasi altro sistema che generi comunque dei valori da chiave primaria. Per completezza sull’argomento diamo anche la definizione di superchiave, che non è altro che un insieme di campi per i quali la tabella non contiene due record con valori identici per tali campi (non è altro che il superinsieme di una chiave). Inoltre in uno schema relazionale possono esserci più chiavi (ma solo una di esse verrà definita “principale”). Consulta da questo link l’indice delle faq sulla normalizzazione |
1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
Come usare il Sequence Number
La funzione Sequence Number ritorna un numero progressivo automatico per ogni tabella ed è usato per creare il codice identificativo (o chiave primaria) del singolo record. Parte da 1 alla creazione del database ed è incrementata da 1 per ogni record salvato. La funzione però aveva alcuni limiti per cui era sconsigliata: in pratica poiché non era possibile modificarne il valore corrente diventava difficile, ad esempio, spostare i dati da un database all'altro o ripartire da un certo numero. Finalmente dalla 2004.1 è disponibile un modo accedere al valore usato dal Sequence Number: 1. Get Database Parameter ( Tabella ; Table Sequence Number ) -> Longint Legge il valore corrente del prossimo numero che sarà assegnato dalla Sequence Number per la Tabella passata come primo parametro 2. SET DATABASE PARAMETER ( Tabella ; Table Sequence Number ; Longint ) Imposta il prossimo numero progressivo che sarà generato dalla Sequence Number pe la Tabella. |
1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
2004.1: creare relazioni da linguaggio con AP Create relation
Il 4D Pack della 2004.1 permette di creare via linguaggio di programmazione le relazioni della struttura. La sintassi del comando AP Create relation è semplice: AP Create relation (sourceTableNum; sourceFieldNum; destTableNum; destFieldNum) prende cioè i numeri di tabella e di campo di partenza e di destinazione della relazione. Per le proprietà della relazione bisogna sempre agire dalla finestra delle proprietà della relazione. Se l'operazione viene portata a termine con successo, la funzione ritorna 0, altrimenti un codice di errore. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
Memorizzare le opzioni di stampa
Il comando AP Print settings to BLOB del 4D Pack 2004 permette di memorizzare in un BLOB passato come parametro le attuali impostazioni di stampa per 4th Dimension. Il BLOB memorizza sia i parametri di layout (paper, orientation, scale) che gli altri parametri tipo (number of copies, paper source, ecc.) Il BLOB non può essere modificato via linguaggio di programmazion, ma va richiamato usando il comando AP BLOB to print settings. Il comando ritorna 1 se il BLOB è stato correttamente generato, altrimenti 0. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Identificare il tipo di un'immagine
Per conoscere il tipo di un'immagine in un documento o in un blob è possibile usare questo comando del plugin 4D Pack: AP Get Picture type (Blob_immagine) -> longint Il valore ritornato sarà: -1 Sconosciuto 0 immagine 'PICT' 1 immagine 'PICT' compressa con QuickTime 2 immagine JPEG 3 immagine WMF 4 immagine EMF 5 immagine BMP 6 immagine GIF Esempio: DOCUMENT TO BLOB($nomeDocumento_t;$immagine_blb) $tipo_l:=AP Get picture type($immagine_blb) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Eseguire una query fra due campi
Quando si vogliono confrontare due valori dei record di una tabella non è possibile usare la forma: QUERY([Tabella];[Tabella]Campo1 < [Tabella]Campo2) Questa forma non funziona. Deve utilizzarsi invece: QUERY BY FORMULA([Tabella];[Tabella]Campo1 < [Tabella]Campo2) Si deve in ogni caso tenere presente che tale operazione è più lenta, anche su campi indicizzati, poiché non si possono usare gli indici per eseguirla: 4D caricherà infatti ogni record per eseguire il confronto (valutare l'espressione passata come argomento) per poi aggiungerlo o meno alla selezione risultante. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Stile |
Non mostrare valori quando un campo numerico vale zero
Quando si mostrano dei numeri in una maschera di output o in un report è possibile "nascondere" i campi che contengono semplicemente uno zero. Possiamo sfruttare infatti la possibilità di scrivere un formato del tipo "valore_positivo;valore_negativo;zero" per i numeri. Ad esempio, un formato possibile potrebbe essere: "###.##0 ;###.##0-;" I formati possono essere inseriti o direttamente nel campo o nel report, oppure creati e memorizzati nelle Database Properties. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Se andando in Design 4D va in crash
Capita (raramente, ma potrebbe capitare) che un metodo o una maschera (form) si danneggino e mandino in crash 4D quando vengono aperti. Ciò diventa realmente un problema quando, passando al Design, 4D cerca sempre di riaprire la finestra "danneggiata" perchè ricorda quale erano le finestre aperte dall'utente da una sessione all'altra. Tenendo però premuto il tasto Alt (Option su Mac) quando si passa per la prima volta all'ambiente Design, 4D non aprirà nessuna delle finestre precedentemente aperte. Questo permette di selezionare poi l'oggetto nella finestra Explorer (avendo avuto cura di chiudere il pannello di Anteprima) e di eliminarlo. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Un AppleScript per lanciare 4D
Vediamo come si può lanciare un 4D Server usando un AppleScript. Supponiamo che: - il disco di chiami "Titanium" - la struttura si chiami "test" - il data file is chiami "test.data" - entrambi siano nella cartella "test" - la cartella sia contenuta nella cartella "Documents" dell'utente "pierpaolo" Laciare Script Editor e inserire questo codice, sostituendo al più i percorsi di 4D Server: tell application "Finder" activate select file "Titanium:Users:pierpaolo:Documents:test:test" open selection using file "4D Server" of folder "4D Server" of folder "Applications" of startup disk end tell Salvare lo script e scegliere "Non mostrare all'avvio". A questo punto aggiungere lo script agli elementi di avvio. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Web |
Tag HTML nidificati
Spesso può essere necessario nidificare i tag HTML. Ad esempio: <input type ="text" name="varName" value = "<!--4DVAR [Table]Field-->"> è un esempio interessante poiché il tag nifificato è inserito all'interno delle virgolette. Poiché però le specifiche HTML non permettono di inserire tag all'interno di altri, per specificare se un check box è attivo NON si può scrivere: <input type="checkbox" name="cbOne" value="Yes" <!--4DHTMLVAR isChecked-->> dove la variabile isChecked ha il valore "checked". Ovviamente, in casi come questo, si può usare un semplice stratagemma: <!--4DIf (isChecked="checked")--> <input type="checkbox" name="cbOne" value="Yes" checked> <!--4DElse--> <input type="checkbox" name="cbOne" value="Yes"> <!--4DENDIF--> |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Aprire le finestre del Pannello di controllo con AP Sublaunch
Il comando AP Sublaunch del 4D Pack permette di eseguire una azione di sistema sotto Windows. Possiamo utilizzarlo quindi anche per aprire, ad esempio, finestre del pannello di controllo di Windows. Per aprire il pannello di controllo: $String_t:="rundll32 shell32.dll,Control_RunDLL" $lErr:=AP Sublaunch ($String_t;0) Per aprire una voce specifica del pannello di controllo, ad esempio il pannello di controllo dell'origine dei dati ODBC: $String_t:="rundll32 shell32.dll,Control_RunDLL odbccp32.cpl" $lErr:=AP Sublaunch ($String_t;0) Alcune voci del pannello di controllo contengono più pagine, selezionabili attraverso un tab control. Possiamo anche da linguaggio specificare quale pagina aprire. Con l'esempio che segue viene aperta la pagina screen saver delle proprietà dello schermo: $String_t:="rundll32 shell32.dll,Control_RunDLL desk.cpl,,1" $lErr:=AP Sublaunch ($String_t;0) Fonte: Jeffrey Kain, 4D Today |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Mail avvelenata anti spam
Per chiunque abbia un sito, abbiamo già pubblicato una faq su come elaborare leggeremente l'indirizzo in modo tale che non sia facilmente recuperabile dai programmi che girano su inernet e recuperano le mail dal codice html. C'è un'alternativa.. che è quella di includere nel tuo sito un indirizzo "avvelenato", cioè finto del tipo "billgates@miodominio.it" e lo affoghi nel codice html all'interno di un commento o in un font che lo rende non visibile all'utente normale. Il programma che tira su gli indirizzi dai siti prende anche quello e poi tu filtri i messaggi che ti arrivano con la regola "blocca i messaggi in cui fra i destinatari c'è anche billgates@miodominio.it" |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
4th Dimension e Mac OS 10.4 - Tiger *
La prima versione di 4D di comprovata compatibilità col nuovo sistema operativo di casa Apple, Tiger, sarà la 2004.2. Per quel che riguarda le altre versioni al momento non si hanno notizie ulteriori. |
1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Se i comandi da menu sembrano non funzionare...
Se i comandi da menu sembrano non funzionare, una delle cose che più probabilmente è successa è che abbiamo dimenticato di associare la menu bar ad una maschera (o form). Supponiamo infatti che la nostra applicazione parta usando il menu bar 1. Quando apriamo il processo relativo ad una certa tabella usiamo il comando MENU BAR(2) per dire al processo di usare la menu bar numero 2, che viene correttamente visualizzata ma, se usata, non produce alcun risultato. Ciò che manca è l'associazione della menu bar al form: andare sulle proprietà del form e alla voce Menu bar scegliere la menu bar #2 Da notare che nelle ultime versioni è possibile dare un nome alle Menu Bar: usando il nome ne guadagna molto la comprensibilità del codice. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Creare un nuovo metodo da programma con 4D Pack
Nel 4D Pack della 2004.1 c'è un nuovo comando AP Create Method che permette di creare un nuovo metodo in un database interpretato. La sintassi è la seguente: codice_errore:=AP Create Method(NomeMetodo;arrayAttributi;blobCodice;nomeCartella) Ecco un esempio: C_LONGINT($err_l) C_TEXT($nomeMetodo_t;$nomeCartella_t) ARRAY LONGINT($attributi_al;4) C_BLOB($codice_blb) $nomeMetodo_t:="Mio Nuovo Metodo" TEXT TO BLOB("ALERT(\"Ciao\")";$codice_blb;Text without length;*) $attributi_al{1}:=1 ` è usabile come 4D action? $attributi_al{2}:=1 ` è invisible? $attributi_al{3}:=1 ` è usabile da soap? $attributi_al{4}:=1 ` è pubblicato nel wsdl? $nomeCartella_t:="Default Folder" $err_l:=AP Create method($nomeMetodo_t;$attributi_al;$codice_blb;$nomeCartella_t) err_l contiene 0 se è andato bene e -1 se c'è stato un errore. Da ricordarsi che funziona solo su database interpretati, non compilati. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Impostare in automatico il formato di stampa
Una delle informazioni che un form è in grado di memorizzare in fase di design è il formato di stampa in cui si desidera stampare, dove per formato di stampa non dobbiamo intendere semplicemente l'orientazione del foglio, orizzontale o verticale, ma anche la vera e propria dimensione del foglio, il che permette di utilizzare facilmente anche formati di carta non standard. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novizi |
Puntatori
I puntatori sono uno strumento di programmazione avanzata, che principalmente permettono di scrivere del codice "generalizzato". Tecnicamente un puntatore contiene un riferimento ad una tabella, campo, variabile di qualsiasi tipo compresi gli array o vettori. Ecco un esempio di puntatore ad una variabile: C_TEXT(MiaVariabile_t) C_POINTER(punta_ptr) MiaVariabile_t:="Umberto Migliore" punta_ptr:=->MiaVariabile_t a questo punto: ALERT(punta_ptr->) è come scrivere ALERT(MiaVariabile_t) Ad esempio, se scrivo una procedura generica per la gestione dei pulsanti di una maschera posso usare una variabile di tipo puntatore invece di indicare la variabile stessa. Se ad esempio scrivo un pezzo di codice come il seguente If (Condizione) ` se la condizione è Vera… ENABLE BUTTON (MioPulsante) ` abilita questo pulsante Else ` altrimenti… DISABLE BUTTON (MioPulsante) ` disabilitalo End if dovrò ripeterlo se ho molti pulsanti nel form. Invece è possibile scrivere un metodo generico "ImpostaPulsante" così: ` metodo IMPOSTA PULSANTE ` IMPOSTA PULSANTE ( Pointer ; Boolean ) ` IMPOSTA PULSANTE ( ->MioPulsante ; Abilita ) ` ` $1 – Puntatore al pulsante ` $2 – Booleano. Se TRUE, abilita il pulsante. Se FALSE, lo disabilita If ($2) ENABLE BUTTON($1->) Else DISABLE BUTTON($1->) End if |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
Impostare il timeout di una chiamata SOAP
Nelle chiamate SOAP con Call Web Service il timeout di connessione è di default 10 secondi: se il server non risponde in questo tempo, il client chiude la connessione. Per impostare un timeout differente per la prossima chiamata è possibile usare il seguente comando (disponibile dalla versione 2004): SET WEB SERVICE OPTION(Web Service HTTP Timeout;30) Se non si riesce ad utilizzare questa opzione, magari perchè la connessione cade lo stesso malgrado un timeout più lungo, allora si può provare ad ottenere il risultato della propria chiamata in differita. Cioè, ipotizzo una comunicazione del genere: A) il client : invia il dato B) il server : riceve e risponde subito un codice "sto elaborando" C) il client : ogni tempo X riprova a chiedere lumi al server D) il server : quando ha finito il codice è "ok" oppure "err, lista errori" Se il client (e l'utente) deve rimanere bloccato in attesa, il tempo X potrebbe essere molto breve, anche di 5 secondi. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Uso dei semafori
Quando si vuole essere certi che una certa operazione sia eseguita senza contemporaneità è possibile usare la funzione Semaphore. Questa funziona permette di testare se un semaforo esiste già (ritorna TRUE) oppure lo crea (e ritorna FALSE). Eseguite le sue operazioni lo si cancella con Clear Semaphore. Ecco un esempio di codice per usarlo: If (Semaphore("ModificaDelListinoPrezzi")) ` Provo a creare il semaforo ALERT("Qualcun altro sta già modificando i prezzi. Riprova più tardi.") Else ` Metti qui il codice che devi eseguire CLEAR SEMAPHORE("ModificaDelListinoPrezzi")) ` Non mi serve più End if Oppure per una modifica che coinvolge operazioni di breve durata, faccio aspettare la mia richiesta finché non si libera il posto: C_Boolean($Fatto_b) $Fatto_b:=False While ($Not($Fatto_b)) If (Semaphore("RegistroNumFattura")) IDLE Else ' Metti qui il codice che devi eseguire CLEAR SEMAPHORE("RegistroNumFattura") $Fatto_b:=True End if End while |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Problemi conosciuti fra 4D e le stampanti HP con driver PCL
Esiste un problema di compatibilità fra alcuni driver PCL per stampanti HP sotto Windows e 4th Dimension. In questi casi, la cosa migliore è utilizzare un driver di tipo PostScript. Se la stampante non supportasse questo linguaggio, è consigliabile usare un driver Microsoft per stampanti HP invece del driver distribuito insieme alla stampante. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Comunicazione via porta seriale
Le comunicazioni attraverso le porte seriali tipo RS 232, RS 422 o RS 485 sia in trasmissione che in ricezione possono essere gestite dallo stesso metodo. Eccone un esempio. Utilizzaremo le seguenti variabili: <>Port è la porta da usare per la trasmissione/ricezione. <>Param sono le impostazioni della porta seriale (velocità, data bit, etc.). <>In_Out: controlla l'esecuzione del While. <>vTransmit è la stringa da trasmettere. <>tPages è un array testo per gestire ricezioni maggiori di 30.000 caratteri. Ecco il metodo: C_TEXT($vRecept) C_TEXT($ReadMem) ARRAY TEXT(<>tPages;1) <>PageNumber:=1 SET CHANNEL(<>Port;<>Param) SET TIMEOUT(<>Time_Out) <>In_Out:=True While (<>In_Out) RECEIVE BUFFER($vRecept) Case of : ($vRecept#"") ` dati ricevuti $ReadMem:=$ReadMem+$vRecept <>ReadVar:=<>ReadVar+$vRecept <>LongVarRead:=Length(<>ReadVar) If (Length($ReadMem)>30000) <>tPages{<>PageNumber}:=$ReadMem $ReadMem:="" <>ReadVar:="" <>PageNumber:=<>PageNumber+1 CALL PROCESS(1) INSERT ELEMENT(<>tPages;Size of array(<>tPages)+1) End if CALL PROCESS(-1) : (<>vTransmit#"") ` trasmissione dati BEEP SEND PACKET(<>vTransmit+Char(13)) <>vTransmit:="" CALL PROCESS(-1) End case DELAY PROCESS(Current process;30) End while SET CHANNEL(11) In caso di alti flussi di dati potrebbe essere necessario ridurre il tempo di pausa inserito nella riga: DELAY PROCESS(Current process;30) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Anticipare l'inserimento di una parola
Ecco un metodo semplice per anticipare cosa sta scrivendo l'utente in un campo testo, ipotizzando che il contenuto possa già trovarsi in una tabella a disposizione: ad esempio, per fare un filtro su una sottolista o per suggerire un termine già inserito o un termine fra una lista definita. Dato un oggetto parola_t, bisogna attivare l'evento "on after keystroke": da considerare che questo è chiamato prima di uscire dal campo, quando la variabile parola_t non contiene niente; per questo prendiamo il valore con la funzione "get edited text" If (Form event=On After Keystroke) caratteri_t:=Get edited text If (caratteri_t#"") QUERY([Tabella];[Tabella]ParolaChiave = caratteri_t +"@") SELECTION TO ARRAY([Tabella]ParolaChiave; listaParole_at) UNLOAD RECORD([Tabella]) Else REDUCE SELECTION([Tabella];0) ARRAY STRING(50;listaParole_at;0) End if End if |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novita' |
Ottenere l'elenco degli oggetti di un form
Il nuovo comando della versione 2004 GET FORM OBJECTS permette di popolare tre array (passati come parametro) che elencano gli oggetti presenti in un certo form. Ciò risulta molto utile se l'aspetto del form deve essere gestito in modo dinamico. La sintassi è del tipo: GET FORM OBJECTS($arrOggetti_at;$arrVariabili_aptr;$arrPagine_ai) dove i tre array contengono i nomi degli oggetti, i relativi puntatori ad essi e il numero di pagina in cui si trovano. Una seconda sintassi prevede l'aggiunta del parametro "*" che forza la restituzione degli oggetti relativi alla sola pagina corrente del form. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Cambiare il nome di un metodo
Qualsiasi sia la ragione, quando si decide di cambiare il nome di un metodo in una struttura, bisogna assicurarsi di averlo fatto dovunque. Il sistema principale per trovare tutte le occorrenze in cui è usato un metodo è usare il comando "Find in Database..."; comunque non è del tutto completo. Ecco un elenco di altri posti dove guardare: - nella finestra dove si impostano i Menu - nella finestra delle password di 4D (se ci sono metodi eseguiti all'avvio dell'utente) - nelle Etichette (Label Editor), dove è possibile indicare un metodo da eseguire quano si stampa un'etichetta - nelle Ricerche (Query By Formula), dove puoi inserire il metodo come una stringa ed eseguirlo durante la ricerca - nei Rapporti (Report), dove è possibile inserire un metodo come formula di una colonna |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
Importando da Excel via ODBC perdo la prima riga
Usando ODBC, Microsoft Excel ritiene che la prima riga del foglio di calcolo contenga i nomi dei campi: quindi, per questo motivo, l'importazione dei dati in 4D effettuata via ODBC non "prende" il primo record. E' importante notare come questo comportamento non sia un errore, ma rientri in realtà nello standard ODBC, per il quale è necessario avere un nome per ogni colonna importata: ciò per evitare qualsiasi problema. Come soluzione si può pensare di inserire nel foglio di calcolo, prima dell'importazione, una riga di celle vuote: tale riga verrà considerata da ODBC come la riga contenente i nomi delle colonne. La riga di celle vuote può essere inserita a mano oppure via linguaggio di programmazione usando il plug-in di 4th Dimension DDE Tools. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Importare/esportare campi con immagini
Una soluzione al problema è quella di utilizzare i comandi IMPORT DATA e EXPORT DATA. Prima però è necessario creare un progetto di import/export in questo modo: - aprire l'editor di import/export; - scegliere i campi; - scegliere se esportare tutto o la selezione (meglio la selezione, non si sa mai); - nella sezione "Format" scegliere 4th Dimension; - salvare il progetto cliccando sul pulsante di salvataggio delle impostazioni ("Save settings") nella stessa cartella della struttura (nel nostro esempio supporremo di aver salvato il progetto col nome "IEProject"); - premere "Cancel" per uscire. A questo punto, i due metodi che seguono permettono importazione ed esportazione dei dati: `Metodo: Import C_BLOB($bProject) DOCUMENT TO BLOB("IEProject";$bProject) `Carica l'Import/Export Setting IMPORT DATA("FileName";$bProject) `Metodo: Export C_BLOB($bProject) DOCUMENT TO BLOB("IEProject";$bProject) `Sempre Carica EXPORT DATA("FileName";$bProject) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novizi |
Se un'immagine non viene visualizzata
Quando un'immagine non viene visualizzata, molto probabilmente questo significa che il tipo di pict non è supportato dalla macchina, o meglio dalla sua configurazione software: in genere basta installare Quicktime (che è gratuito) o anche solo aggiornarlo all'ultima versione. Per conoscere i tipi di file immagine supportati si usa il comando: PICTURE TYPE LIST (formatArray{; nameArray}) che riempie gli array passati come parametro con i codici di import/export di QuickTime che la macchina supporta. Diventa facile così controllare se il tipo della pict in questione è supportato. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
SET TABLE TITLES e SET FIELD TITLES *
Il comando SET TABLE TITLES permette di nascondere, riordinare o rinominare le tabelle presenti nel database quando questo elenco appare nelle dialog di 4th Dimension, come ad esempio il Query Editor o Quick Report. La sintassi è: SET TABLE TITLES (tableTitles; tableNumbers) dove tableTitles è l'array contenente i nuovi nomi e tableNumbers le attuali posizioni nella struttura (table number). Gli array devono essere sincronizzati. Per non far comparire una tabella basta non includerne titolo e numero negli array. Quindi, ad esempio supponiamo di avere tre tabelle A, B e C, create in questo ordine, e di volerle far apparire come X, Y e Z. Inoltre non vogliamo che la tabella B sia visibile. Infine, vogliamo far apparire le tabelle nell'ordine Z e X. Tutto ciò si fa semplicemente inserendo Z e X nell'array dei nomi e 3 e 1 nell'array delle posizioni. SET TABLE TITLES non modifica la struttura, ma è valido per le semplici sessioni: quindi ad esempio, più 4D Client possono vedere lo stesso database simultaneamente in modo differente. SET TABLE TITLES non ha il potere di modificare l'attributo Invisible attribuito ad una tabella nella struttura: così, una tabella invisibile continuerà ad esserlo, anche se inserita negli array passsati al comando. Il comando SET FIELD TITLES è molto simile, semplicemente applica le stesse considerazioni di SET TABLE TITLES ai campi di una tabella. |
2 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Uso di Day number col calendario europeo
La funzione Day number segue la convenzione americana relativa alla numerazione dei giorni: 1 è domenica e 7 è sabato. Per convertire tale numero in formato europeo (dove il giorno numero 1 è lunedì e il 7 è la domenica) basta fare: $miogiorno_l:=((Day number($data_d))-1)+(7*(Num(((Day number($data_d))=1))) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Ripulire i dati dopo una importazione DBF
Se capita di dover sviluppare un programma 4D che abbia come dati quelli presenti in archivi DBF, quando viene eseguita l'importazione degli archivi DBF i dati di tipo stringa contengono degli spazi finali inutili. Una tecnica per risolvere il problema è eseguire il presente codice di correzione: For ($tableNum_l;11;20) `se, ad esempio, le prime 10 tabelle non sono importate For ($campoNum_l;1;Count fields($tableNum_l)) GET FIELD PROPERTIES($tableNum_l;$campoNum_l;$tipoCampo_l) If ($tipoCampo_l =0) $table_ptr:=Table($tableNum_l) ALL RECORDS($table_ptr->) $campo_ptr:=Field($tableNum_l;$campoNum_l) APPLY TO SELECTION($table_ptr->;$campo_ptr->:=EliminaSpazi ($campo_ptr->)) End if End for End for Il metodo EliminaSpazi si trova in questa faq. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Estrarre i nomi e i valori da un url
Poniamo di avere una stringa nella forma "http://www.sviluppo4d.it?arg=1&arg2=2&arg3=3". Questa stringa è facilmente spezzata in due array di nomi e valori corrispondenti con il comando GET WEB FORM VARIABLES. Ma in alcuni casi, per risparmiare spazio nella stringa (gli URL sono limitati a 255 caratteri) la stringa potrebbe essere del tipo "http://www.sviluppo4d.it?parametro1=500&miocomando", cioè potrebbe mancare il valore con il suo "=". In questo caso si può usare questo metodo, che accetta come parametri la stringa e il puntatore dei due array, dei nomi e dei valori. `Metodo: EstraiNomiEValori C_TEXT($1;$testoParametri_t;$stringa_t) C_POINTER($2;$Nomi_ptr) C_POINTER($3;$Valori_ptr) C_TEXT($sinistra_t;$destra_t) $testoParametri_t:=$1 $Nomi_ptr:=$2 $Valori_ptr:=$3 ` se troviamo un'altra & nella stringa la gestiamo richiamndo lo stesso metodo If (Position("&";$testoParametri_t)#0) $stringa_t:=Substring($testoParametri_t;0;Position("&";$testoParametri_t)-1) $testoParametri_t:=Substring($testoParametri_t;Position("&";$testoParametri_t)+1) EstraiNomiEValori($testoParametri_t;$Nomi_ptr;$Valori_ptr) Else $stringa_t:=$testoParametri_t End if ` Qui inizia il lavoro vero e proprio If (Length($stringa_t)>0) ` controlla se si tratta di un assegnamento normale o solo di un nome If (Position("=";$stringa_t)#0) $sinistra_t:=Substring($stringa_t;0;Position("=";$stringa_t)-1) ` parte sinistra $destra_t:=Substring($stringa_t;Position("=";$stringa_t)+1) ` parte destra Else $sinistra_t:=$stringa_t ` solo la parte sinistra, senza la parte destra End if INSERT ELEMENT($Nomi_ptr->;1) INSERT ELEMENT($Valori_ptr->;1) $Nomi_ptr->{1}:=$sinistra_t $Valori_ptr->{1}:=$destra_t End if |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Spostamento di una sottolista gerarchica
Ecco una metodo semplice per gestire lo spostamento di una sottolista all'interno di una lista Gerarchica. L'oggetto che contiene la lista gerarchica avrà questo codice: If (Form event=On Drop ) SpostaSottolista(Self->) REDRAW LIST(Self->) End if Ed ecco il codice del metodo SpostaSottolista: C_LONGINT($1;$Lista_l) C_LONGINT($oggettoOrig_l;$elementoOrig_l;$processoOrig_l) C_LONGINT($riferimentoOrig_l;$riferimentoDest_l;$sottolista_l) C_TEXT($testoOrig_t;$testoDest_t) C_BOOLEAN($aperta) $Lista_l:=$1 `prendo i dati della posizione di partenza e di quella di arrivo DRAG AND DROP PROPERTIES($oggettoOrig_l;$elementoOrig_l;$processoOrig_l) GET LIST ITEM($Lista_l;$elementoOrig_l;$riferimentoOrig_l;$testoOrig_t;$sottolista_l;$aperta_b) GET LIST ITEM($Lista_l;Drop position;$riferimentoDest_l;$testoDest_t) `cancello la partenza e inserisco i dati nella posizione di arrivo DELETE LIST ITEM($Lista_l;$riferimentoOrig_l) INSERT LIST ITEM($Lista_l;$riferimentoDest_l;$testoOrig_t;$riferimentoOrig_l;$sottolista_l;$aperta_b) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
Ottenere l'ora di modifica dei file su server FTP
Finalmente dalla versione 2003.6 e dalla versione 2004.1 sono stati modificati due comandi facenti parte del pacchetto Internet commands, e precisamente il comando 'Ftp_GetDirList' e anche il comando 'Ftp_GetFileInfo'. La modifica che è stata apportata riguarda la possibilità di avere nei vari array di ritorno del comando FTP_GetDirList (ftp_ID; directory; names; sizes; kinds; modDates; modTimes): Integer il nuovo array 'modTimes': è un vettore di interi lunghi che ritornano il valore dell'ora di modifica dei file espresso in secondi. Quindi per esempio, se l'ora di modifica è 10:08 (hh:mm) nel vettore moTimes avremo 3600 x (10) + 60 x (8) = 36.480). Stesso concetto per il comando FTP_GetFileInfo (ftp_ID; hostPath; size; modDate; modTime): Integer che compila il nuovo parametro modTime con l'ora di modifica del singolo files, di tipo time (hh:mm). |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Lista dei processi attivi
La funzione Count tasks ritorna il numero totale dei processi che sono stati aperti in un'applicazione 4D, inclusi i processi ormai chiusi. Ecco una semplice procedura che riempie due array con i nomi e i corrispondenti numeri dei processi attivi: la regola che usa è che lo stato del processo è 0 se in esecuzione, positivo se in pausa o in qualche altro stato di attesa, negativo se non esiste o se ha finito. C_LONGINT($quantiProcessi_l;$quantiAttivi_l;$processo_l;$stato_l;$tempo_l) $quantiProcessi_l:=Count tasks ARRAY STRING(31;procNomi_at;$quantiProcessi_l) ARRAY INTEGER(procNum_al;$quantiProcessi_l) $quantiAttivi_l:=0 For ($processo_l;1;$quantiProcessi_l) If (Process state($processo_l)>=Executing ) $quantiAttivi_l:=$quantiAttivi_l +1 PROCESS PROPERTIES($processo_l;$procNomi_at{$quantiAttivi_l};$stato_l;$tempo_l) $procNum_al{$quantiAttivi_l}:=$processo_l End if End for ARRAY STRING(31;$procNomi_at;$quantiAttivi_l) ARRAY INTEGER($procNum_al;$quantiAttivi_l) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Trasformare un blob in un array di testo
`Nome Methodo: BLOB_to_Text_Array `Descrizione: Riempe un array di testo con i dati contenuti in un BLOB `Parametro: $0 ritorna il numero di elementi creati nell'array `Parametro: $1 è un puntatore ad una variabile di tipo BLOB `Parametro: $2 è un puntatore ad una variabile di tipo Text Array (da riempire) C_POINTER($1;$2) C_LONGINT($dimBlob_l;$dimRiga_l;$dove_l;$0) $dimRiga_l:=20000 ` dimensione di ogni blocco di testo (massimo è 32000) $dove_l:=0 $dimBlob_l:=BLOB size($1->) Repeat APPEND TO ARRAY($2->;BLOB to text($1->;Text without length ;$dove_l;$dimRiga_l)) Until ($dimBlob_l<=$dove_l) $0:=Size of array($2->) ` ritorna il numero di elementi aggiunti |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Dove mettere i certificati per SSL
Se si usa SSL con 4th Dimension o 4D Server come Web Server, i file key.pem e cert.pem dovranno essere posizionati nella cartella della struttura, allo stesso livello di questa. Se si usa 4D Client come Web Server, invece, i file devono essere posizionati nella cartella di 4D Client su Win, all'interno del package 4D Client su Mac. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Velocizzare le liste di output
4D fa passare nelle liste di output solo i campi visibili, a meno che non ci sia uno script che richieda un campo che nella prima riga non c’era: a quel punto 4D carica tutti i campi del record. Questo può essere un problema se la tabella ha molti campi o se contiene un campo con un'immagine o un blob. Soluzione: basta caricare in ogni riga, al display detail, tutti i campi che servono anche quando non li si usa. In questo modo la lista è nettamente più efficiente. Ad esempio, se nella lista c'è un codice così: :(form event=on display detail) vTaglia:=[Animale]Altezza If ([Animale]Razza=”Pachiderma”) vTaglia:=[Animale]Peso End if Basta scriverlo in questo modo :(form event=on display detail) vTaglia:=[Animale]Altezza $campoPeso:=[Animale]Peso If ([Animale]Razza=”Pachiderma”) vTaglia:=$campoPeso End if In questo modo 4d può già dalla prima riga mettere in conto quali sono i soli campi necessari a mostrare la lista. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novita' |
Il comando DISPLAY NOTIFICATION
Il comando (della 2004) DISPLAY NOTIFICATION permette, sotto Windows, di visualizzare un messaggio nella barra delle applicazioni, per intenderci accanto all'orologio! Ecco una immagine esplicativa proveniente dal sito 4D: La sintassi è: DISPLAY NOTIFICATION (title; text{; duration}) dove title è il titolo della notifica (la parte in grassetto), text il testo del messaggio e, opzionalmente, duration è la durata del messaggio. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Stile |
I nomi dei semafori
Il nome di un semaforo è una semplice stringa: per evitare di creare semafori non voluti oppure di non cancellare semafori creati è buona prassi attribuire il nome del semaforo ad una variabile e poi utilizzare quest'ultima nei comandi successivi. Ad esempio: $SemaphoreName:="IlSemaforo" If (Not(Semaphore($SemaphoreName)) ` quel che vuoi CLEAR SEMAPHORE($SemaphoreName) End if |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Modificare l'input da tastiera
Supponiamo di avere il seguente problema: voler utilizzare il tasto "Canc" del tastierino numerico come "." e non come "," per ottenere un input da tastiera del tipo "ABC.123.456" invece di "ABC,123,456". La soluzione è utilizzare i comandi che permettono di intercettare l'inserimento da tastiera da parte dell'utente: - il comando Keystroke restituisce in una stringa il carattere inserito dall'utente; - il comando FILTER KEYSTROKE prende come parametro una stringa e sostituisce il testo inserito dall'utente col primo carattere della stringa passata come parametro; - il form event On Before Keystroke che si attiva quando l'utente "sta per digitare" qualcosa sulla tastiera. Mettendo insieme tutte queste informazioni il codice diventa: Case of :(Form event=On Load ) myObject_s:="" :(Form event=On Before Keystroke) If (Position(Keystroke;",")>0) FILTER KEYSTROKE(".") End if End case Per altre possibilità per intercettare l'input dell'utente è possibile vedere anche questa faq |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
Eseguire funzioni Oracle usando comandi ODBC
Supponiamo di voler eseguire la funzione CIOCCOLATA presente in un database Oracle e di voler ricevere il valore ottenuto in una varaibile 4D. Per fare questo bastano i comandi ODBC, da usare come come segue: $sqlstmt:="SELECT CIOCCOLATA FROM DUAL" ODBC LOGIN("data";"nome";"pass") ODBC EXECUTE($sqlstmt;vlresult) ODBC LOAD RECORD `il risultato viene caricato in vlresult ODBC LOGOUT Se la funzione avesse bisogno di un parametro, potremmo anche passarlo in maniera dinamica: vlinput:=5 $sqlstmt:="SELECT CIOCCOLATA(:vlinput) FROM DUAL" ODBC LOGIN("data";"nome";"pass") ODBC SET PARAMETER(vlinput;ODBC Param In ) ODBC EXECUTE($sqlstmt;vlresult) ODBC LOAD RECORD ODBC LOGOUT |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Ricreare gli indici
Una tech tip della Knowledgebase di 4D consiglia questo metodo per effettuare una reindicizzazione completa ed accurata dei dati. Ovviamente non è un'operazione da fare tutti i giorni, ma potrebbe servire in emergenza quando ad esempio si aggiorna un database da una versione molto datata. Il procedimento suggerito è il seguente: - duplicare la struttura - aprire questa compia utilizzando una nuova base dati - eliminare manualmente tutte le relazioni - eliminare manualmente gli indici dai campi indicizzati - chiudere questa struttura aprirla nuovamente, stavolta però sui dati originali - chiudere nuovamente tutto e riaprire la struttura originale sui dati originali: gli indici verranno così completamente ricostruiti. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Una nuova immagine per lo splash screen
Con 4D 2004 è cambiato anche il modo di di associare l'immagine di partenza alla nostra struttura. Non è più necessario incollare l'immagine nell'anteprima, ma basta scegliere Design -> Toolbox -> Menus e nell'angolo in basso a destra cliccare per ottenere uno splash screen che chiede se vogliamo effettuare l'"Incolla" della clipboard: |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Chiudere il 4D server interagendo con le dialog
Nota UM: Dalla 6.8 è disponibile il comando Quit che rende obosleta questa Faq, ma il metodo utilizzato (Post Key) è interessante e utilizzabile in qualche altro caso. Ecco un metodo che permette di eseguire l'uscita da un 4D Server direttamente da 4D Client, senza dover quindi accere alla macchina dove il Server è installato: l'unico parametro utilizzato è il tempo di attesa che si vuole date al Server prima di chiudersi. C_INTEGER($1) ` C_STRING(11;$attesa_stringa) ` tempo di attesa come stringa C_INTEGER($I_Attesa;$I_ProcessNum;$i) C_BOOLEAN($B_WaitingUserDisconn) ` True = wait attende l’uscita ` ` Case of ` su 4D Client, lanciamo lo stesso metodo, ma come Stored procedure : (Application type=4D Client ) $I_Attesa:=-2 ` -2 means "Default 4D Server's value" (see below) If (Count parameters#0) $I_Attesa:=$1 End if $I_ProcessNum:=Execute on server(Current method name;32*1024;Current method name;$I_Attesa) ` ` su Server generiamo un Command o Ctrl - Q : (Application type=4D Server ) $B_WaitingUserDisconn:=False $attesa_stringa:="" Case of : (Count parameters=0) ` possibile se chiamato altrove : ($1<0) ` se negativo usa l’opzione di default $B_WaitingUserDisconn:=($1=-1) ` cioè attendo l’uscita Else $attesa_stringa:=String($1) ` per fare in modo che la cifra venga scritta con POST KEY End case ` ` Mando l’evento al processo numero 1. POST KEY(Ascii("q");Command key mask ;1) ` attendo che compaia la finestra DELAY PROCESS(Current process;60) ` scrivo il numero per l’attesa ` e se la stringa è vuota non entra For ($i;1;Length($attesa_stringa)) POST KEY(Ascii($attesa_stringa[[$i]]);0;1) DELAY PROCESS(Current process;10) End for ` passiamo dopo POST KEY(9;0;1) DELAY PROCESS(Current process;10) ` se richiesto, spuntiamo WaiUser If ($B_WaitingUserDisconn) POST KEY(US ASCII code ;0;1) DELAY PROCESS(Current process;10) End if ` Conferma ed esce POST KEY(13;0;1) End case |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Cercare una stringa all'interno di un BLOB
Ecco un metodo "brutale" per cercare una stringa all'interno di un BLOB. Il metodo riceve come parametri un puntatore al BLOB, la stringa da cercare e la posizione da cui partire con la ricerca, e ritorna la posizione, altrimenti -1. C_LONGINT($0;$3;$Start) C_POINTER($1) C_TEXT($2) C_BOOLEAN($match) $0:=-1 $Start:=$3 TEXT TO BLOB($2;$blob;Text without length ) $l:=BLOB size($1->)-1 $ll:=BLOB size($blob)-1 For ($i;$Start;$l) If ($1->{$i}=$blob{0}) $match:=True For ($ii;0;$ll) If ($1->{$i+$ii}#$blob{$ii}) $match:=False $ii:=$l End if End for End if If ($match) $0:=$i $i:=$l End if End for Fonte: 4DToday - Patrick Marty |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Conoscere lo stato della base dati da remoto
Supponiamo di voler conoscere lo stato di una base dati remota, alla quale non possiamo accedere direttamente. Il seguente metodo, usando semplicemente il comando SEND PACKET, permette di costruire un file testo separato da tabulazioni (quindi apribile ad esempio con Excel) sullo stato della base dati da qualsiasi client. Nel'esempio che riporto vogliamo conoscere lo stato dei data segment e il numero di record delle tabelle. $DocRef:=Create document("") If (ok=1) `Intestazioni $Text:="Segment Size"+Char(Tab )+"Percorso"+Char(Carriage return )+Char(Carriage return ) SEND PACKET($DocRef;$Text) `trovo i segmenti ARRAY TEXT(text_Segments;0) DATA SEGMENT LIST(text_Segments) `scrivo per ogni segmento dimensione del file e percorso For ($Segment;1;Size of array(text_Segments)) $Size:=Get document size(text_Segments{$Segment}) $Text:=String($Size;"#,###,###,##0")+Char(Tab )+text_Segments{$Segment}+Char(Carriage return ) SEND PACKET($DocRef;$Text) End for `una linea vuota $Text:=Char(Carriage return ) SEND PACKET($DocRef;$Text) `ancora intestazioni... $Text:="Table #"+Char(Tab )+"Table Name"+Char(Tab )+"Records"+Char(Tab )+"Cancellati"+Char(Tab )+"Frag%"+Char(Carriage return )+Char(Carriage return ) SEND PACKET($DocRef;$Text) `ciclo su ogni tabella For ($Table;1;Count tables) $Recs:=Records in table((Table($Table))->) $Max:=Sequence number((Table($Table))->) $Deletions:=($Max-1)-$Recs $Frag:=($Deletions/$Recs)*100 `Expressed as a percentage $Text:=String($Table)+Char(Tab )+Table name($Table)+Char(Tab )+String($Recs)+Char(Tab )+String($Deletions)+Char(Tab )+String($Frag)+Char(Carriage return ) SEND PACKET($DocRef;$Text) End for CLOSE DOCUMENT($DocRef) End if |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
Connettersi ad un database mySQL
Se avete la necessità di connettervi ad un database mySQL, esistono due plugin per 4th Dimension che potrebbero aiutarvi: - VmySQL 1.0, rilasciato da Rose development e distribuito da e-Node. - MySQL Plugin di Pluggers Software. Entrambi supportano mySQL 4.1 e funzionano a partire dalla versione 2003 del sistema di sviluppo. MySQL Plugin sotto Windows lavora anche con le versioni 6.7 e 6.8. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Trovare il valore di un attributo di un elemento XML usandone il nome
Analizzando il DOM di un XML può essere necessario ottenere l'attributo per un certo insieme di elementi: il problema è che un certo attributo può non essere presente in tutti gli elementi. Ad esempio: Se si usa il comando GET ATTRIBUTE BY NAME e l'attributo non esiste, verrà restituito un errore. Può essere allora interessante usare GET ATTRIBUTE BY INDEX per evitare di ottenere l'errore: ` Parametri ` $1 - il nodo dell'elemento per cui trovare l'attributo ` $2 - il nome dell'attributo che stiamo cercando ` $0 - il valore dell'attributo o stringa vuota se non trovato ` ---------------------------------------------------- C_TEXT($1;$2) C_TEXT($elemRef) $elemRef:=$1 C_TEXT($searchName) $searchName:=$2 C_LONGINT($i;$attribCount) C_TEXT($attribName;$attribValue) $attribCount:=Count XML attributes($elemRef) ` cerca l'attributo finché non viene trovato For ($i;1;$attribCount) GET XML ATTRIBUTE BY INDEX($elemRef;$i;$attribName;$attribValue) If ($attribName=$searchName) ` esco dal ciclo $i:=$attribCount+3 End if End for ` ritorna attribValue (che potrebbe anche essere vuoto) $0:=$attribValue |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
QPix: un'introduzione *
Ci sono fondamentalmente due possibilità per gestire le immagini in 4D. La prima è quella di usare i comandi del linguaggio standard, la seconda di usare un plug-in esterno. QPix è il plug-in della Escape per il trattamento delle immagini nei database 4th Dimension. Utilizzando la tecnologia di QuickTime, QPix permette, ad esempio: - di acquisire informazioni su un'immagine; - caricarla da un file per visualizzarla in un'area QPix oppure in una variabile o in un campo; - filtrarla e comprimerla; - crearne una thumbnail di qualità normale o alta; - acquisirla da una fonte TWAIN, creando volendo anche dei TIFF multipagina; - esportarla su file in uno dei formati supportati da QuickTime. |
1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Teoria della normalizzazione: Forma Normale di Boyce-Codd [BCNF]
La Forma Normale di Boyce-Codd (Boyce-Codd Normal Form, BCNF) è sicuramente la più forte fra le forme normali, anche per questo quindi molto difficilmente realizzabile. Infatti, in maniera più limitante rispetto alla 3NF: Uno schema R è in BCNF se ogni volta che in R vale X -> A e A non è X, allora X è una superchiave per lo schema (cioè è una chiave o contiene una chiave). Questa condizione è realmente molto complessa da ottenere, ma non impossibile. E’ infatti possibile scomporre uno schema relazionale in uno in BCNF, anche se non è garantito che conservi le dipendenze funzionali di partenza. Ad esempio, lo schema Corso (C), Insegnante (T), Ora (H), Aula (R), Studente (S), e Voto (G), che indichiamo con CTHRSG, dove C -> T ogni corso ha un insegnante HR -> C in ogni istante un solo corso in un’aula HT -> R un insegnante non gode del dono dell’ubiquità CS -> G uno studente ha un solo voto per ogni corso HS -> R anche gli studenti non godono del dono dell’ubiquità Si può applicare un algoritmo che scompone il seguente schema in uno in BCNF, formato da HRS, CT, CSG, CHS. Consulta da questo link l’indice delle faq sulla normalizzazione |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Teoria della normalizzazione: Terza Forma Normale [3NF]
La Terza Forma Normale (3NF) aggiunge un ulteriore livello di controllo sull’unione delle tabelle. Una definizione l’abbiamo già vista in una delle FAQ precedenti: Una tabella deve avere un campo che identifica in maniera univoca ognuno dei suoi record, e ogni campo deve descrivere il soggetto che la tabella rappresenta (Michael J. Hernandez, Database Design for Mere Mortals). Equivalentemente: Per verificare se una tabella in 2NF è anche in 3NF basta chiederci: “Esiste un campo non chiave che dipenda funzionalmente da un altro campo non chiave?”. In maniera più formale: Uno schema R è in 3NF se ogni volta che in R vale X -> A e A non è X (dove X è un insieme di campi e A è un campo specifico), allora o X è una superchiave per lo schema oppure A è primario (cioè è una delle chiavi, visto che in uno schema possono eserci più chiavi). L’esempio visto per i CAP esplica perfettamente questi concetti. Altro esempio “postale” è quello classico della tabella contenente Citta (che indicheremo con C), Via (S) e CAP (Z), dove valgono: CS -> Z Z -> C Questo schema è in Terza Forma Normale. E’ sempre possibile modificare uno schema in maniera tale che diventi in 3NF conservando le dipendenze funzionali di partenza. Consulta da questo link l’indice delle faq sulla normalizzazione |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Teoria della normalizzazione: Seconda Forma Normale [2NF]
La Seconda Forma Normale aiuta a identificare i casi in cui due tabelle distinte siano state erroneamente riunite in un’unica tabella. Si dice infatti che: Una relazione è in Seconda Forma Normale (2NF) se e solo se è in 1NF e ogni attributo che non sia chiave è funzionalmente dipendente dalla chiave primaria. In altre parole, una tabella è in 2NF se non ci sono gruppi ripetuti e ogni campo non facente parte della chiave è in dipendenza funzionale rispetto alla chiave stessa. Una tabella che ha una sola chiave ed è in 1NF è già anche in 2NF. Consulta da questo link l’indice delle faq sulla normalizzazione |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Teoria della normalizzazione: Prima Forma Normale [1NF]
I principi della normalizzazione sono descritti in una serie di definizioni dette “Forme Normali”. La Prima Forma Normale (1NF) è la più semplice da soddisfare, la seconda è più complessa, e così via fino ad arrivare alla quinta o sesta forma normale. La Prima Forma Normale dice che: Una tabella è in Prima Forma Normale se non contiene gruppi ripetuti. Cos’è un gruppo e cosa può esserci di sbagliato? Quando si ha più di un campo che memorizza lo stesso tipo di informazione in una singola tabella, si ha un gruppo ripetuto. I gruppi ripetuti sono inevitabili quando il sistema di memorizzazione è un foglio di calcolo (che è una forma di database “piatto”), ma sono impensabili in un database relazionale. Ecco un esempio: [Clienti] ID_Cliente Nome Telefono1 Telefono2 Telefono3 Dov’è l’errore? Ecco, cosa succede quando ci serve un quarto numero di telefono? Siamo costretti ad aggiungere un campo, modificare tutti i form e riscrivere i metodi. Diventa problematico creare query a campi incrociati tra il cliente e i suoi contatti telefonici. Tutte le difficoltà descritte vengono risolte muovendo i telefoni in una tabella a parte: [Clienti] ID_Cliente Nome [Telefoni] ID_Cliente (che permette la relazione con Clienti) ID_Contatto (la chiave) Telefono Consulta da questo link l’indice delle faq sulla normalizzazione |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Totali nelle liste di Output
Per mostrare una somma alla fine di una selezione in un normale layout mostrato con una Display selection non basta scrivere :(Form event= On Header) v_TotRow:=Sum([Fatture]Euro_tot) ma se la display selection è suscettibile di cambiamenti a causa di query, use set ecc bisogna scrivere nel metodo della Form :(Form event= On Header) v_TotRow:=Sum([Fatture]Euro_tot) Set Visible(v_TotRow;True) così il valore si aggiorna ad ogni cambio di record visibili. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Teoria della normalizzazione: ridondanze e storicizzazione dei dati
La necessità di storicizzare le informazioni, molto spesso si scontra, apparentemente, con la necessità di normalizzare un database. Illustro il caso con due tabelle perfettamente normalizzate: [Cliente] Codice RagioneSociale ... [Fattura] Numero Data CodiceCliente ... Bene, cosa succede se il cliente in una certa data comunica una variazione di ragione sociale? Tutte le fatture antecedenti alla data di variazione non potrebbero più essere ristampate correttamente. Per prevenire un problema di questo tipo, normalmente si ricorre all'aggiunta della ragione sociale del cliente anche sulla tabella [Fatture]: [Fattura] Numero Data CodiceCliente RagioneSocialeCliente ... In questo caso la ragione sociale memorizzata sulla fattura non è un dato ridondante ma un dato storico (storicizzato). L'aspetto interessante, però, è che esiste un'altra via per risolvere il problema, anche se molto più complessa e dispendiosa sotto tutti i punti di vista. Immaginiamo di voler gestire, per il cliente, anche il cambio di indirizzo di fatturazione (indirizzo, cap, città, provincia...). Seguendo l'esempio di cui sopra, dovremmo aggiungere anche questi campi alla fattura, oppure, e qui sta l'alternativa, possiamo creare un secondo record cliente, accessibile con data: [Cliente] Codice DataInizioValidità RagioneSociale .... Nella tabella [Cliente] è come se il cliente venisse "fotografato" ad una certa data. Il campo DataInizioValidià viene a far parte, in un certo modo della chiave primaria. Il cliente continua ad avere un codice solo ma i record sono multipli in base alla data di ricerca (esempio la data della fattura) (primo record con data validità inferiore a quella della fattura...) Volendo si può sofisticare ancora il metodo, separando i dati storicizzabili in una tabella separata: [Cliente] Codice DatoNonModificabile .... [ClienteDatiStorici] Cliente DataInizioValidità RagioneSociale IndirizzoFatturazione .... Questa tecnica non permette di creare delle relazioni efficienti in 4D perché si otterrebbero delle relazioni n-n. L'accesso al record deve avvenire con una query, un ordinamento decrescente sulla data inizio validità e una first record. Inoltre il presupposto è che tutte le tabelle interessate da questa logica abbiano una data di riferimento da utilizzare per gli accessi (nell'esempio la data della fattura per accedere al cliente). Ripeto, il metodo è molto complesso, ma in alcune realtà è applicabile. Consulta da questo link l’indice delle faq sulla normalizzazione |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Teoria della normalizzazione: denormalizzare
Abbiamo visto ed elencato tutti i vantaggi legati alla normalizzazione. Allora perché in molti casi si ricorre volontariamente alla denormalizzazione, cioè alla deliberata violazione dei criteri di normalizzazione? Solitamente questo dipende dall’analisi del caso specifico. Facciamo un esempio banale. Perché memorizziamo di ogni fattura il totale quando abbiamo già calcolato Imponibile ed IVA? Anzi di più, perché memorizzare Imponibile, IVA e Totale della fattura, se possiamo ottenere questi dati in ogni momento a partire dalle righe della fattura? Questi esempi retorici fanno capire come nella realtà l’uso dei campi calcolati o delle tabelle di generazione delle statistiche o dei campi costruiti “ad hoc” per effettuare degli ordinamenti veloci (ordinare su un solo campo “riunito” può essere anche 40 volte più veloce dell’effettuare lo stesso ordinamento su due campi separati), malgrado possano essere considerati violazioni alle forme normali in realtà risultano necessari per migliorare le prestazioni sulle operazioni più complesse che un sistema di database deve compiere. Consulta da questo link l’indice delle faq sulla normalizzazione |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Teoria della normalizzazione: pro e contro
Ci si potrebbe chiedere: ma quali sono alla fine i vantaggi concreti nell’applicare un discorso così teorico? Eccoli elencati. - Struttura del database assai più efficiente, flessibile e facile da mantenere. - Migliore comprensione dei dati. - Minore quantità di errori in itinere. - Avvicinamento al mondo reale. - Eliminazione dei dati duplicati - Creazione di tabelle distinte solo quando realmente necessario Certo, un contro c’è e non è da poco: l’uso della normalizzazione impone che la costruzione del database deve avvenire necessariamente DOPO essere venuti a conoscenza di tutte le esigenze dell’utente Comunque i pro sembrano essere più dei contro... Consulta da questo link l’indice delle faq sulla normalizzazione |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Teoria della normalizzazione: progettare o implementare?
“Progettare un database” o “implementare un database” sono due attività completamente differenti. Quando progettiamo una struttura, ciò viene fatto in maniera assolutamente indipendente dallo specifico tool di sviluppo che verrà poi usato per l’implementazione: questa, infatti, verrà fatta in un secondo momento. Solo dopo aver disegnato la struttura in maniera astratta, passeremo all’implementazione vera e propria nel sistema preferito, 4D nel nostro caso. Troppo spesso avviene che soprattutto i programmatori di database alle prime armi uniscano in un unico processo progettazione ed implementazione: ciò è anche dovuto al fatto che 4th Dimension offre una tentazione forte verso questo tipo di pratica, data la facilità di “disegnazione” (mi venga concesso il neologismo) dello Structure Editor. Ma avere a priori le idee chiare su “cosa” disegnare, permette di realizzare poi tutto in minor tempo e con ridottissimi margini di errore. Consulta da questo link l’indice delle faq sulla normalizzazione |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Teoria della normalizzazione: l'abbiamo sempre usata
Il solo termine “teoria” potrebbe far pensare a qualcosa di estremamente complesso e teorico: niente di più sbagliato: la teoria della normalizzazione si potrebbe sintetizzare nella seguente affermazione: Una tabella deve avere un campo che identifica in maniera univoca ognuno dei suoi record, e ogni campo deve descrivere il soggetto che la tabella rappresenta (Michael J. Hernandez, Database Design for Mere Mortals). Questa affermazione è interessante: ogni record deve essere identificabile in modo unico e ogni campo deve riguardare l’oggetto in questione. In maniera più semplicistica possiamo dire allora che: La normalizzazione ha come obiettivo l’eliminazione dei campi ridondanti e l’unificazione di tabelle. E’ pressoché certo che un principio simile lo abbiamo bene o male, e più o meno coscientemente, già tenuto in considerazione sviluppando i nostri database! Consulta da questo link l’indice delle faq sulla normalizzazione |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Teoria della normalizzazione
Analizzando le statistiche di accesso a Sviluppo4D mi sono accorto con sorpresa, e ovviamente con piacere, del fatto che molti dei nuovi visitatori del sito sono sviluppatori (quanto meno probabilmente) in cerca di informazioni e notizie relative a sistemi di sviluppo di database “altri” rispetto a 4th Dimension: oltre ai già ampiamente trattati Access e FileMaker, anche ricerche riguardanti Macromedia Cold Fusion, Oracle, Visual Basic, Code Warrior, AS 400, Delphi portano visitatori su questo sito. Visto dunque che 4D può diventare fonte di conoscenza “open source” anche per altre piattaforme, ho pensato di dedicare alcune faq ad un argomento che prescinde realmente dal tipo di sistema di sviluppo per database utilizzato dal programmatore-visitatore: la teoria della normalizzazione. Tanto per dare un’idea di ciò che cercherò di sviluppare più ampiamente possibile nelle varie faq sull’argomento, normalizzazione è un processo, in parole molto povere, che determina quali campi debbano appartenere ad una determinata tabella in un database relazionale. Sono poche, semplici ed intuitive regole che portano vari benefici: - Eliminazione delle ridondanze (cioè la duplicazione dei dati); - Creazione di modelli “chiusi” (per la teoria degli insiemi) di entità del mondo reale, con i loro processi e le loro relazioni; - Strutturazione dei dati assai flessibile. La normalizzazione assicura lo sfruttamento di tutti i benefici dati dall’uso di un sistema di database relazionale: il tempo “sprecato” in questo processo viene ripagato da sé immediatamente. Come fonte per i vari argomenti trattati userò un brillante articolo di David Adams e Dan Beckett (e le relative fonti) del 1997, ricavato da Programming 4th Dimension: The Ultimate Guide degli stessi autori, oltre a “Basi di dati e basi di Conoscenza” di Jeffrey D. Ullman Consulta da questo link l’indice delle faq sulla normalizzazione |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
Un esempio di uso di 4D Open
Per vedere in azione alcuni comandi di 4D Open, il plug-in che permette a due programmi 4D (di cui almeno uno 4D Server) di comunicare, facciamo il seguente esempio. Supponiamo di conoscere il nome della tabella in cui cercare un certo campo ma di non conoscere il nome del campo stesso. L'unica cosa che sappiamo di questo campo è che è l'unico campo boolean della tabella. Vediamo di ottenere la posizione di questo campo nella tabella. Supponimo che la tabella sia la numero 1. Avremo: C_LONGINT($File;$ErrCode;$Field) ARRAY LONGINT(aTypes;0) `tipi ARRAY LONGINT(aLength;0) `… lunghezza (degli alfanumerici) ARRAY LONGINT(aIndexes;0) `indicizzato? ARRAY LONGINT(aInvisible;0) `invisibile? ARRAY STRING(15;aNames;0) `nomi $File:=1 `tabella numero 1 $ErrCode:=OP Get field properties (vl_ConnectID;$File;$Invisible;aNames;aTypes;aLength;aIndexes;aInvisible) For ($i;1;Size of Array(aTypes)) If (aTypes{$i}=Is Boolean) $Field:=$i 'questo è il numero End if End for Si noti che l'array aTypes è stato dichiarato longint, ma poteva essere string text real o integer. Il comando ritorna il valore corretto in base al tipo di array inserito. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Ricerca di elementi negli array bidimensionali
Come ben sappiamo, il comando Find in array ritorna il primo elemento di un array che corrisponde a un certo valore. Per gli array bidimensionali il processo è lievemente differente. Supponiamo di avere: Array Text(Myarray;2;2) Myarray{1}{1}:="Cinema" Myarray{1}{2}:="Teatro" Myarray{2}{1}:="Film" Myarray{2}{2}:="Commedia" Se cerchiamo la parola Cinema 4D ci restituisce: $find:=Find in array(Myarray{1};"Cinema") $find1:=Find in array(Myarray{2};"Cinema") $find sarà 1 $find1 sarà -1 Per effettuare una ricerca diretta su tutto l'array allora si scriverà: $arrSize:=Size of array(Myarray) For ($i;1;$arrSize) $find:=Find in array(Myarray{$i};"Cinema") If ($find>0) `qualsiasi cosa End if End for |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Controllo delle strutture bloccate usando le password
4th Dimension permette di usare un database da CD: in questo caso, giustamente, la struttura risulta bloccata. In generale però è bene controllare se la struttura è bloccata o meno: se via 4D Client modifico una struttura bloccata, le modifiche saranno scritte in cache e uscendo da 4D Server andranno perse: il caso tipico è la copia della struttura da CD a disco fisso (in ambiente Windows). Un modo per controllare se una strutura è bloccata può essere quello di modificare le password della struttura via codice: per eseguire questa operazione la struttura non deve risultare bloccata, altrimenti viene generato un errore -9937. Nel database method "On Startup" verrà lanciato questo processo: $ref:=New process("MyLockProc";32*1024) Il metodo lanciato avrà questa forma: ON ERR CALL("ControlloErrori") DELAY PROCESS(Current Process;60) GET USER PROPERTIES(2;name;startup;pass;uses;dat) $error:=Set user properties(2;name;startup;pass;uses;dat) ON ERR CALL("") Nella procedura ControlloErrori posso visualizzare messaggi di errore. IMPORTANTE: il metodo di controllo deve partire su un nuovo processo e il DELAY PROCESS iniziale deve essere di almeno 60 tick. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
Creare tabelle e campi da programma
Nella versione 2004.1 di 4D è disponibile con 4D Pack il comando: AP Add table and fields (tableName; fieldNamesArray; fieldTypesArray; fieldLengthsArray{; listFormTemplate{; detailFormTemplate}}) Il comando è stato fondamentalmente creato per creare "al volo" le strutture. Prende come parametri il nome della tabella (fino a 31 caratteri), un array con i nomi dei campi, un array con i tipi, un array con la lunghezza relativa per i campi alfanumerici, e, opzionalmente, il nome dei template da usare per i layout di output e di input. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Ricerca su tutti i campi testuali di una Tabella
` Ricerca di una stringa su tutti i campi alfanumerici e testo di una tabella ` _________________________________________________________________ ` $1 = Puntatore alla tabella ` _________________________________________________________________ C_POINTER($1) C_STRING(80;$Alfa) C_POINTER($PtrField;$PtrTable) C_INTEGER($FieldNum;$TableNum;$NumeroMinimoCaratteri) $PtrTable:=$1 $NumeroMinimoCaratteri:=3 $Alfa:=Request("Cerca...: (min. "+String($NumeroMinimoCaratteri)+" car.)") If ((ok=1) & ($Alfa#"")) If (Length($Alfa)>=$NumeroMinimoCaratteri) $TableNum:=Table($PtrTable) $FieldNum:=Count fields($PtrTable) For ($i;1;$FieldNum) $PtrField:=Field($TableNum;$i) If ((Type($PtrField->)=Is Alpha Field ) | (Type($PtrField->)=Is Text )) QUERY($PtrTable->;$PtrField->=$Alfa;*) $i:=$FieldNum+100 End if End for ` Verifica che abbia eseguito la query precedente If ($i>($FieldNum+10)) For ($i;1;$FieldNum) $PtrField:=Field($TableNum;$i) If ((Type($PtrField->)=Is Alpha Field ) | (Type($PtrField->)=Is Text )) QUERY($PtrTable->; | $PtrField->="@"+$Alfa+"@";*) End if End for QUERY($PtrTable->) Else Alert ("Assenza campi alfanumerici in tabella") End if Else Alert ("Devi introdurre almeno "+String($NumeroMinimoCaratteri)+" caratteri") End if End if ` _________________________________________________________________ |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
Controllare tutti i plugin caricati
Con la versione 2004 di 4D è possibile conoscere la lista di tutti i plug-in caricati utilizzando il comando GET PLUGIN LIST: un ottimo sistema per controllare allo startup del database se tutti i componenti necessari al programma sono presenti. GET PLUGIN LIST elenca tutti i plugin, sia quelli integrati (tipo 4D Chart) che quelli di terze parti. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Read only automatico
4th Dimension mette in automatico una tabella in modalità Read-only quando vengono usati comandi che non richiedono accesso in scrittura alla tabella stessa. Questi comandi sono: DISPLAY SELECTION DISTINCT VALUES EXPORT DIF EXPORT SYLK EXPORT TEXT GRAPH TABLE PRINT SELECTION PRINT LABEL QR REPORT SELECTION TO ARRAY SELECTION RANGE TO ARRAY È possibile controllare lo stato in lettura/scrittura di una tabella usando il comando Read only state |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Assegnare un data file ad una struttura specifica con WEDD
Capita spesso di sviluppare più applicazioni che girano sulla stessa macchina. Ovviamente può provocare una quantità di danni incredibile l'apertura di un file dati con una struttura diversa da quella prevista! 4D (fino alla 2003) permette di associare in maniera esclusiva un file dati e una struttura attraverso il Customizer Plus. Questa applicazione permette infatti di associare una risorsa WEDD sia alla struttura che al file dati, in maniera da limitare l'uso di un certo data file alla sola struttura associata. Infatti, solo la struttura con una medesima risorsa WEDD potrà aprire quel file dati, prevenendo così i danni accidentali provocati da aperture di file dati errate. Ecco come fare: 1) aprire la struttura col Customizer Plus; 2) doppio clic sull'ucona WEDD; 3) nella dialog, inserire un nome per il parametro WEDD; 4) chiudere la dialog, chiudere il file e, alla richiesta, salvare le modifiche; 5) ripetere la stessa operazione sul file dati, avendo cura di inserire lo stesso valore WEDD della struttura. A questo punto, quando verranno aperti un file dati e una struttura con WEDD differenti, verrà segnalato l'errore: "The structure and the data files do not correspond to each other. The data file cannot be opened with this structure". Per eliminare l'impostazione di una risorsa WEDD basta aprire la base dati o la struttura con 4D Customizer Plus e fare doppio clic sull'icona WEDD premendo sulla tastiera Alt (Option su Mac). Con 4D 2004, WEDD invece può essere configurato direttamente dalle preferenze del database (percorso da passare a OPEN 4D PREFERENCES è "/Database/Data Management/WEDD") |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Controllare lo stato di un processo senza process ID
Il comando Process state ritorna lo stato di un processo il cui numero viene passato come parametro. In realtà è possibile controllare lo stato di un processo anche quando non se ne conosca il numero, ma solo il nome. Il seguente frammento di codice lo dimostra: C_LONGINT($0) C_STRING(255;$1) $0:=Process state(Process number($1)) Passando come parametro il nome del processo, il comando Process number ne ritorna il numero. Questo numero viene così poi passato a Process state. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Istanze multiple di 4D WebSTAR V
Ci sono te modi per lanciare WebSTAR V: 1) lanciare l'applicazione manualmente; 2) inserirla nelle applicazioni di avvio per l'utente; 3) durante l'installazione, scegliere l'opzione di installazione di WebSTAR come "Startup Item". Questi ultimi due casi sono notevolmente differenti: nel caso 2, infatti, WebSTAR viene lanciato quando l'utente relativo accede ala macchina, mentre nel caso 3 WebSTAR viene lanciato all'avvio per qualsiasi utente, per di più in backgroud (il che significa che la finestra di WebSTAR Launcher risulta invisibile). Potrebbe causare dunque problemi la possibilità di eseguire più volte WebSTAR, "abilitando" sia il caso 2 che il caso 3. Un modo per vedere se ci sono più WebSTAR lanciati può essere quella di lanciare il Visualizzatore di Processi di MacOSX e controllare i processi "WS" in esecuzione: l'unico processo che dovrebbe essere in esecuzione più volte è WSAdminServer, ma comunque non più di due istanze. Nel caso di duplicazione, rimuovere WebSTAR o dagli elementi di login dell'utente o dal lancio come servizio utilizzando l'Installer. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
Backup di 4d Monoutenza *
4dBackup è un plugin forinito con 4d che di solito si usa in versione client-server. E' possibile però usarlo anche in monoutenza, ma o lo si esegue in ambiente User o occorre comandarlo da procedura. Ecco un esempio di utilizzo: C_INTEGER ($Progress_i;$Fill_i) If (BK Begin full backup = 0) If (BK Start copy = 0) Repeat BK GET PROGRESS ($Progress_i; $Fill_i) MESSAGE ("Backup in corso: " + String ($Progress_i) + "%") Until (BK Get state # 4) End if BK END BACKUP End if |
1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Le variabili dei componenti
Quando si scrive un componente è importante ricordarsi che verrà utilizzato all'interno di una struttura con altri metodi e variabili. Quindi bisogna seguire queste importanti regole : 1) il nome deve essere unico: in genere puoi aggiungere un prefisso usato anche per dare il nome ai metodi, ad esempio "ESE_Dup_" per un componente della società Esempio per contare i duplicati. 2) usa sempre un metodo Privato che inizi con il prefisso "Compiler_" per fare in modo che chi usa il componente non abbia problemi a compilare correttamente la propria struttura, quindi "Compiler_ESE_Dup_VariabiliProcesso" 3) le variabili non devono essere utilizzate al di fuori del componente, per cui è necessario creare dei metodi per leggere/scrivere il valore (chiamati "accessor method"). Ad esempio, se nel componente ci fosse la variabile <>ESE_QuantiDoppi_i si potrebbero scrivere due metodi ESE_Dup_Leggi_QuantiDoppi e ESE_Dup_Scrivi_QuantiDoppi. Oppure un metodo unico, a cui puoi passare un parametro se vuoi impostare la variabile, comunque ritorna sempre il valore della stessa. ` Metodo ESE_Dup_QuantiDoppi(Numero) --> Numero ` Accesso: Protetto C_LONGINT($0;$1) If (count parameters>=1) If ($1>0) <>ESE_QuantiDoppi_i:=$1 Else ALERT("Il valore passato a "+Current method name+" deve essere positivo") End if End if $0:=<>ESE_QuantiDoppi_i Estratto dalla sessione "Write Better Code with 4D Components" di Dave Batton presentata alla "4D Summit Conferences 2004" |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Uscita corretta da 4D Server con Stored procedure
Una stored procedure è un processo lanciato sulla macchina server. L'utilizzo di questa tecnica è molto spesso indicato perché limita la comunicazione via network fra client e server. Una stored procedure può essere lanciata: - da 4D Server, usando il comando New process; - da 4D Client, usando il comando Execute on server. Vediamo di usarla per eseguire una corretta uscita da 4D Server. Nel database method "On Server Startup" inseriamo questo codice: <>StopServer:=False <>StoredProc:=New process("Server_Method";32*1024;"StoredProc (server)") Il metodo "Server_Method" non fa altro che un ciclo molto semplice, che dura finché <>StopServer non diventa "Vero" Repeat $currentTime:=Current time DELAY PROCESS(Current process;60) Until (<>StopServer=True) Ora, esistono due modi, come ben sappiamo di uscire da 4D Server: - "Disconnect from server in nn min." è sicuramente il più pericoloso: trascorso il numero di minuti TUTTI I PROCESSI VERRANNO CHIUSI, con grosso rischio, ovviamente di integrità del database; - "Wait for all Users to disconnect" attende che tutti i client vengano chiusi. Se viene usato questo secondo sistema di chiusura del server, è possibile usare la variabile <>StopServer impostata precedentemente per controllare nelle varie stored procedures se il server sta o meno per chiudersi. Per fare in modo che 4D Server attenda la conclusione dei vari processi si può usare questo codice nel database method "On Server Shutdown" (dobbiamo controllare tutti i processi possibili del server, quindi anche Web): <>StopServer:=True `inizializzo $Index:=1 $nbUsersProcs:=5 $serverReady:=11 Repeat ` Quanti processi vivi? $nbProcess:=Count user processes ` Condizione dei processi kernel $interface:=ProcessExist (204;1) ` process 'User interface' $client:=ProcessExist (204;2) ` process 'Client manager' $cache:=ProcessExist (204;3) ` process 'Cache manager' $web:=ProcessExist (401;1) ` process 'Web server' $index:=ProcessExist (204;4) ` process 'Index manager' ` Una variabile che condensa gli stati $serverReady:=$interface+$client+$cache+$web+$index ` Delay per 5 secondi DELAY PROCESS(Current process;300) Until (<>StopServer=True) & ($index=0) & ($nbProcess<5) & ($serverReady<11) Il metodo "ProcessExist" controlla lo stato dei processi kernel accedendo alle risorse: ` $1 => STR# number ` $2 => STR# item number ` $0 <= number $0:=Process number(Get indexed string($1;$2)) Così, se $index è uguale a zero, significa che nessun processo di indicizzazione è in corso e il server può uscire. Un altro approccio potrebbe essere quello di far lanciare un processo al client che controlli lo stato di <>StopServer, in modo che possa completare tutti i suoi processi prima che venga eseguito il comando "Quit 4D" |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Numeri Integer e overflow automatico
Il tipo Integer in 4D può avere valori fra -32.768 e 32.767. Se viene inserito un valore maggiore o minore di questi limiti, il numero sarà modificato automaticamente per rientrarci: questa operazione si chiama "overflow". Per esempio se aggiungi 1 ad un intero 32.767 esso diventerà -32768. Così se togli 1 da -32.768 otterrai 32.767. Però bisogna anche sapere che in 4D (dalla versione 3 in poi) in realtà sono interi veri i campi e gli array. In realtà le varibili sono dei Long integer (che hanno un limite molto più alto). Per verificare la cosa, prova ad eseguire questo codice controllando nel debugger i valori ottenuti: CREATE RECORD([Tabella]) [Tabella]Intero:=32766 [Tabella]Intero:=[Tabella]Intero+1 ` 32,767 = normale [Tabella]Intero:=[Tabella]Intero+1 ` -32,768 = overflow [Tabella]Intero:=[Tabella]Intero-1 ` 32,767 = overflow ancora! ARRAY INTEGER(arrayInteger;1) arrayInteger{1}:=32766 arrayInteger{1}:=arrayInteger{1}+1 ` 32,767 = normale arrayInteger{1}:=arrayInteger{1}+1 ` -32,768 = overflow C_INTEGER(variabile) variabile:=32766 variabile:=variabile+1 ` 32,767 = normale variabile:=variabile+1 ` 32,768 = non c'è l'overflow!!!! If (Type(variabile)=Is LongInt ) `infatti se controllo... è un Long integer ALERT("variabile è di tipo long integer.") End if |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
La precedenza nelle espressioni aritmetiche
Il sistema secondo cui vengono valutate delle espressioni algebriche viene chiamato precedenza. 4D valuta le espressioni non secondo la normale precedenza matematica (potenza, moltiplicazione-divisione, somma-sottrazione), ma molto più semplicemente leggendo da sinistra a destra. Ecco perché: 3 + 4 * 5 restituisce come risultato 35, mentre secondo la notazione comune il risultato dovrebbe essere 23. Quindi, per valutare l’espressione secondo la notazione classica è neccessario utilizzare la parentesizzazione: 3 + ( 4 * 5) con cui 4d restituisce appunto 23. Un sistema di valutazione di questo genere può sembrare assai incomprensibile, ma d’altro canto esistono molti modelli matematici che preferiscono "letture" che non usino le precedenze o che permettano valutazioni dirette "sinistra - destra". Il caso più famoso è probabilmente quello della forma postfissa (detta anche polacca, dalla nazionalità di Lucasievic, che l'ha formalizzata), in cui gli operatori non si trovano in mezzo (come nella notazione infissa, che è quella da noi comunemente utilizzata) ma dopo gli operandi (4*3 diventa 4 3 *). Tale forma ha il vantaggio di non aver bisogno di parentesizzazione per specificare la precedenza fra gli operatori. Fonte: Alfredo Ferro - Teoria ed Applicazione delle Macchine Calcolatrici - Università degli Studi di Catania, 1991-2 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Posso convertire un real in longint?
Nell uso di un interprete, due aspetti da separare sono gli errori dovuti a una cattiva "interpretazione" di una istruzione e quelli dovuti ad un modo sbagliato di usare l'interprete stesso (errori di programmazione). Andrew S. Tanenbaum ne "I moderni sistemi operativi" afferma che "...in molti casi la conversione tra i tipi è necessaria o utile...": tutto ciò che il computer usa è formato da una serie di 0 e 1, basta semplicemente "tradurre" l'insieme di bit da String a Num o da real a longint, nei modi previsti dall'interprete. Il manuale del Language di 4th Dimension afferma che: “You can assign any Number data type to another; 4D does the conversion, truncating or rounding if necessary”. Ciò significa in buona sostanza che convertire un numero con virgola in intero (il cosiddetto casting delle variabili) è ammissibile, solo che 4D non fornisce garanzie sul tipo di metodo che verrà utilizzato per effettuare tale conversione: potrebbe essere indifferentemente usato il troncamento come l’arrotondamento. Fonti: A.S. Tanenbaum: Modern Operating Systems, 1994 Domenico Cantone: Linguaggi Formali e Compilatori, Università degli Studi di Catania, 1996 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
Confrontare due reali: il comando SET REAL COMPARISON LEVEL
Il comando SET REAL COMPARISON LEVEL a cui viene passato come parametro un numero, indica il valore epsilon secondo cui valutare l'uguaglianza fra due numeri reali. Come visto nella faq sull'arrotondamento dei numeri reali, il computer effettua delle approssimazioni per calcolare i numeri reali: quindi anche nel calcolare l'uguaglianza fra due numeri 4th Dimension deve tenere in considerazione questa approssimazione, controllando se se la differenza fra due numeri eccede o meno un certo valore. Questo valore è dato proprio dall'epsilon passato come parametro a SET REAL COMPARISON LEVEL. Vediamo un esempio. Dati due numeri reali a e b, se Abs(a-b) è maggiore di epsilon i numeri verranno considerati diversi, altrimenti uguali. Di default, 4D usa come epsilon 10 elevato a -6 (10^-6). Ciò significa che: • 0,00001=0,00002 restituisce False perché la loro differenza (0,00001) è maggiore di 10^-6. • 0,000001=0,000002 ritorna True perché la loro differenza (0,000001) non è maggiore di 10^-6. • 0,000001=0,000003 restituisce False perché la loro differenza (0,000002) è maggiore di 10^-6. Bisogna dunque usare SET REAL COMPARISON LEVEL se risulta necessario confrontare valori più bassi di 10^-6. Si noti inoltre che se si deve eseguire una query o un ordinamento su un campo contenente valori più bassi di 10^-6, il comando SET REAL COMPARISON LEVEL deve essere usato prima della costruzione dell'indice. Il comando non ha alcun effetto sul calcolo o la visualizzazione dei numeri reali. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Gli arrotondamenti dei numeri reali in 4D
L’argomento dell’arrotondamento dei numeri reali è da sempre uno dei più dibattuti fra gli sviluppatori 4D. Molti considerano questo aspetto come un baco del sistema di sviluppo, altri semplicemente un problema con cui convivere serenamente avendo solo qualche accortezza. Vediamo il problema. A scuola ci insegnano che il risultato di 1/3 è 0,3333….. con 3 periodico. Ma concettualemte sappiamo anche che tre volte un terzo fa uno. Il problema è che il computer non conosce questo problema e ritiene corretto calcolare esattamente queste espressioni. Ad esempio, a seconda del computer che usiamo, vedremo che 1/3 è calcolato con un numero ben preciso di “3” dopo la virgola: questo numero è chiamato “precisione della macchina”. Su Mac 68K, la precisione è 19; ciò significa che 1/3 è calcolato con 19 cifre significative. Su Win e su Power Mac, questo numero è 15; così 1/3 è visualizzato con 15 cifre significative. Se visualizziamo l'espressione 1/3 nella finestra del Debugger di 4th Dimension, otterremo 0,3333333333333333333 su un 68K e qualcosa come 0,3333333333333333148 su Windows o su Power Macintosh. Si noti che le ultime tre cifre sono differenti perché la precisione su Windows e su Power Macintosh è minore rispetto al 68K. Tuttavia, se si visualizza l'espressione (1/3)*3, il risultato è 1 su entrambe le macchine. Perchè il valore 1/3 sembra differente? Nei Macintosh 68K, il sistema operativo usa 10 byte (80 bit) per memorizzare numeri reali, mentre Windows Power Macintosh 8 byte (64 bit). Ecco perchè i numeri reali hanno fino a 19 cifre significative su 68K e fino a 15 cifre significative Windows su Power Macintosh. Allora perchè l'espressione (1/3)*3 restituisce 1 su tutte e tre le macchine? Un computer può fare soltanto i calcoli approssimati. Di conseguenza, mentre confronta o calcola numeri, un computer non tratta i numeri reali come oggetti matematici ma come valori approssimati. Nel nostro esempio, 0,3333... moltiplicato per 3 dà 0,9999...; la differenza fra 0,9999... e 1 è così piccola che la macchina considera il risultato uguale a 1 e conseguentemente restituisce 1. Per i particolari riguardanti il "quanto piccola può essere la differenza fra 0,9999... e 1" vi rimandiamo ad una FAQ sul comando SET REAL COMPARISON LEVEL. Bisogna dunque distinguere due cose sui numeri reali in 4D: Come vengono calcolati e confrontati Come vengono visualizzati sullo schermo o sulla stampante Originariamente, 4D gestiva i numeri reali usando il tipo di memorizzazione a 10-byte. Per compatibilità, le versioni Power Macintosh e Windows di 4D continuano ancora a usare il tipo di dati a 10-byte. Poiché l'aritmetica in virgola mobile è effettuata su Windows o su Power Macintosh usando 8 byte, 4D converte i valori da 10 byte a 8 byte e viceversa. Di conseguenza, se carico un record che contiene valori reali (salvati su 68K Macintosh) su Windows o su Power Macintosh, è possibile perdere una certa precisione (19 - 15 cifre significative). Tuttavia, nel caso diametralmente opposto, su un 68K non ci sarà perdita di precisione. Usando il Customizer Plus, si può regolare il numero di cifre da non considerare quando vengono mostrati dei numeri reali su 68K o su Power Macintosh e Windows. Le impostazioni di default sono: nessuna cifra su 68K e cinque cifre su Power Macintosh e Windows. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
Stampare da codice un'area 4D Write [2]
Quando si vuole stampare un'area 4D Write si può usare il comando WR PRINT. Tale comando però stampa l'area solo una volta. Per stampare un'area un numero di volte pari al numero di record selezionati di una tabella bisogna usare il comando WR PRINT MERGE. Inoltre WR PRINT MERGE permette di impostare in maniera parametrica la visualizzazione o meno della dialog di stampa (0 non la mostra, 1 si), visto che la sintassi è: WR PRINT MERGE (area; tabella; mostra_dialog) Ecco un esempio su come stampare una copia di una lettera per ogni cliente: ALL RECORDS (Clienti]) `Tutti i clienti QUERY ([Lettere];[Lettere]Ref="Spedisci") `Carica un template Temp:=WR New offscreen area `Crea l'offscreen area WR PICTURE TO AREA(Temp;[Letters]Doc_) `Il template nella offscreen area WR PRINT MERGE (Temp;3) `Unisce il template con i dati nella tabella 3 WR DELETE OFFSCREEN AREA (Temp) `Cancella l'offscreen area |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Le icone identificative dei campi
Le icone che si trovano accanto ai campi delle tabelle nella Structure window sono rintracciabili usando i numeri di pict a partire da 150, ad esempio: - 150 restituisce l'icona del campo di tipo string; - 151 restituisce l'icona del campo di tipo real; - 152 restituisce l'icona del campo di tipo text; - 158 restituisce l'icona del campo di tipo int; - 159 restituisce l'icona del campo di tipo longint. |
1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
Stampare da codice un'area 4D Write [1]
Per stampare un'area di 4D Write senza l'intervento dell'utente è necessario utilizzare il comando WR PRINT. Questo comando equivale alla scelta dell'utente di Print dal menu File dell'area. E' interessante notare, per chi inserisce campi dinamici nelle aree 4D Write, che il comando WR PRINT può stampare sia i valori che i riferimenti, ma questi ultimi non vengono calcolati automaticamente: l'aggiornamento dei valori deve essere forzato prima dell'esecuzione della stampa. Ad esempio: WR EXECUTE COMMAND (area;wr cmd compute references) WR PRINT (area; 0;1) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
Ottenere testo formattato da 4D Write
Ecco un metodo che ritorna come risultato un blob contenente il testo formattato presente in un'area 4DWrite. Il risultato del metodo puo essere inserito in un altro documento usando il comando WR INSERT STYLED TEXT. ` $1 - L'area 4D Write ` $2 - Posizione del primo carattere ` $3 - Posizione dell'ultimo carattere ` $0 - Blob il testo C_LONGINT($1;$wrarea) C_LONGINT($2;$3;$begsel;$endsel) C_BLOB($0;$StyledTextBlob) $wrarea:=$1 $begsel:=$2 $endsel:=$3 Case of : (($begsel>=0) & ($endsel>0)) If ($begsel<$endsel) WR SET FRAME($wrarea;wr text frame ) WR SET SELECTION($wrarea;$begsel;$endsel) $StyledTextBlob:=WR Get styled text($wrarea) End if : (($begsel=-1) & ($endsel=-1)) ` Copy all WR SET FRAME ($wrarea;wr text frame ) WR EXECUTE COMMAND ($wrarea;wr cmd select all ) $StyledTextBlob:=WR Get styled text ($wrarea) End case $0:=$StyledTextBlob |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Comporre i numeri telefonici da 4D
Posto di avere un modem collegato alla porta seriale del computer, ecco un metodo che utilizza i comandi seriali di 4D e i comandi AT del modem per comporre un numero di telefono. $numero_t:=$1 SET CHANNEL(MacOS Serial Port+Protocol XONXOFF;Speed 1200+Data bits 8+Stop bits One+Parity None) SEND PACKET("+++") `Reinizializza il modem DELAY PROCESS(Current process;120) `Pausa di 2 secondi $messaggio:="AT S7=0 M1 DT"+$numero_t +Char(13) SEND PACKET($messaggio) DELAY PROCESS(Current process;120) `Pausa di 2 secondi SET CHANNEL(11) `Chiude la porta seriale |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Scaricare con il client il programma 4D su cui siamo connessi
Procedura da lanciare sul server CREATE RECORD([ARCHIVI]) [ARCHIVI]NomeArchivio:="NOME STRUTTURA DEL PROGRAMMA" $NuovoArchivio:=[ARCHIVI]NomeArchivio+"2" vErrore:=0 ok:=1 ON ERR CALL("ErroreSuBlob") $TipoArchivio:=Document type([ARCHIVI]NomeArchivio) If (($TipoArchivio#"") & (ok=1)) COPY DOCUMENT([ARCHIVI]NomeArchivio;$NuovoArchivio;*) If (ok=1) $Ref:=Open document($NuovoArchivio) If (ok=1) CLOSE DOCUMENT($Ref) [ARCHIVI]TipoArchivio:=Document type(Document) If (ok=1) DOCUMENT TO BLOB(Document;[ARCHIVI]DataFork) If (ok=1) COMPRESS BLOB([ARCHIVI]DataFork) End if If (ok=1) DOCUMENT TO BLOB(Document;[ARCHIVI]ResourceFork;*) If (ok=1) COMPRESS BLOB([ARCHIVI]ResourceFork) End if End if End if End if DELETE DOCUMENT($NuovoArchivio) End if End if ON ERR CALL("") [ARCHIVI]DataModifica:=Current date(*) [ARCHIVI]OraModifica:=Current time(*) [ARCHIVI]BytesDataFork:=BLOB size([ARCHIVI]DataFork) [ARCHIVI]BytesResourceFork:=BLOB size([ARCHIVI]ResourceFork) SAVE RECORD([ARCHIVI]) UNLOAD RECORD([ARCHIVI]) procedura da lanciare sul client (anche in remoto) dopo il tempo necessario al completamento della prima da parte del server $NuovoArchivio:=[ARCHIVI]NomeArchivio+" copia" $Ref:=Create document($NuovoArchivio;[ARCHIVI]TipoArchivio) If (ok=1) CLOSE DOCUMENT($Ref) EXPAND BLOB([ARCHIVI]DataFork) EXPAND BLOB([ARCHIVI]ResourceFork) BLOB TO DOCUMENT($NuovoArchivio;[ARCHIVI]DataFork) BLOB TO DOCUMENT($NuovoArchivio;[ARCHIVI]ResourceFork;*) End if su mac osx la struttura viene memorizzata dentro il pacchetto di 4D |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Campi booleani come testo: un altro approccio
Abbiamo visto in una faq sui Quick Report come trasformare un campo booleano in testo. Un sistema altrettanto interessante di risolvere il problema potrebbe essere utilizzare i formati associabili al comando String. Se volgio infatti Mostrare il testo "Vero" oppure "Falso" a seconda del valore di un campo booleano posso scrivere: $0:=String(Num($1);"Vero;;Falso") |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Stile |
Uso di @ nei comandi Object Properties
I comandi della categoria Object Properties (FONT, FONT SIZE, FONT STYLE, ENABLE BUTTON, DISABLE BUTTON, BUTTON TEXT, SET CHOICE LIST, SET ENTERABLE, SET VISIBLE, SET FORMAT, SET FILTER, SET COLOR, SET RGB COLORS, GET OBJECT RECT, MOVE OBJECT, BEST OBJECT SIZE, Get alignment, SET ALIGNMENT) agiscono sulle proprietà degli oggetti presenti in un form durante la sua visualizzazione in modalità User o Custom (le proprietà impostate vengono ovviamente perse alla chiusura del form). Questi comandi accettano come parametro sia il nome dell'oggetto che il nome relativo (sia che esso rappresenti un campo o una variabile), con una sintassi del tipo: COMANDO({*;} oggetto{ ; parametri specifici del comando}) Se viene usato il parametro *, questo indica che in "oggetto" viene specificato l'object name (e non la corrispondente variabile). Essendo questo una stringa, posso utilizzare "@" nel nome per selezionare gruppi di oggetti. Quindi: "IlMioPulsanteBtn" indicherà il pulsante con quel nome. "@Btn" indicherà tutti gli oggetti il cui nome finisce per "Btn" |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Web |
Un javascript per i valori di default
Se sviluppo siti internet che gesticono form di input ho due possibilità di gestire i valori di default. Uno è quello di riempire i campi col valore che mi attendo più frequentemente (ad esempio per il campo nazione potrebbe essere Italia) senza però essere certo che l'utente, in fase di inserimento, non abbia sbagliato a non modificare quel valore. Il secondo è assai più raffinato, e prevede l'uso di uno script in java per controllare dinamicamente l'inserimento dei dati, prima che questi vengano poi processati e controllati da 4D al "Submit" del form. Per il nostro esempio riguardante la nazione: <input type="text" name="newcountry" size="30" maxlength="40" value="«Inserisci la nazione»" onFocus="If (this.value=='«Inserisci la nazione»'){this.value=''}" onBlur="if(this.value==''){this.value='«Inserisci la nazione»'}"> In questo modo, nell'evento onFocus, se l'oggetto ha ancora il valore di default, lo cancello per permettere l'inserimento. Se non viene inserito nulla, inserisco nuovamente il valore di default. Fonte: 4DToday |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Usare i tasti freccia per scorrere la lista di record
Sarà capitato a tutti di ricevere da un cliente la richiesta di poter utilizzare le frecce per poter scorrere le liste di record nel form di output di una tabella. Per chi non usa la 2004 ecco un metodo da associare a quattro pulsanti non visibili nel form di output. Ad ognuno dei pulsanti collegare la pressione dei pulsanti "Freccia Giù" "Freccia Su" "Pag Giù" "Pag Su". Il metodo, prendendo come parametri la tabella corrente, l'azione e opzionalmente il numero di record da saltare selezionerà il record successivo/precedente o salterà avanti/indietro di "$3" record: DEFAULT TABLE($1->) C_LONGINT($N;selectedRecord) $N:=Records in selection($1->) $pTable:=$1 BOOLEAN ARRAY FROM SET($set_ab) $numeroRecord_l:=Find in array($set_ab;True;0) LONGINT ARRAY FROM SELECTION($pTable->;$record_al) selectedRecord:=Find in array($record_al;$numeroRecord_l) If (Count parameters>2) $quanti:=$3 Else $quanti:=1 End if Case of : ($2="down") selectedRecord:=selectedRecord+$quanti If (selectedRecord>$N) selectedRecord:=$N End if : ($2="up") selectedRecord:=selectedRecord-$quanti If (selectedRecord<1) selectedRecord:=1 End if End case GOTO SELECTED RECORD($1->;selectedRecord) CREATE EMPTY SET($1->;"ListSet") ADD TO SET($1->;"ListSet") HIGHLIGHT RECORDS("ListSet") CLEAR SET("ListSet") Usando lo stesso principio si potrebbero aggiungere anche i pulsanti per selezionare il primo o l'ultimo record della lista. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Web |
Scrivere i robots per i siti dinamici in 4D [3/3]
In aggiunta all'uso del meta tag ROBOTS che abbiamo visto si può inoltre utilizzare un secondo meta tag il "revisit-after". La sintassi è del tipo: <META NAME="revisit-after" content="nnnn days"> dove nnnn indica il numero di giorni che il motore di ricerca deve attendere per rivisitare la pagina. Ora, essendo il nostro sito completamente dinamico, fare rivisitare tutte le pagine non avrebbe senso, il motore di ricerca penserebbe che le pagine del sito non sono permanenti e lo declasserebbe. La soluzione diventa allora inserire sulla prima pagina del sito un valore di nnnn molto basso, ad esempio 2, per fare in modo che la prima pagina venga rivisitata spesso (e con essa, di conseguenza tutto il sito, poiché sulla prima pagina abbiamo scritto il nostro robot "index,follow"), e in tutte le altre un valore altissimo, tipo 1000 o 2000, per evitare che queste vengano rivisitate con richiesta diretta da parte del motore di ricerca. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Web |
Scrivere i robots per i siti dinamici in 4D [2/3]
Supponiamo di avere un sito che raccolga link e materiale su alcuni degli argomenti informatici più ricercati su Internet: computers, database software, database design, Oracle, Access, 4Th Dimension, ecc... Date le parole chiave, per essere da motore di ricerca mi interessa che la prima pagina e ogni pagina di dettaglio sia indicizzata, ma nelle pagine successive ci sono ancora link uguali a quelli della prima pagina: senza i Robots il sito verrebbe visitato dal motore di ricerca all'infinito. Invece decidiamo di usarli! La sintassi è: <META NAME =ROBOTS CONTENT="all | none | index | noindex | follow | nofollow"> Alcuni esempi: <meta name="robots" content="index,follow"> <meta name="robots" content="noindex,follow"> <meta name="robots" content="index,nofollow"> <meta name="robots" content="noindex,nofollow"> dove: - follow o nofollow indicano allo snake di visitare o no tutti i link della pagina. - index o noindex indicano allo snake di indicizzare o meno la pagina. La soluzione diventa semplice: alle pagine in testa all'albero di visita darò un meta tag di tipo "index,follow", a quelli che contengono notizie o risorse assignerò un "index,nofollow". |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Web |
Scrivere i robots per i siti dinamici in 4D [1/3]
Come richiesto ad Umberto Migliore durante il corso web spiego come abbiamo risolto per Sviluppo4D.it il problema delle visite dei motori di ricerca. Il motore di ricerca, per creare l'indice delle pagine lancia un programma detto "snake" che, a partire dalla pagina iniziale, si preoccupa di visitare tutti i link del sito. Molti programmatori avranno però notato che gli snake di Google o Msn, nel cercare di tracciare tutto il sito dinamico costruito con 4D, in realtà continuano a girare sempre sulle stesse pagine, innalzando così il numero di richieste in maniera esagerata: quando Sviluppo4D conteneva ancora poche informazioni ho notato picchi di 250 visite contemporanee! Questo è dovuto al fatto che, come avrà notato il programmatore che si è guardato il sorgente del sito, per riconoscere gli utenti, 4D genera una "Session", diversa per ogni visita (guardate l'URL che avete in questo momento sulla barra dell'indirizzo). Questa sessione però, in breve lasso di tempo, viene cancellata, il che significa che alla prossima visita del motore di ricerca, quella pagina per lo snake non esisterà più, e ricomincerà da capo a visitare il sito. La soluzione adottata per problema è stata semplice ed efficace: utilizzare i meta tag "ROBOTS". |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Utilizzare strutture o file dati Mac su NTFS
Supponiamo di avere un database creato su Mac (con i due file MioProgetto e MioProgetto.data) e volerlo utilizzare su Windows. Posto che la partizione Windows deve essere NTFS, è necessario intanto creare una copia compressa sia della struttura che del file di dati (ciò previene che la parte delle risorse non venga danneggiata o addirittura non venga copiata, se il programma che utilizziamo per copiare i file non supporta le risorse). Portati questi file compressi sulla partizione NTFS, scompattarli e chiamare la struttura MioProgetto.4DB e il file dati MioProgetto.4DD Nella versione 2004 4D divide anche su Mac i file in 4DB e RSR (per le strutture), 4DD e 4DR (per le base dati). |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Codici di errore: Network errors
Ecco un elenco degli errori che possono verificarsi nelle connessioni di rete: -10001 La connessione corrente al database è stata interrotta. -10002 La connessione per questo processo è stata interrotta. -10003 Parametri di connesione non corretti. -10020 Il server scelto con Select 4D server non è stato trovato. -10021 Il server scelto con Find 4D server non è stato trovato. -10030 E' avvenuta una desincronizzazione durante il ciclo di scrittura. -10031 E' avvenuta una desincronizzazione durante il ciclo di lettura. -10033 Dimensione dei dati errata durante il ciclo di lettura. -10050 Opzione sconosciuta in Get/SetOption. -10051 Valore errato in Get/SetOption. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Codici di errore: OS File Manager Errors
Ecoo un elenco degli errori ritornati dal file manager del sistema oprativo, solitamente generati quando si usano i comandi della sezione System Documents: -33 La cartella per il documento è piena. Non puoi creare un nuovo documento sul disco. -34 Il disco è pieno. Non c'e altro spazio disponibile sul disco. -35 Il volume specificato non esiste. -36 Errore di I/O . Esiste probabilmente un blocco danneggiato sul disco. -37 Nome del documento o del volume errato. -38 Tentativo di leggere o scrivere un file non aperto. -39 Richiesto un end-of-file logico durante l'operazione di lettura. -40 Tentativo di accedere ad una posizione precedente all'inizio del file. -41 Memoria insufficiente per aprire un nuovo documento sul disco. -42 Troppi documenti aperti sullo stesso disco. -43 Documento non trovato. -44 Il volume è bloccato da una impostazione hardware. -45 Il documento è bloccato. -46 Il volume è bloccato da una applicazione. -47 Tentativo di accedere ad un documento che è stato cancellato. -48 Tentativo di rinominare un documento col nome di un documento cancellato. -49 Tentativo di aprire un file già aperto in modalità di scrittura. -51 Tentativo di accedere ad un documento con un document reference number non valido. -52 Errore interno del file manager (posizione del file marker perduta). -53 Volume non in linea. -54 Tentativo di aprire un file bloccato per la scrittura. -57 Tentativo di lavorare con un disco non-Macintosh. -58 Errore nel file system esterno. -60 Errore nel master directory block. Il disco è danneggiato. -61 I permessi Read/write non consentono la scrittura. -64 Problema hardware sul disco (cattiva installazione, formattazione non corretta...) -84 Problema hardware sul disco (cattiva installazione, formattazione non corretta...) -120 Tentativo di accedere ad un documento usando il percorso di una cartella che non esiste. -121 Il percorso di accesso non può essere creato. -124 Tentativo di accedere ad un volume condiviso disconnesso. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novita' |
4D 2004: il pulsante Done di default
Una caratteristica delle versioni precedenti di 4th Dimension era l'aggiunta in automatico di un pulsante di chiusura del form ("Done") nel caso in cui il form stesso non contenesse altri pulsanti. A partire dalla versione 2004 questo pulsante non viene più aggiunto automaticamente: quindi l'unico modo per chiudere la finestra diventa quello di utilizzare la combinazione di uscita impostata ("Escape"), ad esempio su Windos Ctrl+"." e su Mac Command+"." |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Se 4D Tools non riesce a riparare il file dati
Se il tentativo di riparare un file di dati con 4D Tools non va a buon fine, è possibile che il resource file (il file nomefiledati.4DR su Windows, dove nomefiledati è il nome del file .4DD) sia danneggiato. In tal caso si può provare a sostituirlo. Ecco come fare per le due piattaforme: Windows - Fare un backup del database e del datafile. - Creare un nuovo database: in questo modo abbiamo, oltre al vecchio data file, anche un nuovo file di dati. - Sostituire il vecchio file .4DR associato al vecchio file dati col file .4DR creato dal nuovo database. - A questo punto abbiamo il vecchio file dati associato ad un nuovo file .4DR. - Provare ad eseguire adesso la riparazione con 4D Tools. Mac - Fare un backup del database e del datafile. - Creare un nuovo database: in questo modo abbiamo, oltre al vecchio data file, anche un nuovo file di dati. - Per entrambi i file dati, usare 4D Transporter per portare i dati in formato Windows. - Sostituire il file .4DR associato al vecchio file dati col file .4DR associato al database creato poco prima. - A questo punto abbiamo il vecchio file dati associato ad un nuovo file .4DR. - Essendo il tutto in formato Windows, utilizzare 4D Transporter nuovamente per portare la combinazione vecchio_file_dati-nuovo_4DR in formato Mac. - Provare ad eseguire adesso la riparazione con 4D Tools. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Windows XP Service Pack 2 e 4th Dimension
L'arrivo di Windows XP Service Pack 2 comporta vantaggi e svantaggi. Un vantaggio è che il problema dovuto al fix KB824141 sulle vecchie versioni non sembra più presente. Lo svantaggio è che le porte per 4D Server devono essere controllate per poter pubblicare i database col firewall attivo (standard del client è 19813, standard del web è la 80) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Web |
Usare i metodi con 4DIF
Supponiamo di avere un metodo che ritorni una stringa, e di volerlo utilizzare in un tag 4DIF per controllare se il metodo ritorna una stringa vuota. Penseremmo di scrivere: <!--4DIf (Il_metodo="")--> Pur essendo Il_metodo un prokect method corretto che ritorna una stringa, 4D ritornerà un errore del tipo: :A Boolean argument was expected Il problema è che bisogna aiutare 4th Dimension a valutare l'espressione, e lo si fa aggiungendo una coppia di parentesi alla chiamata del metodo, in questo modo: <!--4DIf (Il_metodo()="")--> Ciò segnala a 4D che Il_metodo è un metodo. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
Uso di Delay Process o di Pause Process
I comandi Delay Process e Pause Process fanno essenzialmente la stessa cosa: interrompono l'esecuzione del processo indicato. La differenza fondamentale sta nel fatto che: - DELAY PROCESS ferma l'esecuzione del processo per un certo lasso di tempo, dopo il quale il processo riprende automaticamente; - PAUSE PROCESS ferma l'esecuzione del processo fino a che non viene eseguito sullo stesso processo un comando RESUME PROCESS. Una situazione tipica si ha ad esempio quando un metodo lancia un nuovo processo e deve attendere il completamento dell'esecuzione di quest'ultimo per poter continuare. L'algoritmo per il metodo chiamante sarebbe: $id:=New process While (Process state($id)>=0) DELAY PROCESS (Current process; tempo_di_pausa_che_penso_ragionevole) End while In questo caso l'attesa e la ripresa sono gestite dal processo chiamante. Il vantaggio è che il processo chiamato non ha interazione alcuna col processo chiamante. Lo svantaggio è che il ciclo While potrebbe sprecare troppo tempo macchina (se il tempo di attesa è troppo corto) o fare restare il processo inattivo inutilmente (se il tempo di attesa è alto). Vantaggi e svantaggi si invertono se l'algoritmo è: $id:=New process PAUSE PROCESS (Current process) Il processo resta fermo in attesa che il processo chiamato non lo svegli con un RESUME PROCESS. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Web |
La sintassi di 4DIF
La documentazione di 4th Dimension specifica che la sintassi di 4DIF richiede l'uso delle parentesi, quindi: <!--4DIf (qualsiasivariabile=True)--> 4DIF potrebbe essere usato anche senza parentesi, ma meglio usarle, anche perché, ad esempio, il plug-in per Dreamweaver richiede l'uso delle parentesi perché il tag venga correttamente valutato. Inoltre è bene sottolineare che, insieme alle parentesi, la sintassi richiede uno spazio tra il tag e la parentesi; infatti se si usa: <!--#4DIF(qualsiasivariabile=True)--> 4D non valuterà correttamente il 4DIF. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novita' |
I cambiamenti del form event On Display Detail
Fino alla versione 2003, l'evento On Display Detail veniva eseguito per i soli record visualizzati, non per tutto il form: per capirci, se ho un form può contenere 15 record ma da mostrare ne ha solo 4, il codice inserito per l'evento On Display Detail verrà eseguito solo 4 volte. Invece, a partire dalla versione 2004, On Display Detail si comporta diversamente: infatti, nell'esempio visto, il codice verrebbe eseguito comunque 15 volte, anche se i record mostrati sono solo 4. Ecco una esemplificativa modifica ad una porzione di codice del manuale di upgrade alla 2004. Si noti anche l'uso del comando Displayed line number, che ritorna il numero di riga visualizzata: If (Form event=On Display Detail) If (Displayed line number %2=0) 'riga pari If (Record number([Tabella1])>-1) 'esiste un record sulla riga 'testo nero su verde chiaro SET RGB COLORS([Tabella1]Campo1;0;0x009FFF89) Else 'il record non esiste 'testo nero su azzurro SET RGB COLORS([Tabella1]Campo1;0;0x00A1FFFF) End if Else 'riga dispari If (Record number([Tabella1])>-1) 'nero su verde SET RGB COLORS([Tabella1]Campo1;0;0xAA99) Else 'blu scuro SET RGB COLORS([Tabella1]Campo1;0;0x70FF) End if End if End if Le righe contenenti un record sono o verde scuro o verde chiaro, le righe senza record sono azzurre o blu. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Web |
Nidificazione dei tag 4D e HTML
Spesso può risultare necessario usare i tag 4D all'interno di altri tag HTML. Analizziamo questo esempio: <input type ="text" name="varName" value = "<!--#4DVAR [Table]Field-->"> Si noti l'uso del tag 4D all'interno delle virgolette. Ciò non crea problemi. Infatti, le specifiche HTML impediscono l'uso di tag nidificati. Se scriviamo: <input type="checkbox" name="cbOne" value="Yes" <!--#4dhtmlvar isChecked-->> l'editor HTML (che sia Dreamweaver o GoLive) potrebbe ritornare un warning o un errore. Per aggirare l'ostacolo siamo costretti a riscrivere il codice così: <!--#4DIF(isChecked="CHECKED")--> <input type="checkbox" name="cbOne" value="Yes" CHECKED> <!--#4DElse--> <input type="checkbox" name="cbOne" value="Yes"> <!--#4DENDIF--> |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Impostare i valori di default
Nelle form di input è possibile prevedere che un campo sia già compilato con la data o l'ora corrente, o con il successivo Sequence Number. Nelle proprietà dell'oggetto Campo, nella riga Default Value è possibile scrivere: #H per l'ora corrente #D per la data corrente #N inserisce il sequence number o numero progressivo automatico |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Web |
Quando viene eseguito il database method On Web Authentication
Se usato, il metodo On Web Authentication viene richiamato nelle seguenti circostanze: - quando 4D riceve un URL che comincia con 4DACTION/ - quando 4D riceve un URL che comincia con 4DMETHOD/ - quando 4D riceve un URL che comincia con 4DCGI/ - quando 4D riceve la richiesta per una pagina statica che non esiste - quando 4D processa una richiesta con un tag 4DSCRIPT in una pagina semidinamica - quando 4D processa una richiesta con un tag 4DLOOP seguito da un metodo in una pagina semidinamica (solo la prima chiamata ) - quando 4D riceve una richiesta SOAP |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Web |
Seleziona un elemento in una lista Html
Ecco il testo con i tag da scrivere in Html per far sì che in una lista sia selezionato un elemento particolare. Il codice sfrutta un generico Array di testo che contiene le varie opzioni e il contenuto in una variabile "sceltaProposta" <SELECT NAME="Lista"> <!--4DLOOP Array--> <!--4DIf (sceltaProposta=Array{Array})--> <OPTION VALUE="<!--4DVAR Array{Array}-->" selected><!--4DVAR Array{Array}--></OPTION> <!--4DElse--> <OPTION VALUE="<!--4DVAR Array{Array}-->"><!--4DVAR Array{Array}--></OPTION> <!--4DENDIF--> <!--4DENDLOOP--> </SELECT> |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Mostrare in un testo una variabile o un campo
Se devo mostrare un testo che contenga un campo o una varibile in un layout, solitamente potrei scrivere: vTestoT:="La variabile ha valore "+vAltraVariabile Stessa cosa per il campo: vTestoT:="Il campo Nome ha valore "+[Table]Nome A questo punto inserisco la variabile vTestoT nel form. Una maniera certamente più rapida di risolvere la questione è inserire direttamente una zona di testo nel form e utilizzare i simboli "<" e ">" per segnalare la variabile o il campo. Basterà dunque scrivere: La variabile ha valore <vAltraVariabile> o Il campo Nome ha valore <[Table]Nome> |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Web |
Cambio dinamico della porta web
Il numero della porta TCP usata da 4D può essere modificato da linguaggio utilizzando il comando SET DATABASE PARAMETER utilizzando il parametro 15 (corrispondente alla costante Port ID). Per fare in modo che 4D usi la porta 8080 si userà: SET DATABASE PARAMETER(15;8080) o SET DATABASE PARAMETER(Port ID;8080) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
Controllare il blocco dei record con LOCKED ATTRIBUTES
Dopo aver controllato che un record è bloccato (prima della modifica o della cancellazione), con Locked, può essere usato il comando LOCKED ATTRIBUTES per capire chi o quale processo ha in uso il record. La sintassi è: LOCKED ATTRIBUTES ({table; }process; user; machine; processName) dove "table" è la tabella (se specificata, altrimenti userà quella di default), mentre gli altri parametri sono variabili che restituiscono il numero di processo (in modalità client/server è il numero di processo del server), nome utente e macchina (ma solo se in modalità client/server, altrimenti si ottengono due stringhe vuote) e il nome del processo. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Macro |
Metodo dei pulsanti *
Scrivendo un metodo per gli oggetti è possibile selezionare gli eventi nelle proprietà e scrivere il codice per gestire solo un particolare evento. Questo purtroppo non è molto leggibile, perche, ad esempio, in fase di debug potresti non sapere se e quale evento è selezionato quando tracci il codice. E' quindi buona norma gestire gli eventi con il solito Case, anche per gestire il clic su un pulsante, che è l'evento più normale. Per facilitare il compito di scrivere sempre la stessa cosa, ecco una macro che lo fa per conto nostro. Case of :(Form event=On clicked) End case Basta incollare questo codice XML nel file Macros.xml file, che si trova nella corrente cartella 4D di sistema, all'interno dei tag A questo punto è possibile usare all'interno del metodo la macro usando il menu contestuale (click-destro su windows o control-click su mac) e scegliendo la macro "OnClicked" dal menu "Insert Macro" |
1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
4th Dimension, MS Access e FileMaker Pro [15] Criteri di scelta
Una domanda che ci si pone è: "Quale sistema scegliere?". Oppure: "Secondo quali criteri un sistema può essere preferibile ad un altro?". La chiave attraverso la quale scegliere un sistema di sviluppo per database può essere l'equilibrio: l'equilibrio fra i bisogni dello sviluppatore e quelli dell'utente. Lo sviluppatore desidera un sistema semplice da sviluppare e flessibile. L'utente cerca un database con caratteristiche che lo rendano potente, ma di facile utilizzo e che costi poco. FileMaker è davvero semplice, ma assai limitato: si arriva ai limiti dell'applicativo non appena si hanno delle richieste un po' complesse. Access ha in alcuni aspetti grandi capacità, ma in altre risulta meno potente o assai complesso. In multiutenza ha un limite per numero di 4-5 utenti oltre il quale è necessario passare all'uso di un server SQL. 4th Dimension ha la facilità di sviluppo di FileMaker, ma possiede una grandissima varietà di caratteristiche aggiuntive rispetto agli agli altri due sistemi. Rispetto a FileMaker è più potente, rispetto ad Access è più facile e semplice da manutenere senza perdere in potenza. Consulta da questo link l’indice delle faq su 4th Dimension, MS Access e FileMaker Pro |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Web |
Riconoscere la lingua dell'utente
Il sistema più semplice e affidabile è quello di dare all'utente la lingua con cui lui si imposta il browser.. così accontenti anche l'utente che si trova in italia, ma parla (o meglio legge) inglese. L'informazioni la trovi facilmente nell'header che ti invia il browser. Ecco un esempio di codice: GET HTTP HEADER(array_nomi;array_valori) $elem:=find in array(array_nomi;"Accept-language") $codice:=array_valori{$elem} La variabile codice conterrà una stringa del tipo "it, us.." dove sono elencate le lingue in ordine di preferenza. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Convertire un numero di secondi in formato Ora
Ecco un modo semplice per convertire un valore LongInt che corrisponda al numero di secondi in un valore Time, Ora: ora_h:=Time(Time string(46800)) ` come scrivere ora_h:=?13:00:00? Nota che 86.400 secondi sono 24 ore. Se converti un numero che è più grande di 86.400, la funzione Time string aggiungerà ore, minuti e secondi. Quindi, Time string (86401) ritornerà 24:00:01. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Web |
Modificare la barra di stato nei siti dinamici
Se devo creare (o programmare, o sviluppare, o mantenere) un sito dinamico con 4th Dimension, capita che i collegamenti all'interno della pagina non siano "diretti", ma siano in realtà dei "redirect" che 4D esegue al momento del clic, vedi ad esempio lo stesso webhome. Ovviamente non è carino che il link venga visualizzato sulla barra di stato del browser con la sintassi del redirect di 4D. Si può fare allora in modo che, al passare del mouse sul collegamento, la barra di stato visualizzi l'indirizzo che verrà poi realmente visitato. Basta usare nella zona dell'html con l'"a href" che segnala il link questo attributo: onMouseOver="return stat('INDIRIZZO')" |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novizi |
Scorrere una selezione di record
Esistono tre modi di scorrere una selezione di record, a seconda che si usino i comandi For...End for, Repeat...Until o While...End while . Ecco il dettaglio delle sintassi: For ($i;1;Records in selection([Table 1])) ` esegui le operazioni NEXT RECORD([Table 1]) End for Repeat ` esegui le operazioni NEXT RECORD([Table 1]) Until (End selection([Table 1])) While (Not(End selection([Table 1]))) ` esegui le operazioni NEXT RECORD([Table 1]) End while Potrebbe essere necessario aggiungere prima del ciclo un FIRST RECORD([Table 1]) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Il percorso alla cartella Desktop
Ecco un metodo per avere un'informazione utile, ma non così semplice da ottenere. C_TEXT($0;$percorso_t;$4Dfolder_t) C_LONGINT($platform;$system;$vlSys;$i) PLATFORM PROPERTIES($platform;$system) If ($platform=Windows) $percorso_t:=System folder(Desktop Win ) Else $vlSys:=$system\256 If ($vlSys=16) $percorso_t:=System folder(Preferences or Profiles_User ) $percorso_t:=Replace string($percorso_t;"Library:Preferences:";"Desktop:") Else $4Dfolder_t:=System folder(System ) For ($i;1;Length($4Dfolder_t)) If ($4Dfolder_t[[$i]]=":") $percorso_t:=Substring($4Dfolder_t;1;$i)+"Desktop Folder:" $i:=Length($4Dfolder_t)+1 End if End for End if End if $0:=$percorso_t |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
Il comando Get menu item
Il comando Get menu item riceve come parametri il numero identificativo del menu, il numero identificativo della voce del menu e, opzionale, il numero di processo e restituisce il testo di una voce di menu. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
Il comando FTP_GetFileInfo
La sintassi è: FTP_GetFileInfo (ftp_ID; hostPath; size; modDate) Passando come primi due parametri un ID di sessione e il percorso ad un documento, il comando degli IC FTP_GetFileInfo restituisce nella variabile passata come terzo parametro la dimensione del documento e nella variabile passata come quarto parametro del documento la data di modifica. La funzione restituisce un error code. L'ID della sessione viene ottenuto usando il comando FTP_Login. Se come percorso viene passato un percorso completo, la Current Working Directory (CWD) della sessione ftp viene modificata con il percorso passato a FTP_GetFileInfo (stesso comportamento di FTP_GetDirList). |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Ottenere il numero di menu e una sua voce in modo esadecimale
A partire dalla versione 6 si possono utilizzare gli operatori di confronto per ottenere il numero di menu scelto e il numero della relativa voce scelta in questo modo: Menu := (Menu selected & 0xFFFF0000) >> 16 menu_command := Menu selected 0xFFFF |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Usare un solo metodo per tutte le voci di menu
Piuttosto che creare un metodo per ogni voce di menu, si può pensare di scrivere un unico metodo "Menu_Manager" che gestisca tutte le possibili chiamate da menu. Questa tecnica risulta interessante perché permette di gestire le chiamate anche dinamicamente. ` Project Method: Menu_Manager C_TEXT($SelectedMenuItem) $SelectedMenuItem:=Get menu item(Menu selected\65536;Menu selected%65536) Case of : ($SelectedMenuItem="Nuovo Record") ` Chiama qui il Metodo per creare un record : ($SelectedMenuItem="Record successivo") ` Chiama qui il Metodo per andare al record successivo : ($SelectedMenuItem="Record precedente") ` Chiama qui il Metodo per andare al record precedente : ($SelectedMenuItem="Stampa report") ` Chiama qui il Metodo per stampare un report End case |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Personalizzazione del Database Structure *
E' possibile modificare lo sfondo standard della finestra del database structure con una immagine personalizzata. IMPORTANTE: LA MODIFICA E' DEFINITIVA, nel senso che non è possibile ritornare all'immagine di sfondo standard di 4D (quella con gli ingranaggi, per intenderci). Per effettuare la modifica: - mettere negli appunti l'immagine che si vuole come sfondo; - cliccare su un punto vuoto (senza tabelle o relazioni) della finestra Database structure; - incollare l'immagine. |
1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
La posizione della 4D folder, la cartella di sistema di 4th Dimension
Il percorso della cartella di sistema dove 4D posiziona le sue preferenze può essere ottenuto in due modi: - usando il comando Get 4D folder; - guardando la voce 4D folder nella pagina "Program" della dialog "About 4th Dimension". A partire dalla versione 6.8: On MacOS X:{Disk}:Library:Application Support:4D Mac OS 9: Disk}:System folder:Application Support:4D Windows NT: {Disk}:\{System folder}\Profiles\All Users\Application Data\4D Windows 98/ME: {Disk}:\{System folder}\All users\Application Data\4D Windows 2000/XP: {Disk}:\Documents and Settings\All Users\Application Data\4D Windows 2000/XP con 4D Client: {Disk}:\Documents and Settings\{Current user}\Application Data\4D |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Macro |
Macro: una per Open form window
Ecco un esempio di macro da aggiungere al file Macro.xml nella cartella 4D del sistema. La macro apre una dialog centrata, ma può ovviamente essere modificata per effettuare altre operazioni sulle finestre. Basta inserire questo codice in qualsiasi punto del file tra i tag <macros> ... </macros>. <macro name="OpenDialog"> <text> C_LONGINT($windowRef) $windowRef:=Open form window(<selection/>;Plain window;Horizontally centered;Vertically centered) DIALOG(<selection/>) CLOSE WINDOW($windowRef) </text> </macro> Ad esempio, scrivendo e selezionando il seguente testo: [Table 1];"Form1" ed eseguendo la macro, si otterrà: C_LONGINT($windowRef) $windowRef:=Open form window([Table 1];"Form1";Plain window;Horizontally Centered;Vertically Centered) DIALOG([Table 1];"Form1") CLOSE WINDOW($windowRef) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
No more room to save the record: l'errore -9999
L'errore -9999, "No more room to save the record" segnala che tutti i segment del database sono pieni o non c'è più spazio per scrivere sul disco. Tuttavia è molto più facile che questo errore sia in realtà dovuto al fatto che il file di dati è in modalità "locked" o sia bloccato il disco su cui il file si trova. E' possibile controllare allo startup lo stato della base dati con il comando is data file locked. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Macro |
Macro: Inserire un elemento alla fine di un array
Per chi non usa 4th Dimension 2004 e non può dunque usare APPEND TO ARRAY ma usa ancora la 2003, ecco un sistema alternativo per inserire rapidamente un elemento in coda ad un array: aprire il file Macros.xml (si trova nella cartella 4D di sistema, ad esempio su Win C:\WINDOWS\4D) e aggiungere prima del tag di chiusura </macros> il seguente codice: <macro name="MioAppendToArray"> <text> INSERT ELEMENT(<Selection/>;Size of Array(<Selection/>)+1) <Selection/>{Size of Array(<Selection/>)}:= </macro> Al solito supponiamo che sia mioarray l'array a cui vogliamo aggiungere un elemento in coda. Nel punto del metodo in cui ci serve fare l'inserimento dell'elemento scriviamo "mioarray" (senza virgolette) e lo selezioniamo. Tasto di destra sul testo selezionato e scegliamo "Insert Macros - MioAppendToArray". La macro genererà il seguente codice: INSERT ELEMENT(mioarray;Size of array(mioarray)+1) mioarray{Size of array(mioarray)}:= Il cursore si troverà inoltre dopo il simbolo "=" pronto per farci inserire il valore desiderato. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Evitare la duplicazione dei processi
Se abbiamo l'accortezza (o usiamo il sistema) di dare ad ogni processo un nome che lo identifichi univocamente, siamo già pronti a controllare che uno stesso processo sia lanciato più volte (e dunque duplicato). Basta usare infatti il parametro "*" del comando New process: se esiste già un processo con lo stesso nome di quello che stiamo creando, New process restituirà l'id del processo esistente, invece di crearne uno nuovo. Ecco dunque un'idea di metodo di apertura dei processi, che prende come parametri nome del metodo, dimensione dello stack e nome del processo: C_TEXT($1;$3;$NomeDelMetodo_t;$NomeDelProcesso_t) C_LONGINT($2;$StackSize_l;$procid_l) $NomeDelMetodo_t:=$1 $StackSize_l:=$2 $NomeDelProcesso_t:=$3 $procid:=New process($NomeDelMetodo_t;$StackSize_l;$NomeDelProcesso_t;*) BRING TO FRONT($procid_l) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Stile |
Uso della ricorsione e metodi ricorsivi
Uno dei sistemi di programmazione più affascinanti è sicuramente dato dall'uso della ricorsione: lo scopo è fondamentalmente quello di scrivere meno codice possibile, facendo in modo che operazioni identiche siano ripetute in cascata sempre dallo stesso metodo: facciamo un esempio. Supponiamo di voler scrivere un metodo che conti il numero di file presenti in una cartella e nelle sue sottocartelle. Usando la ricorsione non faremo altro che chiamare il metodo di conteggio dei file sulla cartella madre e su tutte le sottocartelle in essa contenute. Ecco il codice: C_STRING(255;$1) ARRAY TEXT($FolderList;0) ARRAY TEXT($DocumentList;0) C_LONGINT($piattaforma;$i) C_LONGINT($0;$count) ` ottengo l'elenco di file e cartelle FOLDER LIST($1;$FolderList) DOCUMENT LIST($1;$DocumentList) $count:=Size of array($DocumentList) If (Size of array($FolderList)>0) For ($i;1;Size of array($FolderList)) PLATFORM PROPERTIES($piattaforma) ` richiamo il metodo di conta su ogni `sottocartella della cartella corrente If ($piattaforma#3) $count:=$count+ContaFile($1+$FolderList{$i}+":") `RICORSIONE Else $count:=$count+ContaFile($1+$FolderList{$i}+"\\")`RICORSIONE End if End for End if $0:=$count Il metodo chiamante sarà: $count:=ContaFile(Select folder("Scegli la cartella da contare")) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Gestire la memoria su Windows con 4D Customizer Plus
Tra le preferenze gestibili con 4D Customizer Plus c'è la quantità di memoria allocata su Windows, la voce "Main Memory Application". Per i valori da inserire si può fare riferimento alla faq sulla gestione della memoria. Una cosa importante da tenere presente è che il valore che viene impostato nelle "Preferences" della struttura molto spesso non viene preso in considerazione. Infatti 4D controlla innanzitutto se la preferenza "Main Memory" è impostata su uno dei file delle preferenze; i file delle preferenze si trovano nella 4D folder (la cartella All users\Application Data\4D all'interno di Documents and setting o della cartella di sistema) e sono (nella 2003): - 4D Preferences 2003.RSR per 4D, 4D Server, 4D Client, 4D Tools; - 4D Runtime Preferences 2003.RSR per 4D Runtime, 4D Runtime Classic; - 4D Engine Preferences 2003.RSR per l'Engine Quindi se la preferenza della memoria è impostata sia nell'applicazione che nel file delle preferenze, quest'ultimo ha precedenza. Si possono allora avere questi casi: - Se si configura la memoria attraverso le preferenze di 4d, queste impostazioni verranno inserite nel file delle preferenze (se contiene la risorsa "Main memory"). - Se si apre col Customizer il file delle preferenze, fare doppio clic sulla voce "Main Memory". Impostando qui un valore, questo verrà utilizzato al posto di quello settato nell'applicazione. - Per utilizzare il settaggio della memoria eseguito sull'applicazione il file delle preferenze relativo deve essere cancellato dalla 4D folder. - Il settaggio della memoria della struttura viene utilizzato solo quando questa viene poi inserita nell'Engine, avendo però al solito cura di aver cancellato il file "4D Engine Preferences 2003.RSR", che altrimenti ha priorità nella creazione dell'eseguibile. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Mostrare il Quick Report e il suo Wizard da progranmma
Il Quick Report e il suo Wizard sono disponibili da ambiente User, ma se volessimo permetterne l'uso anchedall'ambiente Custom in un proprio programma è possibile utilizzare il comando QR Report. Il comando accetta fino a sei parametri - QR Report( {tabella;} documento {;hierarchical {;wizard {;search}}} {;*})- dove solo il primo è obbligatorio. Per visualizzare l'editor del Quick Report, basta passare il nome di un documento che non esiste (se esiste il QR Report lo apre e la calcola direttamente); impostando a True il parametro Wizard è possibile rendere disponibile all'utente anche questa funzionalità. Di seguito riportiamo il codice per dare la possibilità all''utente di realizzare, stampare e salvare i propri report: QUERY([Tabella]) If (OK=1) QR REPORT([Tabella];Char(1);False;True;False) End if Come puoi vedere, il parametro del documento è passato come il carattere Char(1), un nome di documento che non esiste, e il parametro wizard è passato come true. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novizi |
Quando impostare i valori delle variabili
Quando si accede ad un INPUT FORM (o maschera di inserimento) è consigliabile impostare i valori delle variabili o dei campi inserendo questi assegnamenti nella zona "On Load" del metodo del form. Ad esempio: Case of :(Form event=On Load) una_variabile:=3 End case Nell'evento on Load vanno preimpostati anche i vari oggetti del form. Ad esempio, se ho un tab control che uso per scorrere le pagine del form, posso impostare "l'etichetta" che deve essere selezionata in partenza. L'evento on Load può in realtà essere controllato anche all'interno di ogni singolo oggetto, ma in genere è meglio raccogliere tutte queste impostazioni in un unico punto, il metodo del form: in questo modo è possibile valutare tutte le preimpostazioni e decidere anche la precedenza o la priorità di alcune. Ad esempio, se ho un menu a scelta che mi mostra/nasconde alcuni campi di inserimento, o se devo cambiare il colore di qualche oggetto (magari un campo è rosso se è obbligatorio quando un altro campo è preimpostato). |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
4D View: selezionare una riga cliccando su una cella
Il comando PV SET AREA PROPERTY di 4D View permette di impostare una serie di proprietà dell'area. Ad esempio possiamo usarlo per fare in modo che, cliccando su una cella si selezioni automaticamente l'intera riga: Case of :(Form event=On Load) PV SET AREA PROPERTY (area;pv select mode ;pv select single row ) PV SET AREA PROPERTY (area;pv select highlight ;pv value on ) End case |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Quale Runtime usare per distribuire un applicativo
Innanzitutto elenchiamo la corrispondenza dei nomi della versione 2004 in confronto con i precedenti: 4D Runtime Interpreted = 4D Runtime 4D Runtime Single User = 4D Runtime Classic 4D Runtime Volume License Light = 4D Engine Light Edition 4D Runtime Volume License Sponsored = 4DEngine Sponsored Edition Illimited 4D Runtime Volume License Pro = 4D Engine Pro Edition Ecco riassunte le differenze: 4D Runtime Interpreted: gratuito, distribuzione illimitata, unico limite applicazioni non compilate, è separato dalla struttura (quindi non è una sola applicazione doppio cliccabile). 4D Runtime Single User: 106 Euro per un utente, per le applicazioni compilate, separato dalla struttura. 4D Runtime Volume License Light: gratuito con 4d o Server Developer, distribuzione illimitata, compilato come singola applicazione, unico limite la creazione di massimo 50 record per tabella (solo se si aggiungono, quindi posso usare una tabella piena con più di 50 record). 4D Runtime Volume License Sponsored : 1.069 Euro, distribuzione illimitata, compilato come singola applicazione, alla chiusura del programma appare per qualche secondo una finestra con scritto www.4d.com. 4D Runtime Volume License Pro : 2.674 Euro, fino a 1000 utenti, compilato come singola applicazione, senza finestra sponsor alla fine. Tutti funzionano in sola lettura, ad esempio su CD. Il modo più economico di sviluppare con 4d è comprare la versione di 4D Standard Edition da 299 Euro e distribuire il proprio applicativo con il 4D Runtime Interpreted, che è gratuito e senza altre limitazioni se non quello della compilazione. Nota: I prezzi sono Iva esclusa e del listino della versione 2004; ad oggi (nov/04) è possibile comprare anche la versione 6.8 e 2003. Inoltre ogni tanto Italsoftware fa accordi con alcune riviste (Mac e/o Windows) per la distribuzione di una standard edition inclusa nel cd allegato, praticamente gratuita. E' possibile, a meno delle nuove caratteristiche e di eventuali differenze estetiche, programmare con una versione precedente e distribuire il software con una versione più nuova del Runtime. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Controllare se Quicktime è installato su Windows
Mentre QuickTime è di default installato su Mac, la stessa cosa non si può dire su Windows. Per controllare se QuickTime è installato o meno è necessario utilizzare dei piccoli trucchi da codice. Ad esempio: PICTURE TYPE LIST($array1;$array2) Se la dimensione di uno di questi array è almeno uno, allora QuickTime è installato. Un altro sistema potrebbe essere questo: GET PICTURE RESOURCE(9000;$vPicture) `carica un'immagine If (OK=1) PICTURE TO BLOB($vPicture;$myBlob;"JPEG") End if Il comando cerca di convertire l'immagine in JPEG. Se la dimensione del BLOB è zero, allora la conversione non è stata eseguita e quindi QuickTime non è installato. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novita' |
4D 2004: accesso alla cartella delle Licenze
Se l'attivazione del prodotto 4D è andata a buon fine, il file di licenza dell'applicazione è posizionato nella cartella Licenses. Tutti gli altri prodotti 4D attivati e i prodotti aggiuntivi (Expansion) avranno i loro file di licenza nella stessa cartella. Questa cartella Licenses può essere trovata in questi percorsi: Windows: Documents and Settings\All Users\Application Data\4D\Licenses Macintosh: Library:Application Support:4D:Licenses Per trovarla direttamente da 4D basta andare nelle finestre di “Update License” e di “About 4D”, dove c'è un pulsante “Licenses Folder” che aprirà una nuova finestra della cartella Licenses. (Fonte: Tech Tips #33938) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
4D e PHP
Per poter servire pagine dinamiche con Php generalmente si utilizza questa configurazione: web server + php + backend verso un database Mysql o altro. Php si integra facilmente con molti database SQL attraverso i vari moduli ODBC, ma non si integra direttamente con 4D Web Server (su Mac non c'è il driver ODBC per 4d) e non esiste un "4D open for php", quindi una soluzione può essere quella di usare i WebServices. In una realtà in cui esiste già un server Apache + Php è stato sviluppato un database 4D. I dati di 4D accessibili via client vengono quindi anche mostrati in alcune pagine dinamiche offerte da Apache, non utilizzando 4D come Web Server, ma pubblicando alcune procedure come Web Services (SOAP). Ecco i passi indispensabili eseguiti in 4D: 1 - Il Server 4D installato ha le licenze web (nella versione 2004 è possibile acquistare solo il modulo per i webservices che costa meno) e il Web Server è attivo (Ambiente User: Menu Web Server : Start Web Server). 2 - Sempre lato server, impostare le Preferenze per i Web Services. In questo caso 4D fa da Server per le SOAP quindi verificare solamente le opzioni per Server Side. Sicuramente impostare "Allow Web Services Requests". Gli altri due parametri sono stati lasciati come di default. 3 - Creazione di un metodo usufruibile via Web Services: Menu Designer:New Method: wbSerTest. Per questo metodo dal menu Method:Method Properties: selezionare due opzioni da Attributes : Offered as a web Service, e Published in WSDL. Questo permette di richiamare il metodo come una funzione che dall'esterno accetta parametri e restituisce valori. ` metodo wbSerTest offerto via SOAP C_INTEGER(in_RowQty; RowQty) C_TEXT(AskDescr;in_AskDescr) C_BLOB(Articles_Bl;Blob_tmp) SET BLOB SIZE(Articles_Bl;0) RowQty:=0 SOAP DECLARATION(AskDescr;Is Text ;SOAP Input ;"in_AskDescr") SOAP DECLARATION(RowQty;Is Integer ;SOAP Input ;"in_RowQty") SOAP DECLARATION(Articles_Bl;Is BLOB ;SOAP Output ) If (Length(AskDescr)>5) READ ONLY(*) If (RowQty<=0) RowQty:=10 End if QUERY([Articles];[Articles]Description= AskDescr) If (Records in selection([Articles])>0) ORDER BY([Articles];[Articles]Description;>) REDUCE SELECTION([Articles];RowQty) $tmp:="" While (Not(End selection([Articles]))) $tmp:=[Articles]Description+Char(9)+[Articles]Code+Char(13) TEXT TO BLOB($tmp;Articles_Bl;3;*) NEXT RECORD([Articles]) End while Else TEXT TO BLOB("empty query";Articles_Bl;3;*) End if End if Lato Php: require_once('nusoap.php'); //nusoap.php scaricabile a quest'indirizzo: //http://dietrich.ganx4.com/nusoap/ //mi connetto al server sul quale "gira" 4d // e' importante notare 4DSOAP come parte del percorso $soapclient = new soapclient('http:// //Qui definisco i parametri da passare alla funzione $parameters = array('in_AskDescr'=>valore1,'in_RowQty'=>valore2); $ret = $soapclient->call('wbserTest',$parameters); if(!$ret) { print "Error:" . $soapclient->getError() . '\n<br><br>'; exit; } else echo "Risultato : " . var_dump($ret) . '\n<br>'; } //Attenzione: se la funzione restituisce un parametro come risultato allora $ret sara' una //variabile semplice altrimenti sara' un array associativo che avra' come chiavi i nomi delle //variabili che restituisce la funzione . //"Spengo il client" unset($soapclient); ?> Funziona. Si ringrazia per il contributo Mauro Donadello |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
File |
Component Query Editor
Ritenendo i component degli elementi importantissimi nella programmazione avevo promesso di fare un regalo a tutti gli sviluppatori 4D. Il regalo era un component che noi usiamo pesantemente, Query Editor. Questo component permette ai vostri utenti di crearsi delle query e di averle a portata di click. Il query editor creato, si differenzia per la possibiltà di usare anche funzioni 4D. Intendo dire che si posso cercare elementi la cui data è la current date, oppure il campo di ricerca è il risultato di una request ecc... oltre alla possibilità di fare query by formula. In allegato troverete il component e 2 manuali. Un manuale è quello di riferimento per il programmatore e l'altro è il manuale da dare all'utente finale. Il component può essere usato solo con 4D 2003.5 e non con 4D inferiori o 4D 2004. Così come è il component è in demo e lavora per un ora. Nel caso dopo le prove lo riteniate interessante e vogliate utilizzarlo nei vostri software mandatemi un mail di richiesta e vi verrà spedita la password. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Salvare il documento di un plugin
Usare SAVE RECORD per salvare un record che contiene un campo blob con una plugin area (tipo WriteArea_) non salva automaticamente il contenuto del campo come farebbe ACCEPT. Questo perché per SAVE RECORD non vale il salvataggio automatico del blob-plugin nel campo che invece ACCEPT esegue. Per eseguire correttamente il salvataggio è quindi necessario fare manualmente la conversione a blob dell'area del plugin. Usando come plugin, ad esempio, 4D Write, la sequenza da seguire è: [Tabella]WriteArea_:=WR AREA TO BLOB(WriteArea;1) SAVE RECORD([Tabella]) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Ordinare le colonne calcolate dei QR nella 2003
Una delle cosa di cui mi lamentavo del nuovo Quick Report della versione 2003 era la scomparsa della "Sorted" per le colonne: il che non era un problema per le colonne che contenessero dei campi del database (che potevano essere trascinate nella zona "Sort order"), ma lo diventava per i campi calcolati. Ma mi sono ricavato uno stratagemma: prendo una colonna, la trascino nella zona "Sort order" e la colonna compare anche fra le colonne del report: un bel doppio clic sulla colonna e si apre l'Edit della stessa; inserisco il calcolo che voglio effettuare, premo OK e la colonna continua a risultare "ordinata". Posso quindi calcolare al solito break, subtotali, ecc... |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
I metodi nel Quick Report
Come citava una famosa rubrica, forse non tutti sanno che è possibile richiamare un metodo in una colonna di un quick report: basta semplicemente scriverne il nome e il valore ritornato dal metodo sarà il valore che prenderà la cella del report. Ecco un esempio di uso: voglio avere un break in un report per Anno&Mese; se ordino per il campo Data il break sarebbe per giorno, quindi scrivo un metodo a cui passo il campo data. `Da usare nel report, ritorna una stringa nel formato AAAAMM $data_d:=$1 $0:=String(Year of($data_d))+String(Month of($data_d);"00") |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
Controllare lo stato di un host con NET_Ping
Usando gli Internet Command è possibile controllare se una macchina è in rete usando il comando NET_Ping. Ovviamente se l'host è protetto attraverso un firewall il comando potrebbe restituire risposta negativa. Il comando NET_Ping riceve come parametri l'host, un testo da usare come dimensione del pacchetto da inviare, un longint che conterrà lo stato deoll'host e, opzionale, il tempo di timeout. Ecco un esempio di codice per controllare lo stato di un certo host: `Method: Ping C_TEXT($1) C_INTEGER($alive) $alive:=0 $errcode:=NET_Ping ($1;"test";$alive) If ($errcode=0) If ($alive#1) ALERT($1+" non è attivo.") Else ALERT($1+" è attivo.") End if Else ALERT("Errore # "+String($errcode)) End if |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
4D 2004 Server Eseguibile e Cambio IP del server
Ecco una soluzione di un problema se producete un applicativo compilato con l'opzione server eseguibile con 4D 2004. Una volta configurato il sistema, quindi server e client, provate e verificate le connessioni con il server, tutto funziona. Decidete di cambiare il computer che svolge la funzione di server: se al nuovo server assegnate lo stesso indirizzo del vecchio server tutto rifunziona correttamente. Se usate una macchina con diverso indirizzo di IP, quando tenterete di riconnettervi dai client, dopo circa 30 secondi appare l'errore -10002 come se non trovasse il server. Per rimediare su Windows bisogna eliminare il file: EnginedServer.xml che si trova all'interno della cartella 4D Client dentro la cartella 4D Extension Su MacOS X dovete eliminare lo stesso file. Visualizzate il contenuto del pacchetto del client generato dal builder e troverete il file dentro la cartella 4D Extension. Cosi facendo al successivo avvio vi verrà mostrata la finestra per scegliere nuovamente un'applicativo server. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Licenze 2004 : qualche informazione pratica *
Ecco alcune informazioni pratiche; occorre precisare che non sono ufficiali, per cui ci potrebbero essere errori o interpretazioni non corrette. 1. Per la registrazione del prodotto occorre un codice utente e la password registrati presso un sito di 4d ( in automatico porta al sito http://4dstore.4d.fr/ ). In teoria ogni utente dovrebbe registrarsi ma non credo ci siano problemi se si registra lo sviluppatore... almeno non tecnici. La registrazione per avere un proprio Account si può fare anche senza avere un prodotto da registrare. 2. Per ogni prodotto 4D esiste un Product Number unico. 3. Nella finestra di Unlock 4d devi scrivere: l'account, la relativa password e il Product Number (e un indirizzo email alternativo o ugale a quello dell'account) 4. Se la macchina non è collegata ad internet si può registrare sempre nella stessa schermata di Unlock4D un file da mandare sempre usando lo stesso sito http://4dstore.4d.fr/ ; il sito poi rimanda via mail un file di autorizzazione che letto sempre nella stessa finestra di 4d abilita il prodotto. 5. Il processo di abilitazione si può fare 3 volte; ovviamente dopo si può richiedere tramite il distributore Italsoftware lo sblocco. 6. Le licenze vengono registrate in un file nella cartella Licenses dentro la cartella 4D nel Sistema. L'informazione non è nascosta tanto che nella finestra di 4D Update License c'è proprio un pulsante che apre questa cartella. I file sono in formato HTML e presentano un elenco delle licenze attive. 7. Se ci si trova nei problemi l'Emergency mode attiva il prodotto solo inserendo il Product Number e senza bisogno di avere una connessione internet per 5 giorni, con l'unica limitazione di poterlo fare solo una volta al mese. 8. Invece la modalità Demo è sempre la stessa, cioè accesso in scrittura a max 20 metodi e 50 records. Nota: link aggiornati, http://4dstore.4d.fr/ è più facile da usare. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Installare i numeri seriali di 4D
Per installare nuovi numeri seriali per 4D, in particolare quando si sta usando il Runtime, basta premere contemporaneamente i tasti Ctrl+Shift+F8 su Win e Command+Shift+F8 su Mac. Per gli utilizzatori della 2004 è inoltre possibile usare il nuovo comando CHANGE LICENSES. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
L'errore -10002 e le impostazioni TCP/IP
Il funzionamento del protocollo TCP/IP dentro 4D è assai semplice: quando 4th Dimension (o 4D Client o 4D Server) devono inviare un pacchetto in rete, il driver TCP/IP, attraverso comandi di basso livello, invia il pacchetto a destinazione. Se l'invio non va a buon fine 4D ritenta un certo numero di volte, fino a restituire il famigerato errore -10002. In linea di massima se la rete è ben costruita, non ci sono particolari problemi di collisioni o di colli di bottiglia, è difficile vedere questo errore. Comunque, per chi avesse familiarità col registro di sistema di Windows, è possibile agire su alcune chiavi per fare in modo che 4D "ritenti più volte" prima di restituire errore (la cosa non risolverebbe ovviamente i problemi di rete, renderebbe solo il TCP/IP più tollerante). I parametri si trovano nelle due sottochiavi: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\ID della scheda e sono i parametri KeepAliveInterval e TcpMaxDataRetransmissions. Vista la pericolosità della modifica manuale di questi valori, è bene studiarne attentamente il comportamento, prima di apporre modifiche che potebbero rendere il sistema inutilizzabile. Inoltre, almeno teoricamente, Windows XP ottimizza questi parametri in funzione dell'hardware usato. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Limitare l'accesso ad un plugin
E' possibile limitare l'accesso degli utenti ad un plugin utilizzando la finestra delle password di 4th Dimension: la funzione è utile soprattutto in installazioni client-server in cui il numero di licenze di un particolare plugin è inferiore al numero di client totali. Ad esempio, in un call center di 100 persone, potrei avere bisogno di solo 10 licenze write per i responsabili. Entrando come Designer o Administrator nella dialog delle password creare un nuovo gruppo a cui assegnare gli utenti che avranno accesso al plugin. A questo punto scegliere dal menu Password la voce Plug-Ins Access per accedere alla finestra che permette di decidere quale gruppo (quello appena creato, ad esempio) può accedere a quale plugin. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Modificare tutte le password del sistema
Se l'ambiente password del database è rovinato o da ripristinare, è possibile crearne uno nuovo con 4D Insider, che permette di creare una nuova struttura senza password. Ecco le operazioni: - aprire il database con l'Insider; - creare un nuovo db; - selezionare nel vecchio tutti gli elementi; - trascinarli sul nuovo; - salvare il nuovo database; - impostare le nuove password con 4th Dimension. Bisogna inoltre notare che: - in relazione al numero di elementi del database, può essere necessario effettuare il trasferimento a piccoli pezzi; - volendo esportare anche gli utenti, solo quelli creati dall'Administrator possono essere esportati. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novizi |
Jumpstart 4D: ovvero un manuale completo di 4th Dimension
Uno degli aspetti più difficoltosi in cui un utente si imbatte iniziando a programmare con 4D è la vastità di informazioni dove attingere, dove per informazioni intendiamo ovviamente i manuali. Da quale parto? Cosa mi serve? E se non trovo ciò che mi serve? Se le varie faq di introduzione a 4D sono troppo piccole, o se gli articoli di 4D sul passaggio da FileMaker Pro a 4th Dimension non vi hanno risolto il problema, un'altra strada da seguire potrebbe essere Jumpstart 4D, il manuale scritto da Steve Hussey che porta il programmatore ad avere una conoscenza di base ma completa del prodotto, partendo dalla struttura, passando poi agli ambienti User e Custom, password, compilazione e distribuzione del prodotto. Il tutto aiutato dalla costruzione guidata di un piccolo database di gestione fatture. Le informazioni potete trovarle su 4D Press. Jumpstart 4D è acquistabile per $29 in versione cartacea su Amazon o su 4D Store, oppure si può scaricare gratuitamente il PDF dal sito ftp di 4d. |
1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
4D SDK: scrivere codice per 4th Dimension in C e C++
Un aspetto molto interessante di 4D è quello di permettere di scrivere delle routine in C o C++ da utilizzare all'interno dei programmi. Queste routine vengono generalmente chiamati plugin. 4D SDK è una raccolta di circa 500 comandi che permettono di integrare il codice scritto in C/C++ con 4th Dimension. La maniera più rapida per scrivere un plugin è utilizzare 4D plug-in Wizard, un tool di 4D SDK nel quale è possibile definire nomi parametri e valori ritornati dei plugin. Vengono così generati una serie di file che costituiscono il punto di partenza del progetto. A questo punto possiamo scrivere il nostro codice in C o C++ e quindi compilarlo. Si piazza il plug-in nella cartella Win4dx o Mac4dx ed ecco che il comando creato in C è tranquillamente utilizzabile dentro 4th Dimension. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Web |
Comunicazione con Macromedia Flash
Ecco un esempio di Action Script per un pulsante in Flash che invia dei dati a 4D: on (release) { loadVariables ("http://www.sviluppo4d.it/4DCGI/web_esempio", _root, "POST"); } "loadVariables" è una funzione Flash che chiama l'URL indicato. Modificando la funzione "loadVariables" nella palette Object Action, vedrai che ci sono delle scelte: "Send using POST" e "Send using GET". Così puoi inviare le variabili Flash a 4D, che da 4D leggi usando GET WEB FORM VARIABLES come se i dati venissero da una pagina HTML. Per rimandare dei dati a Flash, puoi rispondere con una chiamata semplice del tipo: SEND HTML TEXT("success=1&message="QUESTO VIENE DA 4D") dove "success" e "message" saranno delle variabili in Flash. La chiamata "loadVariables" leggerà la risposta e invierà le informazioni alle variabili Flash. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Web |
4D Portal: un'introduzione
Uno degli applicativi sviluppati con 4th Dimension dalla 4D, Inc di maggiore interesse è senz'altro 4D Portal. Questo software mostra le capacità di 4D nel gestire contenuti web di vario genere, come forum, sondaggi, aste, chat, blog, calendari, scadenze, appuntamenti, cartoline, siti web preferiti, e così via. Si utilizza direttamente come server, oppure si interfaccia in maniera nativa con 4D Webstar, o usando 4DLINK oppure con un proxy (cioè lo si può tenere su una macchina in locale e su webstar si imposta l'indirizzo locale cui fare riferimento ad una determinata richiesta di dominio). Il costo di 4D Portal è ZERO, nel senso che è un programma free: si installa ed è già tutto disponibile (non è richiesto alcun plugin aggiuntivo, anche le licenze Web sono incluse!). E' possibile configurare anche più portali contemporaneamente. E' però anche un utile strumento didattico, poiché è disponibile il sorgente, consultabile e modificabile. Se però lo si modifica è poi necessario acquistare una licenza web. Sia il freeware che il sorgente sono scaricabili dal sito di 4d portal stesso. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Controllo cartelle vuote
Ecco un piccolo metodo per controllare se una cartella è vuota. Il metodo riceve come parametro il percorso completo alla cartella e restituisce True se la cartella è vuota. C_BOOLEAN($0) C_TEXT($1;$percorso_t) ARRAY TEXT($arrelementi_t;0) $percorso_t:=$1 $0:=False FOLDER LIST($percorso_t;$arrelementi_t) If (Size of array($arrelementi_t)=0) DOCUMENT LIST($percorso_t;$arrelementi_t) If (Size of array($arrelementi_t)=0) $0:=True End if End if |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Ottenere il nome di un mese dalla data
Questi due frammenti di codice permettono di conoscere il nome del mese di una data passata come parametro. Viene usata la risorsa 'STR#' con ID=11. Il primo frammento restituisce il nome del mese in formato abbreviato: ` $1 - Data ` $0 - Nome breve del mese $0:=Get indexed string(11;Month of ($1)) Il secondo il nome per esteso: ` $1 - Data ` $0 - Nome del mese $0:=Get indexed string(11;12+Month of ($1)) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Ottenere un numero da una data e viceversa
Ecco un semplice metodo che converte una data in un ben determinato numero: ` Project Method: DaDataANumero C_LONGINT($0) C_DATE($1;$data) $data:=$1 $0:=$data-!00/00/00! Avendo un numero si può quindi ottenere la data relativa con questo metodo inverso: ` Project Method: DaNumeroAData C_LONGINT($1) C_DATE($0;$data) $data:=!01/01/01!+$1 $0:=$data-(!01/01/01!-!00/00/00!) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
Il comando Get indexed string
Utilizzando una sintassi del tipo: Get indexed string (resID; strID{; resFile}) dove: - resID è il numero della risorsa; - strID è il numero della stringa; - resFile è il numero identificativo del resource file da usare, altrimenti, se omesso, tutti i file aperti; il comando permette di ottenere la stringa contenuta nella risorsa lista di stringhe resID in posizione strID. Per ottenere tutte le stringhe di una risorsa di questo tipo si usa invece il comando STRING LIST TO ARRAY. |
1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novizi |
Prima introduzione a 4d: FILE E CAMPI *
Prima cosa creare file e campi, nella terminologia di 4D si usano i termini inglesi Table(s) e Field(s). E qui non ci sono problemi, i campi hanno il loro type (tipo, cioe' se alfa, numerico, ecc.) che e' autoesplicativo. Non esistono campi "calcolati" perche' in 4D ci sono funzioni molto piu' potenti che vedremo in seguito. L'unica nota particolare e' che Tables e Fields non si possono piu' cancellare. Se crei un Table (un file) che poi non ti serve lo lasci dove si trova e basta, semmai lo utilizzerai in seguito se servira'; se non aggiungi records non occupa nemmeno memoria dati. Se in un Table crei un campo che non ti serve, e' bene usare qualche accortezza per evitare di trovarselo tra i piedi: primo dagli un nome che ricordi che e' inutile (per esempio "spurio") poi impostalo come invisibile cosi' non compare inutilmente in giro e poi imposta il type come booleano che e' il type che occupa meno memoria (in RAM e su disco). Nota che i nomi di Tables e Fields si possono cambiare quando si vuole. |
1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
QPix: ottenere informazioni su un'immagine
Il comando PICTURE PROPERTIES permette di ottenere, direttamente da linguaggio quindi, informazioni sulla dimensione in pixel di un'immagine, ma non la sua risoluzione in dpi e/o la profondità di colore. Per ottenere queste informazioni è possibile usare le funzioni di QPix QPx_GetImageFileInfo e QPx_GetPictureInfo (per un'introduzione a QPix è possibile consultare questa faq). I parametri che usano sono simili e la sintassi è praticamente identica. Entriamo nel dettaglio. La sintassi è: QPx_GetImageFileInfo(imagePath; imageWidth; imageHeight; pixelDepth; hRes; vRes) e QPx_GetPictureInfo(pictVar; pictWidth; pictHeight; pixelDepth; hRes; vRes) dove: - imagePath è il percorso al file di cui vogliamo ottenere le informazioni; - pictVar è invece la variabile 4D che contiene la pict di cui vogliamo ottenere informazioni; - pictWidth e pictHeight vengono riempiti dai comandi con i valori relativi la larghezza e altezza dell'immagine; - pixelDepth viene riempito con un valore che rappresenta la profondità di colore dell'immagine (1 per il bianco e nero, 2 8 16 24 e 32 per le immagini a colori, 34 [2 bit], 36 [4-bit], 40 [8 bit] per le immagini a scala di grigi); - hRes e vRes vengono riempiti con la risoluzione orizzontale e verticale dell'immagine espressa in dots per inch (dpi). Vediamo un esempio di uso di QPx_GetImageFileInfo `Ottenere info su un'immagine da file C_LONGINT($error) C_TEXT($imagePath) C_LONGINT($width;$height;$depth;$hRes;$vRes) $imagePath:="Hard disk:Barocco in Sicilia:Contea di Modica:Montalbano:San Pietro.gif" $error:=QPx_GetImageFileInfo ($imagePath;$width;$height;$depth;$hRes;$vRes) If ($error=qpx_noErr) `usa i dati ottenuti End if Un esempio per QPx_GetPictureInfo: `Info su una pict C_LONGINT($error) C_PICTURE($picture) C_LONGINT($width;$height;$depth;$hRes;$vRes) $picture:=[Chiese di Modica]Immagine $error:=QPx_GetPictureInfo ($picture;$width;$height;$depth;$hRes;$vRes) If ($error=qpx_noErr) `usa i dati ottenuti End if |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Controllare i privilegi di accesso della struttura
Installando una struttura sul server potrebbe capitare (n funzione del tipo di collegamento usato) che i privilegi di accesso si impostino in modo tale che l'utente corrispondente al 4D Server non abbia accesso in scrittura (cioé sia in Sola Lettura). Poiché il tutto sembra funzionare e le modifiche alla struttura (di programmazione o anche di modifica delle liste o delle passord, per esempio) resterebbero online fino alla chiusura del programma; a quel punto 4d Server tenta di registrarle ma non riesce. Ecco una procedura da installare nel metodo "On Startup Server" che esegue un controllo ed eventualmente avvisa l'utente della cosa prima di chiudersi (i nomi delle variabili non sono significative, per cui sono stati lasciati brevi): Error_l:=0 ON ERR CALL("CatturaErrori") GET DOCUMENT PROPERTIES(Structure file;lck_b;inv_b;cr_d;cr_h;md_d;md_h) SET DOCUMENT PROPERTIES(Structure file;lck_b;inv_b;cr_d;cr_h;md_d;md_h) ON ERR CALL("") If (Error_l =-5000) ALERT("Attenzione, controlla i privilegi di accesso alla struttura.") QUIT 4D End if Ci vuole anche il methodo “CatturaErrori” Error_l:=Error `Error contiene l'errore intercettato, e lo copia nella variabile usata dopo Suggerito da Thomas Schlumberger, 4d Francia |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Come avere la Ricevuta di Ritorno nelle mail
E' possibile inviare mail con 4D richiedendo la notifica di ricezione. Basta inserire un Header come da esempio: Disposition-Notification-To: "XXXXX" <XXXX@TTTTTT.YY> Dove la parte destra è l'indirizzo a cui si vuole che giunga la notifica. Per inserire lo header si devi usare il comando: SMTP_AddHeader (smtp_ID; headerName; headerText{; deleteOption}) Integer Parameter Type Description smtp_ID Longint Message reference headerName String Name of header headerText Text Header text deleteOption Integer 0 = Add 1 = Replace all headers 2 = Remove all headers Function result Integer Error Code esempio: $err:=SMTP_AddHeader($SMTP_ID;"Disposition-Notification-To:"l.larosa@italsoftware.it";1) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Stile |
Accedere ad un array da metodi o processi diversi
In 4th Dimension non è possibile passare un array come parametro ad un metodo o ad un processo in maniera diretta. Esistono comunque due modi per superare questo ostacolo: 1) il più semplice è quello di passare come parametro al metodo chiamato un puntatore all'array. Questo sistema funziona solo con array processo o interprocesso. Ad esempio: ` Method1 Method2 (->MyArray) ` Method2 C_POINTER($1) Questo metodo è molto usato anche perché i cambiamenti apportati dal Method2 sono condivisi dal Method1. 2) il metodo più affascinante è invece sicuramente quallo di riversare l'array in un blob. Questo approccio risulta molto utile soprattutto nelle chiamate fra processi diversi con array non interprocesso, e più in generale quando comunque non risulta necessario che gli array dei due metodi siano "lo stesso array", a differenza del caso precedente. Ovviamente, nella comunicazione tra processi diversi, il passaggio di un puntatore ad un array locale o di processo come parametro non funzionerebbe. Vediamo un esempio di questo uso: ` Method1: VARIABLE TO BLOB (MyArray;vBlob) $id_l:=New process ("Method2";32000;"ProcessName";vBlob) Il Method2 inizierà così: ` Method2 C_BLOB($1) ARRAY LONGINT(MyArray;0) BLOB TO VARIABLE ($1; MyArray) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Uso di SET COLOR in un output form
Capita spesso che sia necessario già in fase di visualizzazione della lista dei record consentire una analisi di un certo dato della tabella. Ad esempio il programma potrebbe far vedere con colori diversi nella lista le ragioni sociali dei clienti che non acquistano da più di 60 giorni. Nell'object method del campo Ragione scriveremo: If ((Current date-UltimoAcquisto)>60) SET COLOR(Ragione;-256*Red ) Else SET COLOR(Ragione;-Black ) End if Però le righe vuote alla fine della lista avranno il colore dell'ultimo record visualizzato e non quello standard (qui il nero). Per sistemare questo intanto inseriamo nel metodo del form il seguente codice: If (Form event=On Header ) SET COLOR(Ragione;-Black ) End if |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Riconoscere un anno bisestile *
Ecco un piccolo frammento di codice che prende in input un numero e restituisce True se l'anno rappresentato dal numero è bisestile: C_BOOLEAN($0) C_LONGINT($1;$anno_l) $anno_l:=$1 $0:=True Case of : (Dec($anno_l/400)=0) `è bisestile, come il 2000 : (Dec($anno_l/100)=0) `non è bisestile, come il 1900 $0:=False : (Dec($anno_l/4)=0) `è un anno bisestile Else $0:=False End case |
1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Stile |
Usare il nome del metodo come nome del processo
Esistono molti vantaggi nell'usare il nome del metodo che lancia un processo come nome del processo stesso, cioé con una sintassi del tipo: $id_l:=New process("P_Calcola";32000;"P_Calcola") Eccone alcuni: - conosco sempre l'id del processo senza usare variabili interprocesso, e quindi è valido scrivere: If (Current process=Process number("P_Calcola")) `quello che serve End if - nel Runtime explorer so perfettamente quale metodo fa partire un certo processo: hanno lo stesso nome! - e, molto interessante, per far partire un processo non ho bisogno di scrivere due metodi separati, ma uno solo: Case of : (Current process#Process number("P_Calcola")) $id_l:=New process("P_Calcola";32000;"P_Calcola") : (Current process=Process number("P_Calcola")) `quello che deve fare End case Ancora maggiori diventano i vantaggi se a tutto questo si associa anche l'uso di Current method name Fonte: 4D Today, John Baughman |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Calcolo del numero della settimana *
Seguendo le regole dell'Iso 8601: - il primo giorno della settimana è Lunedì - una settimana è contata nellanno in cui stanno la maggior parte dei giorni - E possibile avere anche anni con 53 settimane Propongo una soluzione, da testare: $d:=Date("04-01-"+String(Year of(Current date))) $0:=Int((Current date-(1+$d-Day number($d)+(7*Num(Day number($d)>4))))/7)+1 Si sarebbe potuto scrivere su più righe per essere più chiari, o in una riga sola per essere più concisi... |
1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Storico annuale di un database
Una soluzione semplice per chi ha poco tempo da dedicargli, sperimentata da me, è questa: - fare una copia del db chiamarlo "Storico2003.db" - da Storico2003.db togliere a tutti utenti il privilegio di scrittura, se il tuo db ha una gestione "personalizzata" dei privilegi. Altrimenti creare un gruppo "Consulta" e spostare gli utenti li dentro, creare un gruppo Admin dove c'è solo Designer ed Administrator. Dalla struttura per ogni tabella che ti interessa mantenere in sola lettura fare doppio clic e nella Table properties-Privileges : impstare le opzioni load Record gruppo Consulta, Save, Add, Delete: Gruppo Admin - aprire (se non ci sono limitazioni dell' hardware: disco già troppo pieno, scarsa potenza della macchina server) "Storico2003.db" sulla stessa macchina server dove è il database originale ancora utilizzato in aggiornamento. (vedi la faq Eseguire più 4d Server sulla stessa macchina su questo sito) - dall'originale si può fare una sorta di pulizia cancellando tutti i dati vecchi, compattando e rimettendo su un originale più snello. Non è elegantissima ma permettere di non scrivere nessuna riga di codice e di avere la stessa interfaccia utente nello storico e nel db originale; inoltre l'utente quando apre il client può velocemente scegliere se consultare lo storico o lavorare sul db aggiornato. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Macro |
4D 2004: creare un separatore nell'elenco delle macro
In 4D 2004 è possibile separare l'elenco delle macro con una linea. Per fare questo basta creare una nuova macro il cui nome sia semplicemente "-" (il trattino) e che come testo abbia il seguente: <macro name="-"> <text> </text> </macro> Posto questo testo nel file macro, verrà visualizzata nell'elenco delle macro una linea non selezionabile. Ciò aiuta ovviamente a rendere più leggibile l'elenco. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Utilizzare le impostazioni di Import/Export salvate
La finestre standard di Importazione/Esportazione permettono di salvare le impostazioni scelte, registrando: - il nome file e il suo percorso - le tabelle e i campi selezionati - il nome del layout se selezionato o le altre impostazioni come tipo di file, delimitatori di campo e di record, etc Dopo aver impostato queste opzioni basta salvarle (su Windows l'estensione è .4SI) usando il pulsante di registrazione nella toolbar della finestra di dialogo. Questa impostazione può esere ricaricata con il pulsante di Load oppure da programma caricandole in un blob. Per esempio: C_BLOB($impostazioni_blb) DOCUMENT TO BLOB("FileRegistrato";$impostazioni_blb) `qui le carico IMPORT DATA("NomeFile";$impostazioni_blb) `qui le uso |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novita' |
4D 2004: i file per l'help in linea
Nelle versioni precedenti di 4D in cui era previsto un help in linea direttamente da method editor per il programmatore, il file 4D Help (MacOS) o 4D Help.rsr (Windows) doveva essere posto nella cartella di sistema di 4D (per i ragguagli sull'argomento si può consultare questa faq). Per semplificare gli aggiornamenti, con la nuova versione di 4th Dimension il file si chiama adesso 4D Syntax.rsr su entrambe le piattaforme e deve essere inserito nella cartella 4D Extensions della applicazione 4D. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Macro |
4D 2004: esempio di uso delle macro
Vediamo un esempio che dimostri l'uso delle macro in 4D 2004: il nostro scopo nell'esempio è creare un record, inizializzarne i valori e infine salvarlo. Quando chiamiamo una macro 4D gestisce una serie di variabili di input (_textSel, _blobSel, _selLen, _textMethod, _blobMethod, _methodLen) con le quali possiamo conoscere, per esempio, il testo selezionato nel metodo in cui stiamo chiamando la macro, e una serie di variabili di output (_textReplace, _blobReplace, _action), con cui gestire il testo da generare. Supponiamo allora di scrivere la macro "Init_record" che chiami il metodo "Init_macro_record" in questo modo: <macro name ="Init_record"> <text> <method>Init_macro_record</method> </text> </macro> Ecco adesso il codice del metodo Init_macro_record: C_TEXT(_textSel;_textReplace) C_TEXT($text) $text:=_textSel $start:=Position("[";$text) If ($start>0) $text:=Substring($text;$start) $end:=Position("]";$text) If ($end>0) $text:=Substring(_textSel;1;$end) $table:=0 For ($i;1;Count tables) If ($text=("["+Table name($i)+"]")) $table:=$i $i:=Count tables+1 End if End for $br:=Char(Carriage return) $to_insert:=Command name(68)+"("+$text+")"+$br `68 = CREATE RECORD command For ($i;1;Count fields($table);1) $field:=$text+Field name($table;$i) $type:=Type(Field($table;$i)->) Case of : ($type=Is Alpha Field) | ($type=Is Text) $to_insert:=$to_insert+$field+":=\"\""+$br : ($type=Is Real) | ($type=Is Integer) | ($type=Is Longint) $to_insert:=$to_insert+$field+":=0"+$br : ($type=Is Date) $to_insert:=$to_insert+$field+":=!00/00/00!"+$br : ($type=Is Time) $to_insert:=$to_insert+$field+":=?00:00:00?"+$br : ($type=Is Boolean) $to_insert:=$to_insert+$field+":="+Command name(215)+$br `215 = False command : ($type=Is Picture) $to_insert:=$to_insert+Command name(286)+"($pict)"+$br `286 = C_PICTURE command $to_insert:=$to_insert+$field+":=$pict"+$br : ($type=Is BLOB ) $to_insert:=$to_insert+Command name(604)+"($blob)"+$br `604 = C_BLOB command $to_insert:=$to_insert+$field+":=$blob"+$br End case End for _textReplace:=$to_insert+Command name(53)+"("+$text+")"+$br `53 = SAVE RECORD command _action:=1 Else _action:=0 End if Else _action:=0 End if A questo punto basta selezionare in un metodo il nome di una tabella e chiamare la macro: il nome della tabella verrà sostituito da testo desiderato! |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Macro |
Cosa sono le macro?
Una macro è una porzione di codice 4D (e quindi anche righe di commento) che può essere inserita in qualsiasi momento nei metodi, specialmente per evitare la riscrittura della parti ripetitive (come ad esempio i cicli For, While, Repeat). La macro è abbastanza intelligente da usare la selezione corrente come parametro: poiché sono memorizzate in file XML, ci sono dei tag speciali che vengono sostituiti al momento dell'inserimento della macro in base al contesto di metodo. Con 4D 2004 è possibile anche lanciare metodi di 4d dall'interno della macro stessa per avere delle funzioni più complesse e personalizzate. Per poter richiamare codice 4D con un method è stato aggiunto il nuovo tag: "<method> </method>". |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Macro |
4D 2004: il 4D 2004 Macro Pack
4D inc ha annunciato giovedì 16 settembre 2004 il rilascio di 4D 2004 Macro Pack, una collezione free di 17 macro per l'ambiente di sviluppo. Le macro, che possono essere conservate come file XML, possono generare il codice più usato ed aiutare i programmatori a lavorare in modo più rapido. Fra le macro incluse: Doc 4D, per generare la documentazione di API; Modularize, che aiuta a ridurre grandi metodi in metodi più piccoli; DeclareSoap, che trasforma metodi 4D in metodi per Web service; e CreateObject, che genera script che possono accedere a oggetti COM. 4D 2004 Macro Pack è disponibile nella versione Win a questo indirizzo: ftp://ftp.4d.com/PRODUCTS/4D/Current/4D_2004/Windows/Macro_Pack.exe Nella versione mac a quest'altro: ftp://ftp.4d.com/PRODUCTS/4D/Current/4D_2004/MacOS/Macro_Pack.sit I pacchetti includono la documentazione dettagliata. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novita' |
4D 2004: i form event delle List box
Con l'avvento delle List box hanno fatto la loro comparsa sette nuovi form event: - On Before Data Entry: generato prima che il cursore venga mostrato in una cella; - On Selection Change: generato ogni volta che viene cambiato l'insieme delle righe selezionate (l'evento è valido anche per le liste di record e le gerarchiche); - On Column Moved: generato quando una colonna viene spostata (e il comando MOVED LISTBOX COLUMN NUMBER restituisce la nuova posizione); - On Row Moved: lo stesso ma per le righe (e il comando correlato è MOVED LISTBOX ROW NUMBER); - On Column Resize: generato quando di una colonna viene modificata la larghezza (o col mause o col comando SET LISTBOX COLUMN WIDTH); - On Header Click: generato quando si clicca sull'intestazione della colonna (è ciò può anche generare l'ordinamento della stessa); - On After Sort: generato dopo un ordinamento. Inoltre un evento On Clicked viene generato ogni volta che si clicca su un elemento della list box o sull'intestazione col tasto di destra (Ctrl+clic su MacOs). |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novita' |
4D 2004: introduzione all'uso delle ListBox
Le "List box" possono essere definite come la naturale e attesa evoluzione delle "Scrollable area" raggruppate o, dall'altra parte, l'inglobamento nella versione standard di 4th Dimension di alcune caratteristiche presenti in 4D View. Fino ad oggi, infatti, i sistemi per mostrare a video il contenuto di un array erano due: o avere delle scrollable area, ognuna chiamata come l'array da mostrare, che dovevano poi essere raggruppate in modo da poter scorrere gli array in maniera "sincronizzata" con un'unica barra di scorrimento, con però le limitazioni create da questo approccio (ad eempio, per avere delle linee orizzontali queste dovevano essere disegnate manualmente e aggiornate per esempio con un timer in modo da non essere nascoste, oppure inserire un bottone invisibile sugli array raggruppati per impedire il clic), oppure usare 4DView in maniera da personalizzare notevolmente l'interfaccia, usando però uno strumento a pagamento potentissimo per una cosa relativamente semplice. Le List box consentono adesso di avere dei dati raggruppati come le scrollable area, ma con funzioni aggiuntive, tipo l'inserimento di valori, ordinamenti, alternanza di colori, ecc. Le proprietà delle List box sono settabili sia via Form editor che direttamente la linguaggio di programmazione, da dove quindi è facile ad esempio aggiungere, togliere o scambiare array visualizzati. Ecco un elenco dei nuovi comandi del linguaggio di programmazione: INSERT LISTBOX COLUMN DELETE LISTBOX COLUMN Get number of listbox columns SORT LISTBOX COLUMNS SET LISTBOX COLUMN WIDTH Get listbox column width SELECT LISTBOX ROW INSERT LISTBOX ROW DELETE LISTBOX ROW Get number of listbox rows SET LISTBOX ROWS HEIGHT Get listbox rows height MOVED LISTBOX ROW NUMBER GET LISTBOX ARRAYS Get listbox information SHOW LISTBOX GRID SET LISTBOX GRID COLOR SHOW LISTBOX SCROLLBAR MOVED LISTBOX COLUMN NUMBER |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Due problemi fissati nella 2003.4
Nella versione 2003.4 appena uscita ci sono due correzioni molto interessanti specialmente per gli svilupatori, che riguardano il method editor: - inserendo un commento all'inizio di una riga, la riga commentata si spostava al rigo precedente; - effettuando la selezione del testo di un metodo con maiuscolo+frecce, se si selezionava il testo al di fuori della zona attualmente selezionata, non veniva effettuato uno scroll contemporaneo per vedere fino a dove si eseguiva la selezione (come un qualsiasi editor di testo), ma la visualizzazione restava immutata. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novita' |
4D 2004: Impostare le opzioni di stampa in 4D Write
Seguendo l'esempio dato dal comando SET PRINT OPTION dalla versione 2003, adesso anche 4D Write permette di settare da linguaggio di programmazione le impostazioni di stampa usando il comando WR SET PRINT OPTION. La sintassi del comando è: WR SET PRINT OPTION (area; option; value1{; value2{; value3}}) dove area è l'area di 4DWrite, option è l'opzione da settare e i valori value1, value2 e value3 sono i valori che possono essere assegnati ad option. Le costanti utilizzabili nel parametro option ricalcano molto da vicino le costanti del già citato comando SET PRINT OPTION; in aggiunta notiamo però la presenza delle due costanti wr pages from option e wr pages to option, che permettono di definire da quale pagina a quale pagina effettuare la stampa. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novita' |
4D 2004: creare un nuovo elemento in un array
Per aggiungere un elemento ad un array, siamo sempre stati abituati nei nostri software 4D a scrivere: INSERT ELEMENT($mioarray;Size of array($mioarray)+1) $mioarray{Size of array($mioarray)}:=$ilvalore Dalla versione 2004 di 4D tutto questo viene sostituito dall'unica istruzione APPEND TO ARRAY che accetta come parametri il nome dell'array e il valore che deve assumere l'elemento aggiunto all'array. In modalità interprete, se l'array non esiste viene creato, in relazione al valore passato come parametro. Il comando funziona con tutti i tipi di array. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Help in linea di 4D [4] : 4D Help Html
Un Help in linea molto completo è quello in versione HTML consultabile con un browser. Questo tipo di Help si richiama premendo il tasto funzione F1 dopo aver selezionato un comando 4D (su Windows non dovrete aver installato 4d.HLP). Viene aperto il vostro browser e mostrata una pagina con la sintassi e tutte le informazioni utili sul comando scelto. Da questa finestra utilizzando i vari link è possibile consultare tutti i comandi di 4D, in pratica il Language Reference, e tutte informazioni di maggior utilità sui vari programmi e Plugin che fanno parte delle soluzioni 4th Dimension. Tutto ciò è contenuto nella cartella Documentation (di 54,9 Mb): i file si possono scaricare dall' ftp di 4D.com (versione Macintosh o Windows) oppure copiare dal CD di installazione. Copiata la cartella sul disco (magari nella stessa folder dove avete messo l'applicativo), per poter richiamare in maniera veloce questo Help come sopra spiegato bisogna specificare a 4D dove si trovano i documenti HTML dal menu: 4th Dimension | Preferences | Design mode | Documentation qui scegliere Local folder e sfogliare il percorso fino alla vostra cartella Documentation. |
1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novita' |
4D 2004: il comando GET SERIAL PORT MAPPING
Tramite questo comando è finalmente possibile avere due array con i nomi e i codici delle porte seriali attive, specialmente utile in situazioni dove è importante sapere quando si usano adattatori seriali sulle porte USB. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novita' |
4D 2004: 4D Server come servizio su Mac OS X
Adesso anche su Mac è diventato molto semplice eseguire 4D Server come servizio: basta scegliere nel menu File di 4D Server la voce Register Current Database as Service: la volta successiva che il server verrà avviato, 4D Server verrà lanciato automaticamente usando il database corrente. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Utilizzo del modo tabella di Quick Report
Ipotizziamo di avere un archivio che contiene i movimenti di vendita. In questo archivio avremo il codice articolo, il codice cliente e il valore della vendita. Vorremmo ottenere un report che riporti nelle colonne i clienti, nelle righe gli articoli e nella cella di incrocio il valore del singolo articolo per il corrispondente cliente. Aprendo il report e selezionando tabella si presenta l'editor dello stesso, che presenta 3 colonne e 3 righe. La prima cella serve solo per selezionare tutto il report. La prima cella della seconda colonna è quella in cui andremo a mettere il campo cliente. Per farlo tenete premuto il tasto control e all'apparire del menu selezionate "modifica". All'apertura del layout di modifica inserite il campo del file a cui si riferisce il cliente. La seconda cella della prima colonna è quella in cui andremo ad inserire il campo articolo, per inserirlo procedete come sopra. Nella seconda cella della seconda colonna dobbiamo inserire il campo che vogliamo totalizzare, per farlo procedete come sopra. Ora se vogliamo tutti i totali di riga e colonna selezionate la prima cella e cliccate sul bottone di totalizzazione. Il report è finito, provate a stampare e otterrete tante colonne quanti sono i clienti che hanno acquistato e tante righe quanti sono gli articoli venduti, con il totale per cliente/articolo e i relativi totali di righe e colonne. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Mettere una formula nel subtotal di Quick Report *
Anticipo che il titolo non è proprio veritiero, nel senso che quanto scritto è possibile solo passando poi da excel. L'esempio è avere un report che riporti le vendite di quest'anno paragonate alle vendite dell'anno passato calcolando il delta. Nel nostro report avremo una colonna con le vendite1 una colonna con le vendite 2 e una colonna calcolata 100-(vendite1*100)/vendite2). Se volessimo avere un break per regione non esiste sistema per poter calcolare il delta nel subtotal. Il sistema che ho trovato si basa sul fatto che se scriviamo nel subtotal all'interno della cella della terza colonna una formula che non sia una delle sue, quick report riporta pari pari la scritta. In excel esiste la funzione "R1C1 reference style" che deve essere settata, fatto questo nella nostra cella possiamo mettere "=100-((RC1*100)/RC2)" senza apici. Se questo report lo esportiamo come HTML e lo apriamo con Excel avrete il risultato anche nel subtotal. Uso html per il mantenimento della grafica. |
1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Cambiare dinamicamente gli Help Messages *
Forse non tutti sanno che è possibile modificare il contenuto degli Help Messages (le micro finestre gialle che forniscono info sugli oggetti dei forms posizionando il cursore su di essi) in modo dinamico e sensibile al contenuto o al contesto. Basta applicare la già nota tecnica illustrata nell'articolo "Displaying variables and field values in Text objects" presente nell'elenco 4D Tech Tips della home: - dedicare una variabile Text a questo scopo, per esempio vTxt_OKbuttonHelp - nella finestra di definizione dell'oggetto aprire il tab all'ultima posizione dove si impostano gli help messages - nel campo "Help message" inserire in nome della nostra variabile tra i caratteri "<" e ">" così < vTxt_OKbuttonHelp > l'help mostrerà ora il contenuto della variabile che può essere definito da codice, per esempio: If (MyField # "") ENABLE BUTTON(vBt_OK) vTxt_OKbuttonHelp:="Conferma la scheda e registra le modifiche" Else DISABLE BUTTON(vBt_OK) vTxt_OKbuttonHelp:="Conferma la scheda, non attivo perchè mancano dei dati" End if |
1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novita' |
4D 2004: comandi da terminale
Avvio del programma (la & in fondo lo apre in un processo a parte): /MiaCartella4D/4th\ Dimension.app/Contents/MacOS/4th\ Dimension & Per avere l'elenco dei parametri possibili: /MiaCartella4D/4th\ Dimension.app/Contents/MacOS/4th\ Dimension -h Con una struttura: /MiaCartella4D/4th\ Dimension.app/Contents/MacOS/4th\ Dimension /Users/umigliore/db/MioDB/MioDB.4DB Con una struttura e una base dati: /MiaCartella4D/4th\ Dimension.app/Contents/MacOS/4th\ Dimension -d /Users/umigliore/db/MioDB/MioDB.4DD /Users/umigliore/db/MioDB/MioDB.4DB Con un nome utente e gruppo diversi: /MiaCartella4D/4th\ Dimension.app/Contents/MacOS/4th\ Dimension -u umigliore -g admin Chiudere il programma: Kill -s INT numero_del_processo |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novita' |
4D 2004: raggruppare i radio button
Una nuova caratteristica interessante nella fase di disegno di un form è la possibilità di raggruppare dei radio button semplicemente selezionandoli; uno degli aspetti più complicati dei radio button delle versioni precedenti di 4D era infatti rappresentato dal dover chiamare i radio button appartenenti allo stesso gruppo con un nome cominciante con la stessa lettera, il che comportava ovviamente anche una serie di limitazioni. Adesso con 4th Dimension 2004 basta selezionare i radio button da raggruppare e scegliere Group nell'Object menu. Convertendo i software da versioni precedenti può anche essere utile attivare o disattivare l'opzione delle Preferenze presente sotto la voce Application chiamata "Radio buttons grouped by name", per mantenere il vecchio metodo di raggruppamento. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novita' |
4D 2004: contare un certo elemento in un array
Fino alla versione 2003 di 4D per conoscere il numero delle volte in cui un valore compariva in esso era necessario sviluppare un algoritmo del tipo: Contatore:=0 For (dimensione dell'array) If (valore i-esimo dell'array = valore cercato) Contatore:=Contatore+1 End if End for Tutto questo viene adesso condensato nell'unica istruzione Count in array. Questo comando prende come parametri l'array in cui contare le occorrenze e il valore da cercare, restituendo un longint che rappresenta il numero di occorrenze del valore nell'array. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novita' |
4D 2004: gli oggetti Pulsanti
Le novità sono tante, tutte da provare giocando con il form editor: Stili: - Background Offset è lo stile 'ad incasso' dei 3D button nelle versioni precedenti - Push, standard del sistema operativo - Toolbar, per le toolbar :), su Windows si evidenzia passandoci sopra - Circle, per avere i pulsanti tondi su Mac - Small System Square, per avere i pulsanti piccoli su Mac - Office XP, colori che si adattano al sistema, su Windows si evidenzia passandoci sopra - Bevel, come il Toolbar, ma con il triangolino del menu in basso a destra - Rounded Bevel, come sopra con gli angoli arrotondati su Mac - Custom, personalizzabile nelle immagini e posizionamenti di icone e scritta Icone: - le si possono aggiungere a qualsiasi degli stili sopra - icona e testo si possono allineare a sinistra, destra, sopra, sotto e al centro Pop-up menu - lo si può aggiungere ad alcuni stili sopra, sia attaccato che separato da un righino con diversi effetti in funzione dello stile Valore I pulsanti storicamente corrispondevano a variabili Intere, ma ora è possibile scegliere il valore Booleano, quindi la variabile è True (vero) se il pulsante è premuto o selezionato. Gruppi I pulsanti di selezione (radio buttons) ora si comportano (la selezione di uno deseleziona gli altri) controllando il gruppo a cui appartengono e non più soltanto per il loro nome. Eventi Ci sono due nuovi eventi: - On long Click segnala che il mouse è stato premuto per un certo tempo - On Arrow Click segnala che è stato premuto il pusantino del menu a comparsa utile se il pop-up menu è tenuto separato |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novita' |
4D 2004: Convertire in Base64 e viceversa
Con la versione di 4D 2004 sono presenti due comandi che permettono di convertire un blob di dati ( e quindi non solo un testo) in Base64 e viceversa. I comandi sono: ENCODE(blob_blb) DECODE(blob_blb) Attenzione che questi non verificano il contenuto del blob. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novita' |
4D 2004: Stampa sul server
E' finalmente possibile stampare dal server, ad esempio per produrre PDF. I comandi di stampa erano disabilitati specialmente per evitare che sul server di solito non usato da nessun utente apparissero eventuali messaggi di problemi sulla stampante (queste non genereranno errori nella 2004!) Ora funzionano i comandi Print Record, Print Selection, Print form, Set Print Option, Print Label, QR Report; ovviamente dove è possibile è necessario chiamarli con il parametro * per evitare le finestre di dialogo. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
4th Dimension, MS Access e FileMaker Pro [14] I sistemi operativi
Questo è un argomento su cui i tre sistemi differiscono molto. Access lavoro solo in ambiente Windows, mentre sia FileMaker Pro che 4D lavorano sia sotto Windows che sotto Mac OS. 4D, oltre a permettere di usare client Mac anche collegati a server Windows e viceversa, prevede la possibilità di scegliere stili e controlli diversi a seconda della piattaforma usata, e genera codice compilato specifico per ogni piattaforma. Inoltre il sistema di registrazione degli oggetti, sia le maschere che i record (vedi I Tag dei record e l'opzione Completely Deleted), è ottimizzato nell'utilizzo sulla stessa piattaforma pur mantenendosi pienamente compatibile e trasparente all'utente. Consulta da questo link l’indice delle faq su 4th Dimension, MS Access e FileMaker Pro |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Programma una ricerca sugli array!
Ecco uno spunto su come effettuare una ricerca su un array: nell'array di partenza vengono cancellati gli elementi che non servono, e così se la dimensione dell'array diventa zero, la ricerca ha risultato nullo. Al metodo vengono passati come parametri due puntatori, uno all'array (si suppone non vuoto, altrimenti bisogna aggiungere questo controllo) e uno all'elemento cercato. C_POINTER($1;$2;$puntatoreArray_ptr;$puntatoreValore_ptr) $puntatoreArray_ptr:=$1 $puntatoreValore_ptr:=$2 C_LONGINT($posizione;$PrimoDaControllare_l;$dimensioneArray_l) $posizione:=1 $PrimoDaControllare_l:=0 Repeat $PrimoDaControllare_l:=$PrimoDaControllare_l+1 $posizione:=Find in array($puntatoreArray_ptr->;$puntatoreValore_ptr->;$PrimoDaControllare_l) If ($posizione>0) DELETE ELEMENT($puntatoreArray_ptr->;$PrimoDaControllare_l;$posizione-$PrimoDaControllare_l) End if Until ($posizione<0) $dimensioneArray_l:=Size of array($puntatoreArray_ptr->) If ($dimensioneArray_l>=$PrimoDaControllare_l) DELETE ELEMENT($puntatoreArray_ptr->;$PrimoDaControllare_l;($dimensioneArray_l-$PrimoDaControllare_l)+1) End if |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
4th Dimension, MS Access e FileMaker Pro [13] Le ricerche
In ambiente di Utilizzo dei tre sistemi le ricerche sulla base dati si eseguono nei seguenti modi: In Access le query sono degli oggetti definiti tramite una interfaccia dedicata prima del loro uso e memorizzati nella struttura. La versione SQL della query può essere visualizzata in una finestra a parte. In FileMaker Pro le ricerche sono effettuate usando la modalità di ricerca, che mostra la stessa maschera di consultazione con i campi liberi all'utente e da riempire con i criteri necessari. Una volta effettuata la ricerca è possibile utilizzarla negli script. In 4th Dimension, le ricerche sono effettuate sia come in FileMaker usando la modalità "Query by example" oppure definendo i vari criteri di ricerca con chiavi in And e Or tramite una maschera dedicata effettuando una "Query". I criteri di ricerca possono essere salvati in un file per essere richiamati quando necessario. Consulta da questo link l’indice delle faq su 4th Dimension, MS Access e FileMaker Pro |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Creazione di un codice di controllo CRC
Il codice di controllo CRC, Cyclic Redundancy Check, serve a controllare l'integrità di un insieme di dati, sia esso un file, un pacchetto di bit sulla rete, il testo di una email. La procedura proposta è ricavata dalla Nota Tecnica di 4d 99-11, dove viene spiegato il processo di calcolo del CRC: in pratica si dividono con operazioni binarie tutti i byte dell'insieme di dati per un polinomio di partenza e si conserva il resto come codice di controllo (o checksum). In pratica è quasi impossibile che una modifica ai dati diano come risultato lo stesso codice CRC. Il polinomio di partenza consigliato è quello usato nelle trasmissioni Ethernet e nel programma di compressione PkZip. C_BLOB($1;$blob) `contiene l'insieme di dati da controllare C_LONGINT($0;$CRC_L;$REG_L;$TOP_L;$i;$j) C_BOOLEAN(<>crc_setupFatto_b) `serve a controllare che il setup sia fatto almeno e solo una volta If (Not(<>crc_setupFatto_b)) `prepara una volta soltanto l'array con le operazioni di shift e XOR `con il polinomio usato come radice del CRC ARRAY LONGINT(<>crcTable_al;255) C_REAL($CRCSetup_r;$CRC32_r) $CRC32_r:=0x04C11DB7 `polinomio usato come base di calcolo For ($i;0;255) $CRCSetup_r:=$i For ($j;0;7) `bit shift a destra e XOR con il polinomio If (($CRCSetup_r & 1)=1) $CRCSetup_r:=(($CRCSetup_r >> 1) ^| $CRC32_r) Else $CRCSetup_r:=$CRCSetup_r >> 1 End if End for <>crcTable_al{$i}:=Abs($CRCSetup_r) End for <>crc_setupFatto_b:=True End if $CRC_L:=0xFFFFFFFF SET BLOB SIZE(vblob;BLOB size(vblob)+4;0x0000) $REG_L:=BLOB to longint(vblob;0) For ($i;0;BLOB size(vblob)-5) $TOP_L:=(($REG_L >> 24) & 0x00FF) $CRC_L:=<>crcTable_al{$TOP_L} $REG_L:=(($REG_L << 8) | vblob{$i+4}) ^| $CRC_L End for $0:=Abs($REG_L) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
Il comando FTP_GetDirList
Il comando FTP_GetDirList restituisce un elenco di oggetti contenuti in una directory di una sessione ftp identificata da un ftp_ID ottenuto tramite il comando FTP_Login (deve essere ovviamente anche valida, il che si controlla usando FTP_VerifyID). Le informazioni su nome, dimensione, tipo e data di modifica vengono restituite in 4 array. La cartella passata come parametro diventa la cartella corrente della sessione ftp. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
4th Dimension, MS Access e FileMaker Pro [12] Gestione delle transazioni
Col termine transazione (transaction) definiamo la possibilità di raggruppare in un unico "blocco" una serie di modifiche apportate ai dati: tanto per dare un esempio, immaginiamo un classico schema con due tabelle, fatture e righe fatture: ovviamente se creo una fattura, aggiungo delle righe fattura e poi non registro la fattura, desidererei che neanche le righe venissero salvate: gestire queste operazioni in automatico come un'unica mega-operazione va proprio sotto il nome di transazione. Ora, molto semplicemente, Access e 4th Dimension supportano le transazioni, FileMaker no. Consulta da questo link l’indice delle faq su 4th Dimension, MS Access e FileMaker Pro |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
I Tag dei record e l'opzione Completely Deleted
I tag si trovano nei primi 4 caratteri di ogni record salvato su disco e ne identificano il tipo: - $4444: record creato su Mac, versione prima della 6.x - $4447: record creato su Mac, versione 6.x e successive - $5555: record creato su Windows - $0000: record cancellato Il tipo di record è importante perché viene mantenuto l'ordine dei byte come usato su ogni piattaforma; su Mac i byte sono scritti e letti da destra a sinistra, cioè a destra sta la parte meno significativa, per cui il numero esadecimale $0100 equivale al decimale 256, mentre su Windows la modalità è inversa lo stesso va letto invece come il decimale 1. Il tag $0000 viene scritto quando il record è cancellato e viene lasciata nella definizione della tabella (in Struttura) l'opzione "Completely Deleted". Quando un record viene cancellato è segnalato innanzitutto in una lista ad accesso veloce (bit table), poi 4D va a cercare il record per cambiare il tag. Se in una tabella si prevede di fare molte cancellazioni, ad esempio si tratta di una tabella temporanea usata per importare ed esportare i record, è possibile avere una maggiore velocità di cancellazione togliendo l'opzione "Completely Deleted"; l'unico effetto negativo di questa operazione è che se per caso si fosse costretti a recuperare la base dati con l'opzione "recupera per tag", 4D non potrebbe riconoscere i record cancellati e li recupererà per intero. Quindi per tutte le tabelle dove i dati sono fondamentali è meglio lasciare questa opzione selezionata. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
4th Dimension, MS Access e FileMaker Pro [11] Mantenimento di un db multiutente
Una delle differenze maggiori fra i tre sistemi presi in considerazione è il modo in cui vengono gestiti e memorizzati applicazione (tabelle, form, metodi/script/macro) e dati. Nella configurazione classica, FileMaker Pro ha un file per ogni tabella dell'applicazione contenente tabella, form, script e dati. Questo sistema rende problematici gli aggiornamenti, poiché lo sviluppatore non può quindi effettuare modifiche al volo ma solo off-line, ed è costretto ad effettuare una esportazione/importazione dei dati per eseguire un aggiornamento. Access può memorizzare applicazione e dati in file separati. Per migliorare le prestazioni, molti sviluppatori scelgono di posizionare il file dati su un file server e una copia della struttura sui computer di ogni utente. Così è possibile lavorare off-line e installare le nuove versioni senza dover esportare e importare, ma risulta necessario aggiornare tutte le macchine. Si usano così spesso dei pacchetti di distribuzione, che d'altra parte aumentano i costi. Access può anche essere usato come client di un database SQL, operazione comunque costosa e complessa ed in ogni caso non risparmia il programmatore e l'utente dell'aggiornamento della struttura Access ad ogni modifica. Come Access, 4th Dimension mantiene in file separati struttura e dati, ma entrambi vengono serviti direttamente da 4D Server. 4D Server ha prestazioni nettamente superiori a quelle di un file server, poiché tutte le operazioni vengono svolte sul server, senza intasare così la rete. Consulta da questo link l’indice delle faq su 4th Dimension, MS Access e FileMaker Pro Unica installazione Quando viene installata una nuova versione di un programma sul server, al primo login ogni utente sarà automaticamente aggiornato alla versione attuale. 4D usa in modo assolutamente trasparente per l'utente una cache locale quando l'utente accede ad una parte dell'applicazione: ciò aumenta le performance in maniera davvero considerevole. Modifiche on line Inoltre è possibile programmare su una struttura anche mentre viene utilizzata; ogni modifica fatta alla struttura viene subito riportata su tutti i client collegati. E' cioè possibile ad esempio aggiungere un campo, modificarlo da numero Longint a tipo Stringa, visualizzarlo nelle maschere di inserimento o nelle liste e l'utente se lo ritroverà senza dover interrompere il suo lavoro! Questa è l'argomento principale dove 4th Dimension mostra dei vantaggi e delle prestazioni nettamente migliori rispetto ad entrambe le altre due piattaforme. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Transazioni
Le transazioni rappresentano una serie di modifiche fatte al database all'interno di un processo. Una transazione non è salvata nel database in modo permanente finché non viene validata. Se una transazione non viene completata, sia perché è stata annullata o a causa di qualche evento esterno, le modifiche non sono salvate. Durante una transazione, tutte le modifiche fatte al database all'interno di un processo sono salvate localmente in un buffer temporaneo. Se una transazione è accettata con VALIDATE TRANSACTION, le modifiche sono salvate in modo permanente. Se la transazione è annullata con CANCEL TRANSACTION, le modifiche non vengono salvate. Visto che nelle transazioni i record sono selezionati temporaneamente o creati con indirizzi temporanei, quando questa viene validata o annullata, la selezione di ogni tabella per il processo corrente diventa vuota. Per questa ragione è necessario fare attenzione ad usare le Named selection: se sono state create prima o durante una transazione potrebbero contenere indirizzi che dopo la tansazione non sono più corretti; la stessa attenzione bisogna averla nell'utilizzare i set, che si basano su una tabella binaria (di vero/falso) corrispondente agli indirizzi dei record. Non ci sono limiti teorici al numero di record che una transazione può contenere. Comunque, il primo limite che si può incontrare sarà quello della memoria disponibile. 4D prova a tenere le transazioni in cache; se diventano troppo grosse, 4D le salva in un file temporaneo. I file temporanei vengono salvati per default sul disco C: sotto Windows, sul disco con più spazio sotto Macintosh, oppure nella cartella indicata nelle preferenze del database (System Settings). |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Conversione da decimale a esadecimale
Il sistema più veloce per convertire in esadecimale un numero è il seguente: $esadecimale_t:=String($decimale_l;"&x") `es. 26 -> 0x1A oppure $esadecimale_t:=String($decimale_l;"&$") `es. 26 -> $1A |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
4th Dimension, MS Access e FileMaker Pro [10] Programmare una multiutenza
Occupiamoci della possibilità che un database debba essere utilizzato da più utenti contemporaneamente. Access uilizza un approccio di tipo file/server, in cui l'applicazione e/o i dati e/o Access stesso sono piazzati su un file server accessibile dagli utenti: questo comporta ovviamente che maggiori sono le richieste al file server, più lento è l'accesso al server stesso; inoltre se un client va in crash si potrebbe bloccare l'accesso a tutti. Normalmente superando i 4-5 utenti il programmatore Access deve prendere in considerazione l'uso di un SQL Server. Ogni copia di FileMaker Pro ha all'interno un protocollo di comunicazione proprietario punto-punto multiutente: in questo modo, per un numero ridotto di utenti e/o tabelle è possibile simulare un server senza che un server vi sia dedicato. D'altra parte, FileMaker Pro non è multiprocesso, e quindi la macchina che contiene il database può fare solo una operazione per volta: se un utente esegue una operazione lunga, gli altri utenti devono attendere che finisca prima di poter a loro volta agire. In queste situazioni risulta necessario FileMaker Server, che è realmente multiprocesso: sul server in questo caso vengono eseguite solo le operazioni sui dati. La multiutenza con 4D viene gestita da 4D Server, che fa diventare una applicazione stand-alone di 4D la corrispondente versione in modalità client-server reale. E' possibile creare dei file di login automatico al server (a questo riguardo vedi la faq Usare 4D Client come fosse l'Engine). Sul server di 4D è possibile lanciare delle Stored Procedure, cioè funzioni che sono eseguite solo sul server. Sono disponibili anche un certo numero di funzioni per scambiare variabili dal client al server, eseguire metodi da un client su un altro client, controllare che ogni singola connessione sia fatta da client, da odbc o da web. Consulta da questo link l’indice delle faq su 4th Dimension, MS Access e FileMaker Pro |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Chiudere i processi correttamente uscendo da 4D *
Il metodo On Exit Database viene eseguito all'uscita del database. Questo metodo viene eseguito da 4D quando viene eseguita un'istruzione QUIT 4D o quando viene scelta la voce di chiusura applicazione da menu. Se il metodo On Exit Database è vuoto, l'applicazione verrà chiusa immediatamente (senza tenere conto quindi delle operazioni attualmente in esecuzione), altrimenti, se contiene del codice, 4D attende per chiudersi che il metodo venga portato a termine: possiamo sfruttare questa attesa per far sì che i processi attivi vengano chiusi con cognizione. Intanto, all'apertura del database impostare la variabile booleana <>StoChiudendo_b impostandola a False. A questo punto nell'On Exit Database la impostiamo a True e "risvegliamo" ogni processo: <>StoChiudendo_b:=True For ($i;1;Count tasks) RESUME PROCESS($i) CALL PROCESS($i) End for Così facendo il programma sa che 4D sta per chiudersi: ragion per cui si dovrebbe programmare ogni metodo che usa dei cicli e che vogliamo sia chiuso correttamente in maniera tale da controllare lo stato di "chiusura" di 4D guardando il valore della variabile <>StoChiudendo_b. Per quel che riguarda invece i metodi dei form, visto come abbiamo scritto il metodo di chiusura, viene generato un evento On Outside Call che possiamo gestire: Case of : (Form event=On Outside Call) If (<>StoChiudendo_b) CANCEL ` o qualsiasi altra istruzione sia necessaria End if End case |
1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Aumentare la casualità del comando Random
Il comando Random restituisce un un numero a caso tra 0 e 32.767. Può capitare che il numero casuale che cerchiamo sia oltre questo limite. Inoltre il tipico uso che viene fatto del comando è quello di restituire un numero compreso in un certo intervallo. Ecco quindi un semplice metodo per aumentare le potenzialità del comando Random: C_LONGINT($minimo_l;$massimo_l;$1;$2) $minimo_l:=$1 $massimo_l:=$2 C_LONGINT($aCaso_l;$0) If ($minimo_l=$massimo_l) $aCaso_l:=(Random*Random) Else $aCaso_l:=((Random*Random)%($massimo_l-$minimo_l+1))+$minimo_l End if $0:=$aCaso_l |
1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Decriptate i dati protetti
Ecco come decriptare i dati protetti usando la chiave Public_Key.txt generata insieme alla relativa chiave privata: C_TEXT($1;$Decriptato_t) C_BLOB($Criptato_blb;$Pubblica_blb) TEXT TO BLOB($1;$Criptato_blb;3) DOCUMENT TO BLOB("Public_Key.txt";$Pubblica_blb) DECRYPT BLOB($Criptato_blb;$Pubblica_blb) $Decriptato_t :=BLOB to Text($Criptato_blb;Text without length) $0:=$Decriptato_t La variabile $Decriptato_t contiene così il testo decriptato. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Criptare il contenuto di un blob
Ecco un esempio su come criptare il contenuto di un blob, usando una chiave Private_Key.txt già generata: C_TEXT($1;$DaCriptare_t) C_BLOB($Criptato_blb;$Privata_blb) $DaCriptare_t:=$1 TEXT TO BLOB($DaCriptare_t;$Criptato_blb;Text without length) DOCUMENT TO BLOB("Private_Key.txt";$Privata_blb) ENCRYPT BLOB($Criptato_blb;$Privata_blb) BLOB TO DOCUMENT("Criptato.txt";$Criptato_blb) Così facendo il testo passato come parametro sarà memorizzato criptato nel file Criptato.txt. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Creazione delle chiavi di protezione dati SSL
Per utilizzare la funzione di protezione dei dati di 4D è necessario creare le chiavi RSA (pubblica e privata) che servano a criptare e decriptare i dati utilizzando l'agoritmo usato nel protocollo SSL. La modalità di uso è di tenere la chiave privata al sicuro e distribuire la chiave pubblica: quello che è criptato con una chiave può essere decriptato solo con l'altra. Ecco un veloce esempio: C_BLOB($Pubblica_blb;$b_Privata_blb) GENERATE ENCRYPTION KEYPAIR($b_Privata_blb;$Pubblica_blb) BLOB TO DOCUMENT("Public_Key.txt";$Pubblica_blb) BLOB TO DOCUMENT("Private_Key.txt";$b_Privata_blb) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Controllare le connessioni al Server
Utilizzando i metodi automatici del 4D Server è possibile controllare l'inizio e la fine di ogni collegamento, incluso ogni singolo nuovo processo avviato sul client. Se il metodo del Database On Server Open Connection esce con $0:=0 il processo potrà essere lanciato, altrimenti sul client apparirà l'errore passato come risultato. Ad esempio, per evitare ogni nuovo collegamento fra le nove di sera e le nove del mattino: ` Metodo Database On Server Open Connection C_LONGINT($0;$1;$2;$3) If ((?21:00:00?<=Current time) & (Current time<=?9:00:00?)) $0:=22000 Else $0:=0 End if I tre parametri passati sono gli id interni usati dal server per identificare lo user, la connessione e il protocollo internet usato. Non sono molto utili se non per utilizzarli alla fine della connessione nella On Server Close Connection |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
I tipi di Set e dove sono registrati
I set sono relativi ad una tabella e identificati da una stringa, che è meglio scegliere con accortezza; il set "miei" ha un nome poco significativo, mentre il set "Ordini Non Pagati" è già più chiaro. I set possono essere di vari tipi: - Set di processo, disponibili solo all'interno del processo dove sono stati creati, come ad esempio il set automatico "LockedSet" - Set interprocesso il cui nome inizia con i simboli <> o su Mac con il carattere ?; sono condivisi da tutti i processi Questi primi due tipi di set quando sono creati e usati agiscono sempre sul server; passano sulla rete solo quando il client usa il comando SAVE SET, LOAD SET o il COPY SET da o verso un set locale. - Set locali o Client il cui nome inizia con il simbolo del $ sono gli unici set conservati solo nel client e non sul server; il set UserSet è locale anche se non inizia per $: occorre fare attenzione perché non è possibile in situazione client-server combinarlo con un set di processo! Prima di utilizzarlo con i comandi INTERSECTION, UNION o DIFFERENCE farne una copia con COPY SET. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Componenti di 4D
I componenti sono creati usando l'Insider per isolare gruppi di procedure con una funzione specifica all'interno di una normale struttura di 4d. Dopo aver creato un componente è possibile distribuirlo come pacchetto a sé stante per installarlo in altre strutture.. I metodi possono essere impostati come: - privati (e invisibili allo sviluppatore che installa il componente), - protetti per i metodi che lo sviluppatore può richiamare ma non vederne il contenuto - pubblici utilizzabili e il cui contenuto è accessibile (ad esempio per i metodi che illustrano al programmatore come funziona il componente). Per un uso interno non ci sono grossi problemi, se si vuole distribuirli bisogna considerare con attenzione vari problemi di convivenza e specialmente se le procedure richiedono eventuali tabelle (il destinatario potrebbe essere restio ad avere nuove tabelle nella propria struttura) e i nomi delle variabili (con un buon prefisso si possono distinguere da eventuali altre variabili di processo o inteprocesso già esistenti nella struttura ospite). |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Le prestazioni di 4D Server con tanta RAM
Se si usa il 4D Server su un computer con molta RAM, potrebbe succedere che benchè sia molto veloce all'inizio diventi sempre più lento dopo ore o giorni di funzionamento continuo. Quando la memoria cache di 4D inizia ad essere poca, per default 4D Server (dalla versione 6.5 in poi) prima di scaricare dati dalla cache passa a comprimere tutti gli indici; in questo modo è possibile liberare memoria diminuendo la necessità di accesso al disco. Comunque se la Cache impostata è molto grande, dai 512 MB in su, l'operazione di comprimere e decomprimere gli indici potrebbe richiedere molto tempo di processore. In questo caso è più veloce semplicemente svuotare e ricaricare la cache quando necessario. Per disabilitare la funzione di compressione degli indici è possibile usare questo comando nel metodo di database On Server Startup: SET DATABASE PARAMETER(Index Compacting; 0) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
I Set e le selezioni di record
4D fornisce uno strumento molto efficiente per manipolare le selezioni di record di una tabella considerandole come insiemi non ordinati; dal punto di vista pratico è possibile registrare in un oggetto Set un elenco di puntatori ai record nella selezione. Li si usa per: - tenere temporaneamente da parte una selezione particolare per ripristinarla successivamente - per controllare cosa ha selezionato l'utente: in pratica ogni volta che 4d mostra una lista di record, sia in un form di output che in una subform viene automaticamente aggiornato un set "UserSet" - per controllare se dopo un APPLY TO SELECTION, ARRAY TO SELECTION e DELETE SELECTION qualche record bloccato in scrittura non è stato modificato, guardando il set automatico "LockedSet" - manipolare gli insiemi e quindi prendere l'unione, l'intersezione o fare la differenza fra due selezioni di record. Rispetto ad una Selection il set non mantiene l'ordine della selezione perchè è costituito solo da bit (vero/falso) che indicano se il record n-esimo è selezionato; contemporanemante occupano pochissimo spazio, ad esempio una selezione in una tabella di 800.000 record occupa solo 100K. I set si possono salvare su disco, ma non sono utilizzabili dopo molto tempo perchè conservano solo la selezione e non la ricerca fatta: ad esempio un set dei minori di 18 anni in una tabella anagrafica potrebbe essere da aggiornare già il giorno dopo. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novizi |
L'elemento scelto di un array
Se ho definito l'array arrProva e lo uso come nome di un oggetto tipo scrollable area in un form, posso utilizzare la variabile arrProva per conoscere l'elemento che l'utente ha scelto: se ha scelto il terzo elemento dell'array, arrProva sarà uguale a 3 e arrProva{arrProva} è il valore del terzo elemento dell'array. Nota: Esiste anche un elemento 0 degli array che normalmente non è usato. Quindi se dichiaro un array di 10 elementi, in realtà ne avrei a disposizione 11, ma è da sempre consigliato utilizzare gli elementi da {1} a {10}. L'elemento 0 viene solitamente usato con combo box o scrollable area: In questi casi il valore di arrProva{arrProva} sarà uguale al valore di arrProva{0}. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Web |
Servire le pagine web inesistenti con 4D
La parte web di 4D permette di servire o pagine fisiche o pagine generate da codice. Se non è possibile soddisfare la richiesta, 4D invia un mesaggio standard di pagina non trovata al browser. È però possibile modificare questa pagina aggiungendo una risorsa alla struttura nella maniera che segue: - aprire 4D su Mac con un editor di risorse; - copiare la risorsa Html numero 45 nella struttura; - copiare il contenuto della risorsa in un editor html o un editor di testo per effettuare le modifiche; - copiare di nuovo l'HTML modificato nella risorsa. A questo punto la pagina servita per le pagine non trovate sarà quella da noi modificata. |
1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
È un numero?
Ecco una piccola porzione di codice per controllare se una stringa, passata come parametro, è o no un numero (inclusi il meno, i punti e le virgole). Il controllo viene fatto sul valore Ascii dei caratteri. C_TEXT($1;$uncarattere_s) C_LONGINT($i) C_BOOLEAN($contienelettere_b) $contienelettere_b:=False For ($i;1;Length($1)) If ($contienelettere_b) $i:=Length($1) Else $uncarattere_s:=Substring($1;$i;1) If ((Ascii($uncarattere_s)<44) | (Ascii($uncarattere_s)>57)) $contienelettere_b:=True End if End if End for $0:=Not($contienelettere_b) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Stile |
Campi booleani nei Quick report
Stampando un report di una tabella con un camp Booleano, Quick Report visualizza il valore del campo come True o False. Ecco una funzione per rendere il report più leggibile. Mettiamo il caso che nel campo booleano si segni se una fattura è pagata o meno e questo campo si chiami [Fatture]Pagata_b. Per fare in modo che vengano stampate o esportate le voci "Pagata" e "Non pagata", invece del campo inserirò una colonna nel report in cui scriverò la formula: (Num([Fatture]Pagata_b)*"Pagata")+(Num(Not([Fatture]Pagata_b))*"Non pagata") Questo mostrerà dei valori più comprensibili; ovviamente la stessa formula può essere utile anche nelle liste e in genere nei layout di visualizzazione. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
Leggere i tag TIFF Exif GPS IPTC e QTT con QPix
Alcuni tipi di immagini possono contenere delle informazioni di tipo "non visuale", che vengono chiamate meta-data o tags. Un tag solitamente è composto di due parti, l'ID e i dati. QPix consente di accedere ai tag TIFF (presenti nei file TIFF e Exif JPEG secondo le specifiche 2.1), Exif (presenti nei file TIFF e Exif JPEG), GPS, IPTC (nei file JPEG, TIFF, and PhotoShop) e QuickTime. Per ottenere questi dati bisogna intanto estrarre il tag container dall'immagine (è un BLOB) usando il comando QPx_GetImageFileTagContainer. Preso questo BLOB, si usa il comando QPx_OpenTagContainer per ottenere un longint che viene usato come riferimento dai comandi che permettono di estrarre informazioni dai tag, che sono QPx_GetTagInstances, QPx_GetTagInstanceInfo e QPx_GetTagInstanceText: i dati provenienti da tag con un solo elemento vengono memorizzati in variabili di testo, per i tag com più elementi QPix popola un array di testo. Terminate le operazioni sui tag si usa QPx_CloseTagContainer per liberare la memoria allocata. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Scrivere testo alla fine di un campo
In un form di input, portando il cursore su un campo testo, la barra di inserimento lampeggia all'inizio del testo (almeno 4D si comporta così). Per fare in modo che invece il cursore lampeggi alla fine del testo è possibile attivare nell'oggetto testo l'evento On Getting Focus e scrivere al suo interno il seguente codice: Case of :(Form event=On Getting Focus) HIGHLIGHT TEXT ([Table1]CampoTesto_t;MAXTEXTLEN ;MAXTEXTLEN ) End case dove MAXTEXTLEN è la costante predefinita di 4D che contiene la massima lunghezza di un testo (32000). |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Da una lista di elementi in array
Questo metodo serve a riempire un array di tipo testo con gli elementi di una lista, il cui separatore può essere definito e non limitato ad un carattere. Un suo uso potrebbe essere (vedi gli esempi nel commento): nella lettura di file di testo con i campi separati dal tabulatore, nella individuazione di parole da una frase, delle cartelle in un percorso ad un file, etc `Metodo: listaInArray `Nexus srl - www.nexusonline.it `Descrizione: mette gli elementi di una lista di testo in array `$0 = ritorna il numero di elementi letti `Nota:l'array deve essere già dichiarato e passato per parametro `esempi: $campi:=listaInArray(varLetta;->array_at) `esempi: $parole:=listaInArray("uno due tre";->array_at;" ") `esempi: $cartele:=listaInArray("MacHD:Lavori:Personali";->array_at;":") C_TEXT($1;$3;$lista_t;$separatore_t) C_POINTER($2;$array_ptr) C_LONGINT($pos_l;$quanti_l) $lista_t:=$1 `contiene la lista di parole o termini da leggere $array_ptr:=$2 `contiene un puntatore ad un array text che conterrà il risultato If (Count parameters=3) $separatore_t:=$3 `è opzionale indicare il separatore usato Else $separatore_t:=Char(9) `altrimenti separatore di default è il Tabulatore End if ARRAY TEXT($array_ptr->;0) `ridimensiona l'array a zero $pos_l:=Position($separatore_t;$lista_t) `trova il primo separatore While ($pos_l#0) `se c'è almeno un separatore $quanti_l:=Size of array($array_ptr->)+1 INSERT ELEMENT($array_ptr->;$quanti_l) `1 elemento è il default $array_ptr->{$quanti_l}:=Substring($lista_t;1;$pos_l-1) `estrae il prossimo elemento $lista_t:=Substring($lista_t;$pos_l+Length($separatore_t)) `e poi lo cancella dalla lista $pos_l:=Position($separatore_t;$lista_t) `e controlla il prossimo separatore End while `ne rimane ancora uno, anche se solo vuoto $quanti_l:=Size of array($array_ptr->)+1 INSERT ELEMENT($array_ptr->;$quanti_l) $array_ptr->{$quanti_l}:=$lista_t $0:=$quanti_l |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Compendio QuickReport
Ecco un piccolo elenco delle poche informazioni necessarie ad un utente per generare i suoi report personalizzati con Quick Report: - per aggiungere un campo al report fai doppio clic su un elemento dell'elenco dei campi; - se i campi che vuoi inserire appartengono ad un altro archivio, scegli l'archivio relativo dopo aver scelto Related Tables; - se vuoi che 4D non calcoli in automatico la larghezza della colonna seleziona la colonna e disattiva "Columns" "Automatic width" e scegli la larghezza che vuoi; - puoi contare i campi di qualsiasi tipo, usando il tastino "N", mentre le funzioni di somma, minimo, massimo e media sono utilizzabili solo per i valori numerici; - puoi ordinare i dati secondo uno o più dati trascinando il campo da ordinare nella colonna "Sort order"; - se vuoi che 4D mostri per ogni riga il valore secondo cui sta ordinando e non solo sulla prima riga che ha un certo valore scegli "Columns" "R epeated values"; - creando un ordinamento, è possibile sfruttare i break: un break viene generato quando il campo secondo cui hai ordinato cambia valore, quindi anche sui break puoi sfruttare le funzioni conta, somma, ecc.; - per far ricomparire il valore che ha generato il break (il valore ordinato fino ad adesso elencato), inserisci un cancelletto (#) in corrispondenza del campo ordinato; - su "File" - "Headers and footers" puoi modificare intestazione e piè di pagina del report, inserendo dati al centro o a destra o a sinistra, e in automatico puoi inserire data e ora di stampa e numero di pagina, il tutto inframmezzato da testo personalizzato; - puoi personalizzare l'aspetto come credi o utilizzare l'opzione "Style" "Presentation" per delle combinazioni di font e colori già create; - puoi salvare il report andando su "File" "Save" e richiamarlo quando vuoi andando su "File" "Open"; - imposti l'orientamento del foglio da "File" "Page setup"; - vedi l'anteprima del report da "File" "Print preview"; - stampi il report andando su "File" "Generate". |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Help in linea di 4D [1] : Explorer Help *
All'interno della finestra di method editor, dopo aver terminato di scrivere un comando di 4D, l' Explorer Help visualizza la sintassi del comando nella parte alta della finestra. Perché questo funzioni deve essere installato un file, che fornisce le informazioni di aiuto, il suo nome è "4D Help" su Macintosh e "4D Help.RSR" su Windows. Questo file di help non va confuso con il Menu di Help, che utilizza un altro file chiamato 4D.HLP. "4D Help" per l'Explorer Help può essere comodamente scaricato dal sito ftp di 4D.com da questo indirizzo ed installato nella seguente cartella di sistema: Macintosh = Library:Application Support:4D Windows = C:\Document and Settings\All Users\Application Data\4D Dopo l'installazione l'Explorer Help è fruibile su quel computer sia se utilizzate un 4D Client oppure una versione Desktop. |
1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Formato di Data e Ora per importare ed esportare
Con 4D versione 2003 è disponibile un formato DateTime per importare ed esportare data e ora. Il formato corrisponde alla rapresentazione standard di data e ora XML, che usa il formato aaaa-mm-ggThh:mm:ss come ad esempio: 2000-10-12T16:30:00 Benché 4D non conservi data e ora in un unico campo, è possibile usare questo formato in entrambi i casi: - da un campo data, 4d produrrà un testo del tipo 2000-10-12T00:00:00 - da un campo ora, 4d produrrà un testo del tipo 0000-00-00T16:30:00 D'altro canto da questo formato 4D leggerà l'informazione necessaria per importare in un campo di tipo data o di tipo ora. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Help in linea di 4D [3] : Microsoft Help
Esiste anche un file chiamato 4D.HLP che è in formato Microsoft Help; ovviamente funziona facilmente con Window, mentre con Macintosh è compatibile con la 6.7 ed è necessario avere installato il Microsoft Help Application (presente nella versione di Office 98). Si scarica dal sito ftp da questo indirizzo. Questo file 4D.HLP (ed eventualmente anche altri file nello stesso formato) possono essere messi allo stesso livello dell'applicazione 4D o anche in una cartella Mac4DX o Win4DX: in questo caso il file viene scaricato automaticamente in una installazione Client-Server ed è disponibile in automatico nel menu Aiuto. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Help in linea di 4D [2] : Visore Aiuto Apple
Su Mac OS X l'aiuto in linea di 4d si richiama dal barra del Menu. "Help" è l'ultima voce di menu sia che siate in ambiente User che in ambiente Designer. Utilizza per la visualizzazione Visore Aiuto (Help Viewer) del MacOsX: è molto completo e contiene tutto il Language Reference. In questo caso tutti i files che servono sono in una cartella (che si scarica dall'ftp di 4d.com da questo indirizzo oppure si copia da CD) la cartella "4th Dimension Help" con tutto il suo contenuto va posizionata in: Library:Documentation:Help Per usufruire di questo aiutonon è necessario avere 4D aperto: è possibile aprire Aiuto Mac e andarlo a scegliere nel menu Libreria. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Ricreare il menu Edit
Se serve ricostruire il menu Edit (nella versione 2003), è possibile creare una nuova barra dei menu nel database esistente e copiare manualmente questo menu Edit su tutti i menu esistenti. L'Edit originale di 4D è riconoscibile dal fatto che "Edit" è in corsivo. Quando i menu e i loro elementi sono in corsivo, questo significa che si sta usando la versione del menu di 4D. Facendo Control-click sulla parola in corsivo nell'editor della barra dei menu verrà visualizzato il numero di riferimento associato. Per esempio: - File: ":79,1" - Edit: ":79,5" Inserendo queste stringhe quando si aggiunge un menu o una voce di menu ci si assicurerà che verranno utilizzate le “versioni correnti” dei comandi. Quindi, per azioni come Taglia, Copia e Incolla, ecc. sarà necessario anche utilizzare i loro riferimenti appropriati. Ecco qualche esempio: Annulla: 131,18 Taglia: 131,19 Copia: 131,20 Incolla: 131,21 Il menu Edit deve essere posizionato direttamente dopo il menu File, che dovrebbe essere il primo e anch’esso in corsivo. Appena fatto, si sarà in grado di utilizzare tutte le funzioni del menu Edit standard. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Il nuovo menu Edit nella versione 4D 2003
In 4D 2003 si ha la possibilità di creare il menu Edit. Nelle versioni precedenti, il menu Edit era impostato per default, non modificabile. Quindi, aggiornando il database alla 2003 da una versione precedente, viene data la possibilità di usare il predefinito o il proprio. Di default, 4D utilizzerà l’ “Old Edit Menu Mechanism”, cioè il menu Edit dalle versioni precedenti. Tuttavia, se si decide di non utilizzare più questo, sarà poi necessario ricostruire il menu Edit per non perdere le funzionalità di Taglia, Copia e Incolla (e i relativi tasti di scelta rapida) nel Custom Environment. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Creare un percorso completo ad un file
Supponi di voler creare un documento da 4D e metterlo in un qualche posto sul disco. Dovresti sapere esattamente dove registrare il documento e se quel posto o cartella esiste. Oppure puoi creare il percorso con tutte le cartelle che servono per arrivare alla posizione desiderata dove mettere il documento. L'esempio che segue, chiamato PreparaPercorso, fa esattamente questo: C_TEXT($1;$percorso_t;$percorsoCreato_t;$cartella_t) C_STRING(1;$separatore_t) C_LONGINT($SistemaOperativo_l) $percorso_t:=$1 SistemaOperativo_l PROPERTIES($SistemaOperativo_l) If ($percorso_t#"") ` per windows, bisogna passare anche la lettera del disco If ($SistemaOperativo_l=Windows) If (Position(":\\";$percorso_t)#0) $percorsoCreato_t:=Substring($percorso_t;0;Position("\\";$percorso_t)) $percorso_t:=Substring($percorso_t;Position("\\";$percorso_t)+1) End if $separatore_t:="\\" Else $separatore_t:=":" End if ` aggiungiamo il separatore in coda, se non ci fosse già If ($percorso_t[[Length($percorso_t)]]#$separatore_t) $percorso_t:=$percorso_t+$separatore_t End if Repeat ` identifica la prossima cartella $cartella_t:=Substring($percorso_t;0;Position($separatore_t;$percorso_t)) $percorso_t:=Substring($percorso_t;Position($separatore_t;$percorso_t)+1) $percorsoCreato_t:=$percorsoCreato_t+$cartella_t ` la crea se non esiste Case of :(Test path name($percorsoCreato_t)<0) CREATE FOLDER($percorsoCreato_t) :(Test path name($percorsoCreato_t)=1) $cartella_t:="" End case Until ($cartella_t="") End if Ad esempio, chiamando questo metodo passando questo parametro: PreparaPercorso("C:\\Prima Cartella\\Seconda\\Ultima cartella\\") Questo crea queste tre cartelle nel disco C:. Con questo metodo non è necessario preoccuparsi che una posizione esista già, perché se serve il metodo la crea, altrimenti non fa niente. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
Ricezione immagine via ODBC da un db SQL
Ecco un semplice approccio per ricevere una immagine da un database SQL via ODBC C_TEXT($sql_t) C_LONGINT($cursorID_l;$res_l) C_PICTURE(vPicture_pic) C_BLOB(vBlob_blb) $cursorID_l:=OC Create cursor (<>connectID_l) If ($cursorID_l#-1) $sql_t:="select picture from PictureTable where pictureid=123" $res_l:=OC Set SQL in Cursor ($cursorID_l;$sql_t) If ($res_l=1) $res_l:=OC Bind ($cursorID_l;1;"vBlob_blb") ` SQL_BINARY $res_l:=OC Execute cursor ($cursorID_l) $res_l:=OC Load row ($cursorID_l) BLOB TO PICTURE(vBlob_blb;vPicture_pic) End if OC DROP CURSOR ($cursorID_l) End if In questo esempio la variabile vBlob_blb viene legata al campo picture col comando OC Bind. Una volta che il risultato è memorizzato nella variabile BLOB vBlob_blb, il comando BLOB TO PICTURE inserirà l'immagine memorizzata nel BLOB nella variabile di tipo picture vPicture_pic. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
Invio immagine via ODBC ad un db SQL
Ecco un semplice approccio per inviare una immagine a un database SQL via ODBC C_TEXT($sql_t) C_LONGINT($cursorID_l;$res_l) C_BLOB(vBlob_blb) PICTURE TO BLOB(vPicture_pic;vBlob_blb;"JPEG") $cursorID:=OC Create cursor (<>connectID_l) If ($cursorID_l#-1) $sql_t:="insert into PictureTable values (?)" $res_l:=OC Set SQL in Cursor ($cursorID;$sql) If ($res_l=1) $res_l:=OC Bind parameter ($cursorID_l;1;"vBlob_blb";1) ` SQL_BINARY/BLOB $res_l:=OC Execute cursor ($cursorID_l) End if OC DROP CURSOR ($cursorID_l) End if In questo esempio il comando OC Bind parameter viene usato per collegare una variabile di tipo picture con un campo di tipo BLOB (SQL_BINARY) nel database ODBC. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
Due modi di eseguire una query SQL via ODBC
In 4D ODBC esistono due comandi che eseguono quasi la stessa operazione (e ovviamente il quasi è rilevante), dove l'operazione in questione è eseguire una query SQL e i due comandi sono OC Query exec e OC Execute SQL. Entrambi i comandi permettono di mandare una query SQL ad una origine dati e di ottenere i dati in degli array. La differenza fra i due comandi sta nel tipo di parametri accettati: OC Query exec può ricevere da 1 a 22 array di dati, e gli array vengono passati come parametri del comando; OC Execute SQLriceve invece come parametro un unico array di stringhe che contiene la lista degli array che dovranno essere popolati dall'esecuzione della query: questo approccio supera dunque il limite delle 22 colonne del primo comando. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
4th Dimension, MS Access e FileMaker Pro [9] Le variabili
Malgrado un database sia fatto per gestire dati, capita di dover gestire dei dati in maniera temporanea. FileMaker usa il concetto dei campi globali associati ad ogni tabella. Ogni utente può avere differenti campi e il loro valore "dura" finché il file è aperto. Ognuno di questi campi contiene un singolo valore. Lo ScriptMaker non consente di dichiarare variabili. Access usa gli oggetti dei form. Gli oggetti dei vari form sono indipendenti fra di loro e valgono finché il form è aperto. L'uso di VBA permette al programmatore di avere variabili indipendenti di vario tipo. 4th Dimension può inserire variabili dove è necessario (form o metodi). Le variabili differiscono solo nello scope che viene loro assegnato: locali (iniziano con il $, appartengono solo al metodo dove vengono usate), processo (appartengono al processo, con i suoi metodi e i suoi form, dove vengono usate), interprocesso (iniziano con <>, sono condivise da tutti i processi su una singola macchina). Inoltre può gestire un insieme di variabili separato per 4D Server. Consulta da questo link l’indice delle faq su 4th Dimension, MS Access e FileMaker Pro |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Stile |
Dove metto i campi calcolati di FileMaker?
Una domanda che ci viene posta da chi, leggendo le faq su FileMaker, vuole cercare di avvicinarsi a 4th Dimension è: "Dove metto i campi calcolati di FileMaker in 4D?". Risposta: come detto, il 4D non esistono i campi calcolati, il che significa che intanto nella struttra 4D creo semplicemente un campo del tipo corretto. A questo punto il campo creato lo posso modificare, ad esempio, in questi posti: - nel metodo del form di input controllo il verificarsi dell'evento "On Data Change" su qualsiasi dei campi mostrati, cioè If (Form event=On Data change) `fai i calcoli che facevi con FM End if Dunque tutte le volte che verrà modificato un dato nel form verrà eseguito questo codice; - nel metodo del form di input controllo il verificarsi dell'evento "On Validate", che equivale al caso precedente con l'unica differenza che il codice viene eseguito solo quando salvo il record cliccando sul tasto che esegue l'azione ACCEPT; - nel metodo dello specifico oggetto, campo, variabile, pulsante, etc controllo il verificarsi dell'evento "On Data Change", che equivale anch'esso al primo caso, solo che il codice viene eseguito solo quando viene modificato il contenuto dell'oggetto stesso; - nel metodo (trigger) della tabella, che è il modo più semplice e complesso allo stesso tempo; tanto per non entrare nel dettaglio, si può dire che qualsiasi cosa succeda sulla tabella in questione in qualsiasi parte del database, 4D esegue il codice del trigger sul record della tabella su cui sto agendo. Però è facile scrivere un trigger che influisca pesantemente sulle performance dell'intera applicazione: per chi si affaccia e 4D è perciò preferibile iniziare con gli altri sistemi, cioè fare i calcoli solo nelle maschere in cui l'utente interviene sui dati o nelle procedure chiamate da menu nel momento in cui l'utente ha bisogno di dati calcolati. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
4th Dimension, MS Access e FileMaker Pro [8] Gli eventi
Gli eventi Col termine evento si può molto semplicisticamente definire la possibilità di eseguire qualche operazione quando succede o sta per succedere qualcosa. FileMaker gestisce un numero davvero limitato di eventi, più ampio quello di Access e 4D; 4D inoltre, dei tre sistemi, è il solo in grado di gestire in automatico anche come eventi l'avvio e la chiusura del server, la connessione e la disconnessione del client. Nello specifico, 4D gestisce: - apertura e chiusura di un form; - clic singolo o doppio; - stampa; - modifica di un campo; - fuoco su un oggetto (in entrata o in uscita); - drag degli oggetti e drop degli oggetti; - inserimento di un carattere; - resize di form e oggetti; - eventi a tempo; - errori; - attivazione o disattivazione di un form (per cambio finestra); - scelta di un menu; - apertura del database; - clic sul pulsante di chiusura; - uscita dal database; - apertura e chiusura del server; - apertura e chiusura dei client; - eventi web. Degli eventi citati, Access non gestisce in automatico, oltre alla parte client/server, la scelta di un menu e il clic su pulsante di chiusura. Gli unici eventi gestiti in automatico da FileMaker sono i clic sugli oggetti, gli eventi a tempo, la scelta di un menu, il pulsante di chiusura finestra, apertura e chiusura del database. Consulta da questo link l’indice delle faq su 4th Dimension, MS Access e FileMaker Pro |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Importare in Excel i dati da 4D
Per importare in Microsoft Excel dei dati generati da 4D è possibile usare questa procedura (testata su Macintosh, ma non dovrebbe essere dissimile in Windows) in 4D viene attivato il web server e creato un metodo richiamabile con il 4DACTION, del tipo: `web_IncassiGiorno QUERY([Incassi];[Incassi]Data=current date) $$Risposta_t:="" While (Not(End selection([Incassi]))) $Risposta_t:=$Risposta_t+String([Incassi]Scontrino)+Char(9) $Risposta_t:=$Risposta_t+String([Incassi]Importo)+Char(13) NEXT RECORD([Incassi]) End while SEND HTML TEXT($Risposta_t) In un file di testo chiamato "Query4D.txt" si scrive: WEB 1 http://127.0.0.1/4DACTION/web_IncassiGiorno Selection=EntirePage Formatting=All PreFormattedTextToColumns=True ConsecutiveDelimitersAsOne=True SingleBlockTextImport=False In Microsoft Excel, scegliere dal menu Data: Get external Data: Run saved query e scegliere il file "Query4D.txt" appena creato.. et voila! |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Estrarre il nome del file dal percorso completo
Questa funzione restituisce il nome di un file estratto da un percorso completo. Ad esempio, per sapere quale base dati è aperta al momento si può usare nel seguente modo, usando la relativa funzione di 4d: $nomeDati:=getNomeFile(Data file) ` getNomeFile ` Nexus srl C_TEXT($0;$1) C_STRING(255;$nomecompleto_t) C_INTEGER($car_l) $nomecompleto_t:=$1 ` identifico il separatore usato, ":" oppure "\" $separatore_t:=System folder[[Length(System folder)]] $car_l:=Length($nomecompleto_t) While (($car_l>0) & ($nomecompleto_t[[$car_l]]#$separatore_t)) $car_l:=$car_l-1 End while If ($car_l>0) $0:=Substring($nomecompleto_t;$car_l+1) Else $0:=$nomecompleto_t End if |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Estrarre il percorso della cartella
Questa funzione può essere usata per ottenere il pathname (percorso) della cartella in cui risiede un determinato file di cui si ha il nome completo. Ad esempio, per sapere la cartella dove si trova l'applicazione 4D in funzione al momento, si può usare con la relativa funzione di 4d: $directory_t:=getPathname(Application File) ` getPathname ` Nexus srl C_STRING(255;$1;$0;$nomecompleto_t) C_STRING(1;$separatore_t) C_INTEGER($viLen;$viPos;$viChar) $nomecompleto_t:=$1 $len_l:=Length($nomecompleto_t) ` identifico il separatore usato, ":" oppure "\" $separatore_t:=System folder[[Length(System folder)]] $car_l:=Length($nomecompleto_t) While (($car_l>0) & ($nomecompleto_t[[$car_l]]#$separatore_t)) $car_l:=$car_l-1 End while If ($car_l>0) $0:=Substring($nomecompleto_t;1;$car_l) `restituisce il percorso Else $0:=$nomecompleto_t `se non contiene separatori End if |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Convertire da Base64 in Testo Ascii
Da un messaggio inviato da Pete Bozek al 4D Nug internazionale, decodifica in Ascii i dati di un blob in base Base64. ` Decode_Base64_Blob ` di Peter Bozek ` http://www.inforce.sk C_POINTER($1;$pPassedBlob) C_LONGINT($i;$iOffset;$iDest) C_LONGINT($lValue;$lValue1;$lValue2;$lValue3;$lValue4) C_LONGINT($temp;$temp2) C_LONGINT($lBlobSize;$lEOLLength) C_BLOB($oDecoding) C_STRING(64;$encoding) $pPassedBlob:=$1 $lBlobSize:=BLOB size($pPassedBlob->) If ($lBlobSize>0) $encoding:="ABCDEFGHIJKLMNOPQRSTUVWXYZ" $encoding:=$encoding+"abcdefghijklmnopqrstuvwxyz0123456789+/" SET BLOB SIZE($oDecoding;0x00FF;0x0040) For ($i;1;64) $oDecoding{Ascii($encoding[[$i]])}:=$i-1 End for SET BLOB SIZE($pPassedBlob->;(($lBlobSize+3)\4)*4;0x0000) $lBlobSize:=BLOB size($pPassedBlob->) `ridimensionare il blob non dovrebbe essere necessario! $iOffset:=0 $iDest:=0 While ($iOffset<$lBlobSize) If ($oDecoding{$pPassedBlob->{$iOffset}}=0x0040) `non fa parte di uno stream $iOffset:=$iOffset+1 Else `prende blocchi di 4 Byte If ($iOffset<($lBlobSize-1)) $lValue:=BLOB to longint($pPassedBlob->;Macintosh byte ordering ;$iOffset) $lValue1:=$lValue >> 0x0018 $lValue2:=($lValue >> 0x0010) & 0x00FF $lValue3:=($lValue >> 0x0008) & 0x00FF $lValue4:=$lValue & 0x00FF $pPassedBlob->{$iDest}:=($oDecoding{$lValue1} << 2) | ($oDecoding{$lValue2} >> 4) $iDest:=$iDest+1 $temp:=$oDecoding{$lValue3} If ($temp<0x0040) $pPassedBlob->{$iDest}:=($oDecoding{$lValue2} << 4) | ($temp >> 2) $iDest:=$iDest+1 $temp2:=$oDecoding{$lValue4} If ($temp2<0x0040) $pPassedBlob->{$iDest}:=($temp << 6) | $temp2 $iDest:=$iDest+1 End if End if Else $iOffset:=$lBlobSize End if End if End while If ($iDest>0) SET BLOB SIZE($pPassedBlob->;$iDest) End if End if |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Convertire da Testo Ascii in Base64
Da un messaggio inviato da Pete Bozek al 4D Nug internazionale, fa la codifica in Base64 di un testo passato come blob. Gli altri due parametri opzionali indicano se inserire un salto riga e che tipo di carattere usato (il default è il Return). ` Encode_Base64_Blob ` di Peter Bozek ` http://www.inforce.sk C_POINTER($1;$pPassedBlob) C_BOOLEAN($2;$bInsertLineBr) C_STRING(2;$3;$sEOL) C_LONGINT($iPos;$iDest;$iWritten;$iWhere) C_LONGINT($lBlobSize;$lNewSize;$lEOLLength) C_BLOB($oTempBlob) C_STRING(64;$encoding) $pPassedBlob:=$1 $lBlobSize:=BLOB size($pPassedBlob->) If ($lBlobSize>0) `carica i parametri If (Count parameters>1) $bInsertLineBr:=$2 Else $bInsertLineBr:=True End if $lEOLLength:=0 If ($bInsertLineBr) If (Count parameters>2) $sEOL:=$3 End if If ($sEOL="") $sEOL:=Char(Carriage return ) End if $lEOLLength:=Length($sEOL) End if `prepara i data COPY BLOB($pPassedBlob->;$oTempBlob;0;0;$lBlobSize) SET BLOB SIZE($oTempBlob;(($lBlobSize+2)\3)*3;0x0000) SET BLOB SIZE($pPassedBlob->;0) $lNewSize:=(($lBlobSize+2)\3)*4 If ($bInsertLineBr) $lNewSize:=$lNewSize+(($lNewSize+75)\76)*$lEOLLength End if SET BLOB SIZE($pPassedBlob->;$lNewSize;0x0000) $encoding:="ABCDEFGHIJKLMNOPQRSTUVWXYZ" $encoding:=$encoding+"abcdefghijklmnopqrstuvwxyz0123456789+/" $iPos:=0 $iDest:=0 If ($bInsertLineBr) `start with NL TEXT TO BLOB($sEOL;$pPassedBlob->;Text without length ;$iDest) `$iDest:=$iDest+$lEOLLength End if While ($iPos<$lBlobSize) $iWhere:=($oTempBlob{$iPos} >> 2) $pPassedBlob->{$iDest}:=Ascii($encoding[[$iWhere+1]]) $iDest:=$iDest+1 $iWhere:=(($oTempBlob{$iPos} << 4) & 0x0030) | ($oTempBlob{$iPos+1} >> 4) $pPassedBlob->{$iDest}:=Ascii($encoding[[$iWhere+1]]) $iDest:=$iDest+1 $iWhere:=(($oTempBlob{$iPos+1} << 2) & 0x003C) | (($oTempBlob{$iPos+2} >> 6) 0x0003) $pPassedBlob->{$iDest}:=Ascii($encoding[[$iWhere+1]]) $iDest:=$iDest+1 $iWhere:=$oTempBlob{$iPos+2} & 0x003F $pPassedBlob->{$iDest}:=Ascii($encoding[[$iWhere+1]]) $iDest:=$iDest+1 $iPos:=$iPos+3 $iWritten:=$iWritten+4 Case of : ($iPos=($lBlobSize+1)) $pPassedBlob->{$iDest-1}:=Ascii("=") : ($iPos=($lBlobSize+2)) $pPassedBlob->{$iDest-1}:=Ascii("=") $pPassedBlob->{$iDest-2}:=Ascii("=") End case If ($bInsertLineBr & ($iWritten%76=0)) TEXT TO BLOB($sEOL;$pPassedBlob->;Text without length ;$iDest) `$iDest:=$iDest+$lEOLLength End if End while End if |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
Colonne in un documento 4D Write
Per creare delle colonne in un documento 4D Write basta andare nel menu Format, scegliere Columns e specificarne il numero. Per eseguire la stessa operazione da linguaggio, si usa il comando: WR SET DOC PROPERTY (Area_l;$selettore_l;$numcol_l) Il valore per il selettore "$selettore_l" è quello della costante wr number of columns (24), mentre "Area_l" indica l'ID dell'area 4D Write e "$numcol_l" è il numero di colonne. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
4D Write: un'introduzione
4D Write è il plugin 4th Dimension che permettte di avere le funzionalità di un text editor all'interno di un database 4D. Come in ogni text editor, tutte le funzionalità sono accessibili da menu, ma tali funzionalità possono essere gestite anche da linguaggio. Il plugin gestisce documenti di tipo proprietario (4WR7/4W7), file di testo, RTF, HTML e alcuni tipi di file Word. In un documento di 4DWrite è possiile ovviamente inserire riferimenti diretti a campi del database, per costruire documenti con i dati dei record selezionati e ottenere così un mail merge. Un'area 4D Write può essere creata o all'interno di un form o in in una external window, con un comando del tipo: vWrite:=Open external window (50; 50; 350; 450; 8; "Lettera"; "_4D Write" ) E' anche possibile generare una offscreen area (area non visibile) che permette di creare e modificare il documento solo in memoria, con un aumento delle prestazioni: è importante ricordarsi di usare il comando WR DELETE OFFSCREEN AREA per cancellare l'area dalla memoria quando non è più necessaria. Con la versione 2004 entreranno in scena un maggior controllo delle opzioni di stampa, lo zoom del documento e il dizionario italiano per il controllo ortografico. I documenti generati da 4D Write sono ovviamente multipiattaforma. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Costruire una Lista Gerarchica
Ecco un codice di esempio per costruire una lista gerarchica di due livelli, basata su una struttura con una tabella [Padri] e una di [Figli] in relazione. C_LONGINT(Lista_l;$sottolista_l;$padri_l) ListaGerarchica_l:=New list ` Ne creo una nuova ALL RECORDS([Padri]) For ($padri_l;1;Records in selection([Padri])) RELATE MANY([Padri]) `seleziona eventuali figli di questo padre If (Records in selection([Figli])>0) `controlla se ce ne sono ORDER BY([Figli];[Figli]Nome) $sottolista_l:=New list `crea una lista temporanea dei figli For ($i;1;Records in selection([Figli])) `per ogni figlio aggiunge il figlio all'elenco dei figli APPEND TO LIST($sottolista_l;[Figli]Nome;-1*Record number([Figli])) NEXT RECORD([Figli]) End for End if ` aggiunge il padre e il suo elenco dei figli alla lista principale APPEND TO LIST(ListaGerarchica_l;[Padri]Nome;Record number([Padri]);$sottolista_l;True) NEXT RECORD([Padri]) End for |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Il carattere \
In 4D 2003 è stato introdotto un uso particolare del carattere "\": nel method editor questo carattere viene interpretato come: "Il simbolo che segue è un carattere". Facciamo degli esempi concreti: - se voglio scrivere il percorso della cartella Windows, questo non sarà "C:\Windows\" ma "C:\\Windows\\" - se voglio far apparire una finestra di alert con all'interno i doppi apici dovrò scrivere del codice tipo: $text_t:="\"ciao\" in inglese si scrive \"hello\"" ALERT($text_t) Convertendo una struttura dalla versione 6.8 o precedenti, il sistema è abbastanza intelligente da trasformare eventuali caratteri "\" inclusi nel testo (ad esempio nei pathname per Windows), che vengono automaticamente e correttamente trasformati in "\\". |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Metodo antispam
Durante la cena seguita alla conferenza del 17 giugno, mi è stato chiesto di pubblicare il metodo con cui abbiamo creato alcune mail nell'html del sito. Scrivo due righe di documentazione: il metodo prende come parametro un indirizzo di posta e ne crea uno in un formato ascii comprensibile dal browser internet. Da questa conversione viene "esentato" il secondo carattere dell'indirizzo per evitare che uno snake faccia in automatico la conversione da ascii a carattere in maniera troppo semplice e automatica. C_TEXT($IndirizzoOriginale_t;$IndirizzoModificato_t; mailto_t) C_LONGINT($i;$k) $IndirizzoOriginale_t:=$1 $mailto_t:="mailto:" `"mailto:" in formato ascii $IndirizzoModificato_t:="" For ($i;1;Length($IndirizzoOriginale_t)) If ($i=2) $IndirizzoModificato_t:=$IndirizzoModificato_t+$IndirizzoOriginale_t[[$i]] Else $IndirizzoModificato_t:=$IndirizzoModificato_t+""+String(Ascii($IndirizzoOriginale_t[[$i]]))+";" End if End for $IndirizzoModificato_t:=$mailto_t+$IndirizzoModificato_t $0:=$IndirizzoModificato_t |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
4th Dimension, MS Access e FileMaker Pro [7] L'automazione
L'automazione Le applicazioni per database richiedono solitamente un certo grado di automazione per eseguire delle operazioni richieste dall'utente o necessarie per il funzionamento del sistema. Gli approcci fra i tre sistemi sono differenti. Il sistema base per scrivere codice in Access è quello delle macro. Una macro viene creata in una finestra tipo foglio di calcolo in cui vengono inseriti i vari passaggi. E' un sistema simile agli script di FileMaker, ma meno potente. Per questo motivo molti sviluppatori preferiscono utilizzare Visual Basic for Application (VBA) per scrivere codice. VBA è l'ambiente di programmazione comune alla piattaforma Office e non solo (si può scrivere codice VBA anche per i software CAD) che consente di avere controllo sul database, offrendo nuove funonalità allo sviluppatore. D'altro canto è un sistema non adattato alle esigenze specifiche di un database. L'approccio di FileMaker all'automazione viene effettuato con l'uso di campi calcolati e script. I campi calcolati vengono definiti durante la creazione della tabella e valutati in maniera automatica ogni qual volta uno dei valori usati nel campo viene modificato. La deifinizione degli script è simile alle macro di Access, ma non esistendo un vero e proprio linguaggio di programmazione in FileMaker, gli script sono più potenti. Questo tipo di approccio però di fatto impedisce alcune funzioni di editing, come ad esempio un copia/incolla diretto degli script. L'automazione in 4D viene eseguita attraverso i metodi. Il tipo di programmazione è simile al sistema concettuale di VBA, ma il linguaggio, assai comprensibile, è molto adattato alle esigenze di un database. Essendo codice di tipo "testo" è possibile farne copia e incolla fra metodi diversi, come si fa con un normale editor di testi; esiste la possibilità di usare delle macro e di crearne di nuove, di avere un commento per ogni metodo aggiornato anche in automatico con la data, l'ora e l'utente per ogni modifica fatta. Consulta da questo link l’indice delle faq su 4th Dimension, MS Access e FileMaker Pro |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
4th Dimension, MS Access e FileMaker Pro [5] Inserimento nei campi **
Controllo dell'inserimento nei campi I filtri di inserimento controllano i caratteri che è consentito digitare in un campo (o in una variabile) da parte dell'utente. Per esempio se voglio controllare l'inserimento di un codice fiscale posso mettere un filtro del tipo "˜A######&9##˜A#&9##˜A#&9###˜A#". Dei tre sistemi solo Access e 4D possiedono questa caratteristica, non FileMaker. Inoltre in FileMaker non è possibile controllare un evento del tipo "on data change" che permetta di eseguire del codice all'uscita da un campo a controllare i dati appena inseriti o modificati. Consulta da questo link l’indice delle faq su 4th Dimension, MS Access e FileMaker Pro |
2 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
4th Dimension, MS Access e FileMaker Pro [4] La sicurezza *
La sicurezza Sul versante sicurezza i tre sistemi risultano abbastanza differenti. In FileMakerPro non esiste una combinazione utente - password come gli altri sistemi, ma supporta solo password. Inoltre le password sono definite a livello dei file, il che significa che per cambiare una password è necessario aprire tutte le tabelle. Il modello di sicurezza di Access è abbastanza flessibile: possono essere definiti utenti, gruppi di utenti, e i privilegi possono essere assegnati ai singoli utenti o ai gruppi. Anche 4D permette la creazione di utenti con password e gruppi di utenti e la gestione dei privilegi. Una differenza assai significativa sta nella possibilità di usare una protezione SSL nella comunicazione tra 4D Server e 4D Client: ciò comporta ovviamente una maggiore sicurezza delle comunicazioni, impedendo di fatto un loro intercettamento e/o alterazione. Consulta da questo link l’indice delle faq su 4th Dimension, MS Access e FileMaker Pro |
1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
4th Dimension, MS Access e FileMaker Pro [3] I form *
I form Se da un lato tutti e tre i prodotti consentono una facile creazione di un form grazie ai wizard, d'altro canto il tipo di oggetti e la possibilità di personalizzarli risulta ben differente. 4D, ad esempio, possiede oggetti per i form che non sono presenti in Access o in FileMaker, come popup menu grafici o gerarchici, liste gerarchiche, splitter, matrici di pulsanti. FileMaker non possiede inoltre i Tab Control, utili ad esempio per gestire form multipagina. FileMaker Pro 7 ha finalmente apportato delle cospicue migliorie nella personalizzazione dei form: a differenza delle versioni precedenti, infatti, risulta possibile indicare dimensione e coordinate delle finestre, nonché aprire più fineste della stessa tabella contemporaneamente, ognuna con una selezione differente. Continuano però a mancare, ad esempio, i tips al passaggio del mouse su un pulsante. In Access, a differenza di 4D o FileMaker, un form non appartiene ad una tabella specifica: ciò significa che il form non sa, in partenza, quale è l'origine da cui prendere i dati. 4th Dimension permette una notevole personalizzazione dell'interfaccia, ad esempio: - controllo su posizione, tipo e dimensione delle finestre; - più form per la stessa tabella aperti contemporaneamente; - visibilità controllabile degli oggetti; - form multipagina; - tips su tutti gli oggetti del form; - stili personalizzati che controllano l'aspetto dell'applicazione a seconda del sistema operativo usato, e non solo windows-mac ma anche per le diverse versioni sulla stessa piattaforma; - personalizzazione della corrispondenza fra combinazioni su tastiera e voci di menu, pulsanti, azioni. Consulta da questo link l’indice delle faq su 4th Dimension, MS Access e FileMaker Pro |
1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
4th Dimension, MS Access e FileMaker Pro [2] Creazione della struttura *
Creazione della struttura Il primo passo passo da compiere nella progettazione di un database è la creazione della struttura, intesa come definizione di tabelle, campi e relazioni. In Access la struttura viene creata attraverso un'interfaccia tipo foglio di calcolo, in cui ogni riga rappresenta un campo (colonna) della tabella. Per ogni campo possono essere definiti molti attributi. La definizione delle relazioni dovrà essere impostata in una finestra a parte. Anche in FileMaker definizione della struttura e definizione delle relazioni avvengono in finestre separate: con la versione 7 è stato abbandonato il sistema ad elenco per passare ad una più moderna ed intuitiva visualizzazione grafica (nonché simile a quella degli altri due sistemi). Rispetto ad Access (e anche a 4D), FileMaker introduce un nuovo tipo di campo, il "campo calcolato", croce e delizia dei programmatori FMP. I campi calcolati vengono definiti usando un editor specifico e vengono trattati alla stessa stregua dei campi "standard": FileMaker si occupa di effettuare il calcolo quando ritiene necessario; se da un lato questo tipo di approccio può sembrare conveniente, esso in realtà nasconde dei problemi. Intanto, visto che il programmatore non ha controllo sull'esecuzione dei calcoli, le prestazioni possono abbassarsi irrimediabilmente. Inoltre, malgrado la versione 7 permetta di creare un file di dati separato dal file contenente script e layout, non risulta un'operazione semplice trasferire nel file della struttura i campi calcolati. In 4th Dimension la creazione di tabelle, campi e relazioni avviene contemporaneamente nell'unica finestra "Database structure". Cliccando sul titolo di una tabella si inseriscono i dati relativi alla tabella, cliccando su un campo si personalizzano i dati del campo, eseguendo un trascinamento da un campo ad un altro si crea una relazione molti a uno dal campo di partenza a quello di destinazione del trascinamento, cliccando sulla linea che definisce una relazione si impostano le proprietà della relazione. Consulta da questo link l’indice delle faq su 4th Dimension, MS Access e FileMaker Pro |
1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
4th Dimension, MS Access e FileMaker Pro [1] NOMENCLATURA *
Con questa faq iniziamo a trattare alcuni degli argomenti che possono aiutare gli sviluppatori che vengono da un altro sistema di sviluppo. Premesso che ogni strumento di programmazione ha i propri pregi e i propri difetti, l'obiettivo che ci possiamo prefiggere è quello di aiutare chi conosce già MS Access o FileMaker Pro e desideri passare a 4th Dimension, sfruttando in una certa misura le conoscenze già acquisite sulle altre piattaforme, trovando e analizzando sia i punti comuni che le sostanziali differenze. Le informazioni saranno ovviamente più precise su 4D, perché è l'ambiente che conosciamo meglio e su cui siamo ovviamente più aggiornati: è possibile dunque ad esempio che alcune caratteristiche di FileMakerPro 7 non siano citate completamente e/o correttamente. Dopo questa necessaria introduzione passiamo all'argomento vero e proprio della faq. NOMENCLATURA: ognuno dei tre sistemi di sviluppo definisce in maniera propria le componenti standard di un database: vediamo di uniformare il linguaggio. - Tabelle: solo in FileMaker assumono una definizione diversa, cioè File. - Campi: solo in Access assumono una definizione diversa, cioè Colonne. - Maschere: i termini maschera, form, layout sono variamente utilizzati. - Automazione: 4D usa degli oggetti chiamati metodi; Access usa macro e script Visual Basic; FileMaker calcoli automatici e script. - Struttura: una finestra di relazioni è presente in tutte le piattafome; la struttura di un database 4th Dimension visualizza e permette l'inserimento di tabelle e campi. - Lista di records: ognuno dei tre sistemi ha il suo modo di chiamare la lista di records: ad esempio se per 4D è il layout di output, per Access è la visualizzazione per foglio di calcolo. - Ricerche: per costruire le query Access usa un editor, FileMaker effettua la ricerca da form, 4D esegue entrambi i tipi di ricerca con Query by example (che permette la ricerca sul form di inserimento dei dati) e Query editor (un editor visuale che permette la costruzione di una query) - Selezione di records: ognuna delle tre piattaforme permette di gestire l'insieme dei record attualmente scelti. Consulta da questo link l’indice delle faq su 4th Dimension, MS Access e FileMaker Pro |
1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
APPLY TO SELECTION
Questo comando esegue una riga di codice, operazione o metodo sulla selezione corrente della tabella passata come primo parametro; in genere si usa per modificare un campo con un'unica operazione. Se nella selezione ci fosse qualche record bloccato, viene preparato un set "LockedSet" da controllare dopo l'uso dell'Apply. Ma i record vengono salvati solo se modificati, per cui questo comando può essere facilmente usato anche in altri modi. Ad esempio le seguenti sei righe di codice: $totale_r:=0 FIRST RECORD([Righe]) While (Not(End selection([Righe]))) $totale_r:=totale_r+([Righe]Quantità*[Righe]Prezzo) NEXT RECORD([Righe]) End while possono essere riassunte in due soltanto: $totale_r:=0 APPLY TO SELECTION([Righe];$totale_r:=totale_r+([Righe]Quantità*[Righe]Prezzo)) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
4th Dimension, MS Access e FileMaker Pro [6] I report
I report Col termine report solitamente si intende un output preparato per la stampa. Ne esistono prevalentemente di due tipi: quello sotto forma di lista o di griglia, per rappresentare un elenco di record, e quello di dettaglio di record, solitamente stampato come una pagina a record. Queste stampe possono avere totali, subtotali raggruppati e quant'altro. I report in Access vengono creati con lo stesso sistema con cui vengono generati i form. Lo sviluppatore inserisce gli elementi utilizzando una interfaccia grafica e il risultato risulta essere parte integrante del database. Un report di Access può avere come origine dei dati sia un tabella che una query precedentemente creata, da cui prendere i record da stampare. FileMaker usa il form editor come editor per i report: l'unica differenza tra form e report sta dunque semplicemente nello scopo per cui il layout viene disegnato. Come in Access, anche in FileMaker un form/report è parte integrante del database. Anche 4D usa il form editor per la creazione dei report. La creazione di intestazioni e subtotali è assimilabile a quella delle altre piattaforme, anche se la mancanza di wizard complessi rende a prima vista meno potente la capacità di reporting di 4D. In realtà, con l'avvento della versione 2003, i programmatori 4th Dimension hanno iniziato ad usare in maniera intensiva un comando diventato potentissimo, PRINT FORM. Questo comando, usato insieme agli altri comandi di gestione di stampa di 4D, permette di avere pieno controllo di un layout: risulta così possibile scegliere quale parte di un form stampare o riempire delle variabili di un form a piacimento a seconda delle necessità, cambiando al volo, da linguaggio font, dimensioni, stili, colori; senza dimenticare la possibilità sempre da linguaggio di orientare il foglio o di conoscere in ogni momento quanti punti del foglio ho già stampato o mi restano da stampare. La differenza tra strumento complesso e strumento flessibile diventa così assai labile. Come per gli altri strumenti, la creazione di un form rende necessario l'aggiornamento del database. Tuttavia lo sviluppatore può mettere a disposizione dell'utente 4D finale il Quick report editor, che permette all'utente di crearsi autonomamente report personalizzati che vengono salvati in file esterni al database e richiamabili in qualsiasi momento. Quick report editor non genera solo semplici stampe ma, a partire da un report, può generare anche dei grafici, dei file di testo o dei file html. Consulta da questo link l’indice delle faq su 4th Dimension, MS Access e FileMaker Pro |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Stringhe identiche in 4th Dimension
Il controllo di uguaglianza di 4D non tiene conto dei caratteri accentati nè della differenza fra maiuscole e minuscole. Ecco un piccolo frammento di codice per controllare se due stringhe sono uguali. Il confronto viene fatto sui valori Ascii dei caratteri. C_STRING(80;$1;$2;$Stringa1_s;$Stringa2_s) C_LONGINT($i) $Stringa1_s:=$1 $Stringa2_s:=$2 $0:=True If (Length($Stringa1_s)#Length($Stringa2_s)) $0:=False Else For ($i;1;Length($Stringa1_s)) If (Ascii($Stringa1_s[[$i]])#Ascii($Stringa2_s[[$i]])) $0:=False $i:=Length($tString1)+5 End if End for End if |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Stile |
Assegnare un valore di default ad un campo testo
Nella finestra "Property list" è possibile assegnare un valore di default ad un campo. Il problema è che il numero di caratteri utilizzabile è 29. Se vengono inseriti più di 29 caratteri, 4D li tronca. La maniera più semplica di aggirare questo ostacolo è di agire via codice: basta inserire il form di input il seguente codice: Case of :(Form event=On Load) If (Is new record([Tabella])) [Tabella]Campo:="il valore che gli voglio assegnare, anche più lungo di 29 caratteri" End if End case Fonte: 4D Tech Tip Knowledge Base, 4DToday |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
L'elenco dei processi senza Runtime Explorer
Per visualizzare l'elenco dei processi e conoscere il processo a cui appartiene un certo form senza aprire il Runtime Explorer basta premere Alt+Shift su Win o Ctrl+Option+Command su Mac e cliccare sul form: viene visualizzato un menu contestuale con l'elenco dei processi (quelli non attivi sono visualizzati come voci disabilitate del menu), e il processo corrente ha accanto un check. La funzione di questo menu è peraltro quella di entrare in modalità Trace per il processo desiderato. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Stile |
Cancellazioni da un array
Il comando DELETE ELEMENT permette di cancellare l'elemento di un array. Per usare questo comando all'interno di un ciclo For bisogna fare attenzione, perchè cancellando un elemento ovviamente diminuisce la dimensione dell'array e cambia anche la posizione degli elementi successivi. Prendiamo come esempio la necessità di cancellare da un array i valori duplicati. Un approccio potrebbe essere: C_TEXT($valore) C_LONGINT($size_L;$i) If (Size of array(MioArray)>0) $size_L:=Size of array(MioArray) SORT ARRAY(MioArray) $valore:=MioArray{1} For ($i;2;$size_L) If ($valore=MioArray{$i}) MioArray{$i}:="" Else $valore:=MioArray{$i} End if End for SORT ARRAY(MioArray) For ($i;1;$size_L) If ((MioArray{1})="") DELETE ELEMENT(MioArray;1) End if End for End if Ma così ho dovuto scorrere due volte il mio array: per scorrerlo solo una volta devo effettuare le cancellazioni durante il primo ciclo, ma con qualche piccolo accorgimento. Infatti, senza usare la variabile $valore e con un solo ciclo for ma che scorra l'array al contrario possiamo ottenere lo stesso risultato: C_LONGINT($size_L;$i) If (Size of array(MioArray)>0) $size_L:=Size of array(MioArray) SORT ARRAY(MioArray) For ($i;$size_L;2;-1) If (MioArray{$i}=MioArray{$i-1}) DELETE ELEMENT(MioArray;$i) End if End for End if |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
Execute on server
Comando: Execute on server Categoria: Processes Versione: 6 Parametri: Execute on server (procedure; stack{; name{; param{; param2; ...; paramN}{; *}}}) : Numero procedure, Stringa : Procedura da eseguire all'interno del processo stack, Numero : Dimensione in byte dello Stack, 128*1024 è un buon numero name, Stringa : Il nome del processo generato param, Expression : Parametri della procedura * = non aprire un altro processo se già in esecuzione con questo nome Valore ritornato, Numero : Numero del processo generato o in esecuzione. Execute on server esegue un nuovo processo sulla macchina server (nella modalità client/server) o in locale (in modalità runtime). Chiamando Execute on server da un client viene ritornato un numero di processo negativo, se viene chiamato dal server un numero positivo. Se il processo non può essere generato il valore ritornato è 0 e viene generato un errore intercettabile con ON ERR CALL. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
Le porte TCP usate da 4D Internet Commands
Esistono tre tipi di porte TCP: - dalla 0 alla 1023: porte che possono essere usate solo da processi di sistema o utenti con privilegi; - dalla 1024 alla 49151: vengono usate per i processi utente; - dalla 49152 alla 65535: porte senza alcuna limitazione. Quindi, per sincronizzare due database attraverso i comandi TCP/IP, devono essere usate porte più alte della 49151. Ecco un elenco dei numeri di porte TCP standard: daytime 13 Daytime qotd 17 Quote of the Day ftp-data 20 File Transfer [Default Data] ftp 21 File Transfer [Control] telnet 23 Telnet smtp 25 Simple Mail Transfer time 37 Time nicname 43 Who Is domain 53 Domain Name Server sql*net 66 Oracle SQL*NET gopher 70 Gopher finger 79 Finger http 80 World Wide Web HTTP poppassd 106 Password Server rtelnet 107 Remote Telnet Service pop2 109 Post Office Protocol – Version 2 pop3 110 Post Office Protocol – Version 3 sunrpc 111 SUN Remote Procedure Call auth 113 Authentication Service sftp 115 Simple File Transfer Protocol sqlserv 118 SQL Services nntp 119 Network News Transfer Protocol ntp 123 Network Time Protocol pwdgen 129 Password Generator Protocol imap2 143 Interactive Mail Access Protocol v2 news 144 NewS sql-net 150 SQL-NET multiplex 171 Network Innovations Multiplex cl/1 172 Network Innovations CL/1 at-rtmp 201 AppleTalk Routing Maintenance at-nbp 202 AppleTalk Name Binding at-3 203 AppleTalk Unused at-echo 204 AppleTalk Echo at-5 205 AppleTalk Unused at-zis 206 AppleTalk Zone Information at-7 207 AppleTalk Unused at-8 208 AppleTalk Unused ipx 213 IPX netware-ip 396 Novell Netware over IP timbuktu 407 Timbuktu https 443 Secured protocol conference 531 chat netnews 532 readnews netwall 533 for emergency broadcasts uucp 540 uucpd uucp-rlogin 541 uucp-rlogin whoami 565 whoami ipcserver 600 Sun IPC server phonebook 767 phone accessbuilder 888 AccessBuilder |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
I file SQL e la struttura di 4th Dimension
E' possibile creare una struttura 4D a partire da un file SQL, usando 4D Insider. Ad esempio supponiamo di avere un file con questo contenuto: CREATE TABLE DITTA ( REF INTEGER, NOME CHAR (25) NOT NULL, INDIRIZZO VARCHAR (200), PRIMARY KEY (REF)); CREATE TABLE CONTATTI ( REF INTEGER, REF_DITTA INTEGER NOT NULL, NOMEC CHAR (20), PRIMARY KEY (REF),FOREIGN KEY (REF_DITTA) REFERENCES DITTA (REF)); CREATE UNIQUE INDEX DIT_IDX ON DITTA (REF); CREATE INDEX NOMEDITTA_IDX ON DITTA (NOME); CREATE UNIQUE INDEX CONTAT_IDX ON CONTATTI (REF); CREATE INDEX NOMECONTATTO_IDX ON CONTATTI (NOMEC); Aprendolo con 4D Insider, verrà creata una struttura con due tabelle (Ditta e Contatti) e una relazione fra esse. Diamo un minimo di sintassi: - CREATE TABLE: crea una tabella; - PRIMARY KEY: indicizza un campo in maniera unica come chiave primaria (duplicati non ammessi); - FOREIGN KEY e REFERENCES: creano una relazione molti a uno; - NOT NULL: rende il campo obbligatorio (mandatory); - CREATE INDEX: indicizza un campo; - UNIQUE: crea un indice senza duplicati. Ecco inoltre un elenco con le corrispondenze fra i tipi SQL e quelli 4D: CHAR, NCHAR: Alpha(2) CHAR(x)*, NCHAR(x)*: Alpha(x) VARCHAR(x): Text CHAR VARYING, NCHAR VARYING: Text LONG VARCHAR: Text TINYINT, SMALLINT: Integer INT, INTEGER: Longint BIGINT, DOUBLE, DOUBLE PRECISION: Real NUMERIC, NUMERIC(x), NUMERIC(x,y): Real DECIMAL, DECIMAL(x), DECIMAL(x,y): Real DEC, DEC(x), DEC(x,y), REAL, FLOAT: Real BIT: Boolean BIT(x), BIT VARYING: BLOB BINARY(x), VARBINARY(x): BLOB LONG VARBINARY: BLOB DATE: Date TIME, TIMESTAMP, TIME WITH TIME ZONE: Time TIMESTAMP WITH TIME ZONE: Time Fonte: 4D Tech Tip library, Ludovic Hanhart, 4DToday |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Tecniche di numerazione
In un form, se si vogliono creare e numerare automaticamente degli oggetti è possibile scegliere il comando da menu "Duplicate many" per duplicare gli oggetti con uno stile "matrice", avendo anche una numerazione automatica per i nomi degli oggetti e delle variabili. Nel caso, invece, di oggetti "sparsi" si può seguire un'altra procedura: - prendiamo un oggetto, ad esempio una variabile, da duplicare più volte; - con Ctrl+D su Win o Command+D su Mac duplichiamo l'oggetto quante volte è necessario (è l'equivalente da tastiera del comando "Duplicate" del menu); - selezioniamo tutti gli oggetti così creati e con Ctrl+Alt premuti (Command+Option su Mac) clicchiamo su uno degli oggetti; - appare una finestra "Increment" che permette di impostare i parametri di numerazione automatica per i nomi delle variabili, che diventeranno così nomevariabile1, nomevariabile2, nomevariabile3, ecc... |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Limiti di 4D: i nomi degli oggetti
Ecco elencati le limitazioni di 4D 2003 sul numero di caratteri dei nomi attribuibili ai vari oggetti del database: Variabili: 31 (esclusi "$" o "<>"); Tabelle: 31; Campi: 31; Metodi: 31; Form: 31; Routine dei plug-in: 31; Set: 80; Named Selections: 80; Processi: 31; Titolo del menu: 15; Elemento del Menu: 31; Nome del menu: 31; List items: 255. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Ottenere le date di 4DTools con un metodo
4DTools aggiorna automaticamente una risorsa all'interno della struttura ogni volta che viene eseguita una operazione di controllo o una riparazione. Il seguente metodo restituisce queste informazioni: ` I parametri: ` $1 - Tipo di informazione da ottenere, i valori accettati sono: ` 1 = Data dell'ultimo controllo del file dati; ` 2 = Data dell'ultima riparazione del file dati; ` 3 = Data dell'ultimo controllo della struttura; ` 4 = Data dell'ultima riparazione della struttura. ` $0 - La data richiesta C_LONGINT($1;$dateType_l) `la variabile locale per $1 C_DATE($ultimadata_d;$0) `la variabile locale per $0 C_BLOB($resData_x) `conterrà la risorsa C_LONGINT($anno_l;$mese_l;$giorno_l) `giorno mese e anno della data C_LONGINT($resID_l) `conterrà l'ID della risorsa C_TIME($resourceDoc_ref) `conterrà il reference number della risorsa aperta. $dateType_l:=$1 Case of : ($dateType_l=1) `ultimo controllo del file dati $resID_l:=3 $resourceDoc_ref:=Open resource file(Data file) : ($dateType_l=2) `ultima riparazione del file dati $resID_l:=4 $resourceDoc_ref:=Open resource file(Data file) : ($dateType_l=3) `ultimo controllo della struttura $resID_l:=1 $resourceDoc_ref:=Open resource file(Structure file) : ($dateType_l=4) `ultima riparazione della struttura $resID_l:=2 $resourceDoc_ref:=Open resource file(Structure file) Else ` Errore End case GET RESOURCE("RegA";$resID_l;$resData_x;$resourceDoc_ref) If (BLOB size($resData_x)>0) $anno_l:=($resData_x{0}*256)+$resData_x{1} $mese_l:=($resData_x{2}*256)+$resData_x{3} $giorno_l:=($resData_x{4}*256)+$resData_x{5} $ultimadata_d:=Add to date(!00/00/00!;$anno_l;$mese_l;$giorno_l)-1 End if $0:=$ultimadata_d `restituisce la deta cercata Fonte: Phillip Hall, 4DToday |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
Application type
Comando: Application type -> Long Integer Categoria: 4D Environment Versione: 6.0 Parametri: Non richiede parametri Risultato: Long Integer - Valore numerico indicante il tipo di applicazione. Descrizione: Il comando Application type restituisce un valore numerico indicante il tipo di ambiente 4D attualmente in esecuzione. 4D fornisce le seguenti costanti (con i relativi valori numerici): 4th Dimension: 0 4D Engine: 1 4D Runtime: 2 4D Runtime Classic: 3 4D Client: 4 4D Server: 5 4D First: 6 Esempio: in un punto qualsiasi di un programma (che non sia il database method On Server Startup) se si vuole controllare se si sta eseguendo 4D Server, si può scrivere: If (Application type=4D Server) `esegui qualcosa End if Comandi correlati: Application version, Version type |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Stile |
Generazione date
La maniera più semplice di ottenere una data avendo tre variabili numeriche che contengono giorno, mese e anno? Ovviamente: $data_d:=Date(String($giorno_L)+"/"+String($mese_L)+"/"+String($anno_L)) Tanto semplice quanto pericolosa! Infatti, se invece del formato DD/MM/YY sul computer ospite ne viene impostato, anche temporaneamente, un altro (ad esempio MM/DD/YY), otteniamo risultati imprevedibili. Per aggirare il problema si può usare un sistema differente: $data_d:=Add to date(!01/01/1900!; $anno_L-1900; $mese_L-1; $giorno_L-1) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
QPix: lettura di un'immagine da file
Un'immagine contenuta in un file del nostro disco può essere letta da QPix con due finalità diverse: - Da file a variabile 4D: il comando QPx_ReadImageFileInPicture legge un file (il cui percorso è il primo parametro) convertendolo, se contiene un file immagine, in un'immagine QuickDraw che viene memorizzata in una variabile (la variabile è il secondo parametro). La velocità di lettura è commisurata alla dimensione e alle caratteristiche dell'immagine di partenza; inoltre bisogna assicurarsi di aver assegnato a 4D la memoria necessaria all'operazione. Ecco un esempio: C_LONGINT($errore_L) C_TEXT($PercorsoFileImm_T) C_PICTURE($immagine_P) $PercorsoFileImm_T:="" `così mostra la finestra di scelta file $errore_L:=QPx_ReadImageFileInPicture ($PercorsoFileImm_T;$immagine_P) If ($errore_L#qpx_noErr) `si può gestire l'errore: `qpx_noErr è una costante che vale 0 `$errore_L vale 0 se non ci sono errori `altrimenti ritorna il codice di errore End if - Da file a area QPix: il comando QPx_SetAreaImageFile mostra in un'area QPix (primo parametro) un file immagine di cui deve essere specificato il percorso (secondo parametro). L'esempio seguente è simile al precedente, eccettuato per la variabile areaQPix_L che contiene il riferimento (un longint) all'area. C_LONGINT($errore_L) C_TEXT($PercorsoFileImm_T) $PercorsoFileImm_T:="" $errore_L:=QPx_SetAreaImageFile (areaQPix_L;$PercorsoFileImm_T) If ($errore_L=qpx_noErr) `nessun errore Else `errore End if |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Uso delle risorse di 4D Client * con metodo aggiorna - signature
Usando 4D in versione client - server, sulla macchina client vengono creati dei file locali (che evitano traffico ridondante sulla rete). Se 4D Client va in crash o ha dei comportamenti inaspettati, il primo tentativo da fare è sicuramente quello di cancellare questi file temporanei, in modo da costringere 4D Client, al prossimo avvio, a ricrearli. Per effettuare la cancellazione manualmente bisogna chiudere 4D Client, quindi cercare una cartella sul disco che si chiama come la struttura che stiamo usando e cancellarla. Alcuni dei posti dove cercare questa cartella possono essere: HD:System Folder:Application Support: (OS9) /Library/Application Support/4D/ (OSX) C:\WINDOWS\4D\ (WIN) Un'altra strada percorribile per ottenere lo stesso risultato è quella di modificare il valore della risorsa "4D4D" nella struttura: in questo caso sarà il server a forzare l'aggiornamento, poiché il valore di questa risorsa deve essere identico fra Server e Client, e 4D Server effettua questo controllo ad ogni connessione. La modifica del valore presente in questa risorsa si può effettuare aprendo la struttura con 4D Customizer Plus e cliccando sull'icona "Update". |
1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comandi |
FLUSH BUFFERS
Comando: FLUSH BUFFERS Categoria: 4D Environment Versione: 3 Parametri: Non richiede parametri Descrizione: Il comando FLUSH BUFFERS salva immediatamente i dati nella cache temporanea su disco: tutte le modifiche effettuate al database vengono salvate. Solitamente non è necessario chiamare questo comando, poiché 4th Dimension si preoccupa di effettuare regolarmente questa operazione. La proprietà del database Flush Data Buffers (nel Design environment), che specifica quanto spesso effettuare il salvataggio, viene usata proprio per controllare la tempistica di questa operazione. Nota: 4D si occupa anche della correttezza delle operazioni effettate sui dati ancora presenti nel file buffer, e in maniera trasparente. Ad esempio l'esecuzione di una query integra tranquillamente i dati presenti nel data file con quelli presenti ancora nel buffer. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Come confrontare due blob
Ecco un metodo semplice per sapere se due blob sono uguali; ovviamente il primo controllo che fa è che siano della stessa lunghezza e poi controlla carattere per carattere. Da notare che in questo modo i caratteri sono contrallati esattamente, cioè un carattere maiuscolo è diverso dallo stesso minuscolo (case sensitive). `Metodo: confrontaBlob `Parametri: ` $1 = Blob; $2 = Blob `Risultato: ` $0: Vero se uguali, altrimenti falso C_BLOB($1;$2) C_BOOLEAN($0) If (BLOB size($1)=BLOB size($2)) $0:=True For ($vByte;0;BLOB size($1)-1) If ($1{$vByte}#$2{$vByte}) $0:=False $vByte:=BLOB size($1) End if End for Else $0:=False End if |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Web |
4D come WebServer: Tag HTML
Usando 4D come webserver si possono costruire pagine semi-dinamiche utilizzando alcuni tag riservati, che hanno il seguente formato (che rappresenta un commento in Html): <--4DVAR variabile--> : viene sostituito dal valore della variabile <--4DVAR campo--> : viene sostituito dal contenuto del campo <--4DVAR espressione--> : viene sostituito dal valore calcolato <--4DVAR metodo--> : viene sostituito dal risultato del metodo <--4DHTMLVAR variabile--> : come sopra, ma il testo viene considerato da elaborare come Html <--4DINCLUDE /percorso/esempio.html--> : viene sostituito dalla pagina indicata <--4DIf (condizione)--> : le righe successive prima dell'endif o dell'Else vengono incluse solo se la condizione è vera <--4DElse--> : se la condizione sopra è falsa vengono incluse le righe successive fino al prossimo endif <--4DENDIF--> : chiude la condizione <--4DSCRIPT/metodo/parametro--> : viene sostituito dal risultato del metodo prima di continuare; al metodo viene passato in $1 il "parametro" <--4DLOOP [Tabella]--> : fa un ciclo sulla selezione corrente della tabella <--4DLOOP array--> : fa un ciclo sulla elementi dell'array <--4DLOOP metodo--> : fa un ciclo passando a metodo un parametro numerico (da 0) che si incrementa automaticamente, finchè il risultato è True <--4DENDLOOP--> : chiude il ciclo 4D elabora questi tag prima di servire: - una pagina inviata con SEND HTML FILE o SEND HTML BLOB (di tipo "text/html") - una pagina con suffisso .shtm, .shtml, .xml, .xsl, .wml (per Wap) - le pagine incluse con <--4DInclude --> |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
La propria icona con 4D Engine 2003
Usando 4D Engine 2003, per ottenere una applicazione con un'icona personalizzata è sufficiente: - copiare l'icona nella cartella che contiene il database, - dare all'icona lo stesso nome dell'applicazione (con l'estensione .ico su Win / .icns su Mac OSX) - a questo punto, generare l'eseguibile. Con Mac OS9 risulta invece necessario andare a modificare manualmente i quattro caratteri della application signature della risorsa di tipo BNDL (inserendone una unica rispetto a qualsiasi altra applicazione). Gli stessi quattro caratteri vanno poi scritti nella risorsa SIG*. A questo punto l'icona dell'applicazione è rimpiazzabile con quella personalizzata andando a modificare le icone nelle risorse icl8, icl4, ICN#, ics#, ics4 e ics8: in ognuna di queste risorse l'icone da aprire è quella con ID 128. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
File |
Metodo Text2Dimensions
Text2Dimensions - Roberto Vergani - maggio 2004 per www.sviluppo4d.it CHE COS'E' Text2Dimensions e' una struttura 4D di esempio dell'uso del method TextDimensions che svolge una computazione analoga alla funzione BEST OBJECT SIZE introdotta con la v 2003 di 4D: ritorna la dimensione grafica in pixel di una stringa di caratteri con determinati attributi tipografici (font, size e style). PERCHE' SCRIVERLA QUANDO ESISTE LA FUNZIONE "BEST OBJECT SIZE"? Semplice, perche' io non ho la v 2003! Lavoro ancora con la 6.7 ed avevo assolutamente bisogno di questa funzione. E CHE CE NE FACCIAMO NOI CHE ABBIAMO LA v 2003? Umberto Migliore dice che puo' essere utile "come esempio di codice che tira fuori da 4D qualcosa di non banale, in fondo lo scopo del sito è educativo" e dato che Umberto e' il migliore lo ascolto, sperando che di fatto possa interessare qualcuno. A questo proposito, il method non e' commentato come piccola sfida ai notevoli talenti che frequentano "sviluppo4d" (dico davvero, l'affermazione non e' ironica!) chi impiega meno minuti a comprendere cosa fa il method vince un sacchetto di camomilla, ammesso e non concesso di avere tempo per queste amenita'. LIMITAZIONI E CARATTERISTICHE Il method e' applicabile a stringhe non ad oggetti. Questo implica che non e' applicabile per esempio ad un Check box, a un Tab control o ad un righello, per contro e' possibile ottenere le dimensioni di una stringa in astratto da method, svincolati dai form, per esempio e' possibile conoscere quanti pixel occupera' "QUESTA STRINGA" con font Helvetica narrow in corpo 36 grassetto corsivo. REQUISITI DI SISTEMA Richiede QuickTime. Sviluppato su Macintosh OS 9.2 con 4D v 6.7 e non mai testato altrove, lo fornisco pero' anche convertito (e testato) con la v 2003 (che ho in versione demo). Quasi sicuramente funzionera' sotto OS X ma non ho provato, ho pero' gia' testato altri miei applicativi che usano le stesse routines di QuickTime e vanno anche sotto OS X. Nessuna idea invece di cosa accada sotto Windows, non e' escluso un crash. ISTRUZIONI Sono contenute nel method e il codice del demo e' autoesplicativo. Se a qualcuno interessera' qualche informazione o un dettagliato commento del codice sono assolutamente disponibile. COPYRIGHT No copyright, assolutamente free. Del resto non servira' a nessuno, comunque io ci metto ugualmente il mio spirito collaborativo. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Codici a barre, conversioni tra Code 39 a Code 32 Farmacod
Non pochi lettori di codici a barre in commercio non gestiscono il Code 32 Farmacod perche' e' usato solo in Italia. In questi casi il Code 32 viene interpretato come Code 39 rendendo inutilizzabile la lettura. Il Code 32 in Italia e' largamente usato non solo per tutti i farmaci ma anche per molti prodotti cosmetici e d'igiene di uso corrente. Questi due brevi method operano le conversioni: ` Conversion from CODE 39 ` to Italian Farmaceutical Code ` for bar code reader ` whithout automatic conversion ` R.V. 29/07/2000 C_TEXT($1;$0) C_REAL($result) C_INTEGER($len;$base10;$base32) $result:=0 $len:=Length($1) For ($X;1;$len) $char:=($1<=($len-$X+1)>=) $base32:=Ascii($char) $base10:=$base32-(48+(8*Num($base32>65))+*Num($base32>69)+*Num($base32>73)+*Num($base32>79)) $result:=$result+($base10*(32^($X-1))) End for $0:=String($result) $0:=("0"*Num(Length($0)=8))+$0 ` Conversion from CODE 39 ` to CODE 32 Farmacod ` (Italian farmaceutical code) ` R.V. 29/07/2002 C_TEXT($1;$0) C_REAL($value) C_INTEGER($X;$codASCII) C_LONGINT($base32) $value:=Num($1) $0:="" For ($X;1;6) $base32:=$value-(Int($value/32)*32) $codASCII:=$base32+48+((8*Num($base32>9))+Num($base32>12)+Num($base32>15)+Num($base32>20)) $0:=Char($codASCII)+$0 $value:=Int($value/32) End for |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Stile |
Ottenere un carattere da una stringa
La maniera più intuitiva per ottenere l'i-esimo (iesimo_L) carattere della stringa MiaStringa_S è usare l'istruzione standard: Substring(MiaStringa_S;iesimo_L;1) Risulta però di certo più facilmente leggibile la sintassi: MiaStringa_S[[iesimo_L]] che restituisce esattamente lo stesso risultato, ma richiede la certezza che la stringa quel carattere lo contiene: cioè che iesmo_L sia minore o uguale alla Length(MiaStringa_S). |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
File |
Component STF
STF è un component che esegue la compressione/decompressione di un documento o di una cartella intera utilizzando come base i blob: - gestisce sia data fork che resource fork (mac); - mantiene type e creator dei file (mac); - mantiene info (data e ora di creazione e di modifica; flag di lock); - filtra file invisibili e nascosti (quelli che sotto OSX iniziano per ".") ed alias; - gestisce file di qualsiasi dimensione; L'utilizzo è molto semplice; dopo averlo installato nella propria struttura, sono a disposizione i seguenti comandi: $err_l:=STF_StuffFolder ($foldername_t;$binHex_b) $err_l:=STF_StuffFile ($filename_t;$binHex_b) $err_l:=STF_Expand ($filename_t) Se il $foldername_t o $filename_t il componente chiede all'utente. Se $binHex_b è True, il file compresso sarà anche codificato in binhex. Se $err = 0 allora ha avuto successo, altrimenti contiene l'errore. Il component è stato realizzato da Italsoftware e reso di pubblico dominio, cioè può essere utilizzato in qualsiasi programma, anche commerciale. Basta includere nella finestra di Info o in un Leggimi di accompagnamento un riconoscimento del tipo "STF component © 2003 Italsoftware" |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Conversione da binario a decimale e viceversa
Ecco due metodi per convertire un numero da binario a decimale e viceversa. Il numero da convertire è il parametro passato. Il numero binario è sempre trattato come stringa. ` DaBinarioADecimale $lunghezza_l:=Length($1) $0:=0 For ($i;0;($lunghezza_l-1)) If ($1[[$lunghezza_l-$i]]="1") $0:=$0 ?+ $i End if End for `DaDecimaleABinario $0:="" For ($i;0;31) If ($1 ?? $i) $0:="1"+$0 Else $0:="0"+$0 End if End for |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Usare 4D Client come fosse l'Engine**
Da un colloquio avuto da poco con Anna Cernuschi di Italsoftware sono venuto a conoscenza di una caratteristica di 4D Server che volentieri condivido. Se i vostri clienti si lamentano perché perché aprire un programma in versione server è troppo lungo (apri il client, scegli l'applicazione corretta, inserisci utente e password), potete creare un file di "scorciatoia" che eviti alcuni o tutti questi passaggi. Aprite l'applicazione dal client e, dal design, andate nella finestra password. Selezionando un utente, si abiliteranno due voci di menu che permettono il salvataggio dell'utente con o senza password. Scegliamo ad esempio di salvare l'utente con password: dalla maschera standard di salvataggio diamo un nome e una posizione al file. Il file creato è di tipo client connection: aprendolo con 4D Client l'utente farà accesso al programma senza dover eseguire la trafila precedentemente descritta, come se avesse l'eseguibile o la struttura in locale sulla sua macchina. |
3 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Intercettare i Comandi di 4D
Nel Runtime Explorer è possibile dire a 4D di interrompere il programma e di entrare in Trace quando esegue un comando in un qualsiasi metodo o script. Ad esempio, se un record viene cancellato durante l'esecuzione di uno o più processi, puoi intercettare l'operazione aggiungendo un controllo per i comandi DELETE RECORD e DELETE SELECTION: ogni volta che questi comandi saranno chiamati puoi controllare se sta per essere cancellato il record in questione. Dopo aver aperto il Runtime Explorer (Ctrl-Shift-F9 su Windows o Command-Shift-F9 su Macintosh) basta andare nel pannello "Catch" e qui si può: - aggiungere o modificare un comando con un doppio clic, - sceglierlo da una lista usando il tasto destro su Windows o Ctrl-click su Macintosh, - disabilitarlo temporaneamente senza toglierlo dalla lista facendo clic sul pallino a sinistra del comando - aggiungere un'espressione per avere l'interruzione solo in una certa condizione. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novizi |
Uso dei comandi in mono o multi utenza
Molti comandi 4D si possono comportare in maniera differente a seconda che vengano usati in versione monoutente o multiutente. Ad esempio QUIT 4D permette di chiudere l'applicazione 4D. Se il comando viene però inserito in una "stored procedure", cioè in un processo da far eseguire al server, è possibile passare al comando un parametro numerico che indica quanti minuti attendere prima della chiusura. Altro esempio può essere dati dai comandi "Current time" e "Current date", che solitamente restituiscono la data e l'ora della macchina su cui si sta lavorando; passando come parametro un asterisco, i dati restituiti saranno quelli relativi al server: questo risulta ad esempio molto utile quando si vuol essere certi della cronologia delle operazioni, in modo da usare una sorta di "orologio unico" per tutti i client. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
4D non vuol restare ridotto a icona
Sotto Windows succede sovente che 4D o 4D Server, benché ridotti ad icona, tornino improvvisamente visibili. Questo accade quando la cache viene scritta fisicamente sui dati (appaiono i famosi dischi in basso a sinistra). Se questo comportamento risulta "fastidioso" è possibile disabilitare la visualizazione dell'indicatore di "Flush Buffers": basta aprire l'applicazione 4th Dimension o 4D Server col Customizer Plus e, andando in "Preferences", disabilitare la voce "Display flush window". |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Break Point condizionali
Quando si vuole andare in trace su una riga di codice occorre cliccare sulla colonna a sinistra della finestra del programma e appare un pallino rosso o Break Point dove l'esecuzione va in Trace. Facendo un clic su questo pallino rosso mentre si preme il tasto Alt (Windows) o il tasto Option (Mac) appare una finestra dove: - posso dire che è un break point Temporaneo, cioè mi serve interrompere il codice solo una volta (il colore diventa verde) - posso dire di andare in Trace solo in certe condizioni; ad esempio se sto aggiornando un milione di anagrafiche, e voglio controllare che cosa fa il codice solo quando arriva su un determinato record scrivo [Anagrafica]Città="Modica". Per essere sicuri di aver scritto correttamente c'è anche un pulsante che controlla la sintassi dell'espressione scritta. - posso saltare un certo numero di passaggi prima del trace; ad esempio se ho un problema verso la fine di un ciclo For($i;1;400), posso impostare di andare in trace solo dopo 350 passaggi. - posso disabilitare il break point (il pallino diventa un trattino) senza doverlo cancellare se magari dovesse riservire in futuro. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Controllo del Codice IBAN
L’IBAN (International Bank Account Number) è la coordinata bancaria internazionale che consente di identificare, in maniera standard, il conto corrente del beneficiario permettendo all’ordinante o alla banca di quest’ultimo di verificarne la correttezza grazie ai due caratteri di controllo. La struttura dell’IBAN per l’Italia è fissata in 27 caratteri: 1) IT = ISO Country Code, identificativo per l'italia (SM per San Marino) 2) 1 = CIN carattere alfabetico di controllo 3) 5 = ABI o Bank Code solo numeri 4) 5 = CAB o Branch Code solo numeri 5) 12 = C/C numero di conto (solo numeri riempito a sinistra di zeri) Potete trovare nfo più dettagliate sul sito: http://www.ecbs.org/iban.htm `Marco Caratto 5-3-2004 `procedura di verifica codice IBAN, restituisce True se corretto C_TEXT($1;$V_Tx_Deposito;$V_Tx_StringaRisultante) C_INTEGER($V_I_conta;$V_I_Carattere;$V_I_Resto) ` variabile contatore C_BOOLEAN($0) $0:=True ` imposto il default a vero $V_Tx_StringaRisultante:="" ` variabile per la stringa di controllo $V_I_Resto:=0 ` variabile per il resto della divisione per 97 If (Length($1)<5) ` se la lunghezza del iban è inferiore a 5 è sbagliato $0:=False Else ` metto i primi 4 caratteri in coda $V_Tx_Deposito:=Substring($1;5)+Substring($1;1;4) If (Substring($1;3;2)>"96") $0:=False ` il codice di controllo non può essere superiore a 96 Else For ($V_I_conta;1;Length($V_Tx_Deposito)) ` esamino il$V_I_conta esimo carattere $V_I_Carattere:=Ascii(Substring($V_Tx_Deposito;$V_I_conta;1)) If (($V_I_Carattere>=48) & ($V_I_Carattere<=57)) ` per cifra 0-9 If (($V_I_conta=(Length($V_Tx_Deposito)-3)) | ($V_I_conta=(Length($V_Tx_Deposito)-2))) $0:=False ` il primo ed il secondo carattere non possono essere numeri End if $V_I_Numero:=$V_I_Carattere-48 Else If (($V_I_Carattere>=65) & ($V_I_Carattere<=90)) ` per cifra 0-9 If (($V_I_conta=(Length($V_Tx_Deposito)-1)) | ($V_I_conta=(Length($V_Tx_Deposito)))) $0:=False ` il terzo ed il quarto carattere non possono essere lettere End if $V_I_Numero:=$V_I_Carattere-55 End if End if If ($V_I_Numero>9) $V_I_Resto:=Mod((100*$V_I_Resto+$V_I_Numero);97) Else $V_I_Resto:=Mod((10*$V_I_Resto+$V_I_Numero);97) End if End for $0:=($V_I_Resto=1) ` se il resto finale è 1 il codice è corretto End if End if |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Passaggio da Subtable a Tabella in relazione
Le Subtable sembrano comode, ma per loro natura hanno molti limiti. In genere succede che dopo qualche tmepo si ha la necessità di usare invece una tabella in relazione. Ecco come fare il passaggio (in linea generale): - creare una tabella secondaria con gli stessi campi della subtable più un campo chiave che identifichi il record padre; - tirare una relazione dalla tabella secondaria alla primaria e impostare gli automatismi Molti a Uno e Uno a Molti: in questo modo quando si seleziona il record padre si ha quasi sempre selezionati i sotto-record nella tabella secondaria (in alcuni casi aggiungere comunque nel codice un Relate Many) - cercare con l'insider tutte le occorrenze dei campi nella sottotabella e sostituirli con i campi della tabella secondaria; - cercare tutti i query subrecords, order subrecords by, etc e sostituirli con comandi che abbiano la stessa funzione (ad esempio: all subrecords dovrebbe diventare relate many, create subrecords diventa create record ed in più impostare il campo chiave, etc) - passare i dati dalla subtable alla nuova tabella, usando un codice come il seguente: ALL RECORDS([TabellaPadre]) For ($i;1;Records in selection([TabellaPadre])) LOAD RECORD([TabellaPadre]) ALL SUBRECORDS([TabellaPadre]CampoSubT) For ($j;1;Records in subselection([TabellaPadre]CampoSubT) CREATE RECORD([TabellaSecondaria]) `impostiamo il campo chiave che distingue il padre [TabellaSecondaria]Campo_1:=[TabellaPadre]Campo_Chiave `questi invece sono gli stessi campi [TabellaSecondaria]Campo_2:=[TabellaPadre]CampoSubT'Campo_1 [TabellaSecondaria]Campo_3:=[TabellaPadre]CampoSubT'Campo_2 SAVE RECORD([TabellaSecondaria]) NEXT SUBRECORD([TabellaPadre]CampoSubT) End for UNLOAD RECORD([TabellaPadre]) NEXT RECORD([TabellaPadre]) End for |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Alternativa a USE SET
Quando nelle liste l'utente seleziona un record su cui eseguire l'azione di un pulsante, in genere si usa l'istruzione USE SET("Userset") che ha l'effetto collaterale di perdere la selezione corrente inclusa del suo ordinamento. E' possibile invece usare questo breve metodo che va a puntare al record selezionato dall'utente e ne fa il record corrente, senza modificare la selezione. `Nexus srl 17-7-2003 `http://www.nexusonline.it ARRAY BOOLEAN($set_ab;0) ARRAY LONGINT($record_al;0) C_LONGINT($numeroRecord_l) C_POINTER($pTable) If (Nil(Current default table)) $pTable:=Current form table Else $pTable:=Current default table End if BOOLEAN ARRAY FROM SET($set_ab) `UserSet è il Default $numeroRecord_l:=Find in array($set_ab;True;0) `nota lo start = 0 LONGINT ARRAY FROM SELECTION($pTable->;$record_al) GOTO SELECTED RECORD(Find in array($record_al;$numeroRecord_l)) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Forzare l'esecuzione dell'evento On Validate
La pressione di un pulsante in un form di input che esegue un Accept non comporta automaticamente che venga generato un evento On Validate. Questo accade solo nel caso in cui 4D si accorga che un campo è stato modificato. Una maniera molto semplice ma al contempo elegante che consenta al programmatore di eseguire questa "forzatura" consiste nel creare un metodo con questo codice: C_POINTER($1;$field;$table) $table:=$1 $field:=Field(Table($table);1) `punta al primo campo della tabella :-))) $field->:=$field-> `si assegna a se stesso, tipo particella di sodio Questo forza l'esecuzione dell'evento On Validate. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Come simulare l'apertura a tendina di una finestra in stile OS X
E' possibile con 4D simulare l'apertura e la chiusura a tendina in stile OS X con dei semplici cicli di For ... End for, al cui interno viene incrementata o diminuita la lunghezza del 'bottom' della finestra mediante il comando SET WINDOW RECT. La finestra da aprire dovra' avere una altezza di partenza uguale a 0 e dovra' essere ridimensionabile ad un'altezza massima desiderata nota. A questo punto sara sufficiente inserire nel form event=On Load della finestra a tendina: Case of : (Form event=On Load ) C_LONGINT($i) For ($i;0;250;25) SET WINDOW RECT((vright-300)-300;vtop;(vright-300)+300;vtop+$i;WPU) End for End case e nel pulsante di chiusura della finestra o nel form event=On Close Box: Case of : (Form event=On Close Box ) For ($i;0;250;25) SET WINDOW RECT((vright-300)-300;vtop;(vright-300)+300;vtop+250-$i;WPU) End for CANCEL End case I parametri (vright; vtop; etc.) di posizionamento della finestra a tendina all'interno di un'altra finestra sono stati precedentemente acquisiti con il comando GET WINDOW RECT riferito alla finestra esterna. La velocità di apertura e chiusura della finestra a tendina potrà essere modificata variando lo 'step' del ciclo di for. Non e' OS X ma cerca di avvicinarsi. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novizi |
Impedire l'accesso ai metodi all'utente finale
L'utente finale del vostro software 4th Dimension può facilmente conoscere i metodi che lo compongono dagli elenchi che compaiono in alcune finestre aperte da "Order by" e "Quick Report". In alcuni casi (per i metodi che ritornano un valore utile) questo accesso è voluto e necessario, ma nella maggior parte dei casi può potenzialmente essere dannoso. La soluzione è abilitare la proprietà "Invisible" per i metodi che si vogliono nascondere; con la versione 2003 si può usare la comoda opzione "Batch setting of attributes" per modificare le proprietà di più metodi contemporaneamente. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Evitare il copia-incolla delle proprie password
Sebbene sia possibile nascondere il contenuto di una variabile usando il font "password" di 4D, il contenuto della variabile può comunque essere copiato negli appunti e quindi poi facilmente visualizzato! Il secondo esempio riportato sul manuale del linguaggio di programmazione di 4D per il comando FILTER KEYSTROKE aggira il problema attraverso l'uso di due variabili: una (quella contenuta nel form) contiene dei caratteri casuali, l'altra invece, non visibile, contiene la password reale. Eccone lo stralcio: ` userPassword_t è l'oggetto del form e questo è il metodo di questo oggetto Case of : (Form event=On Load ) userPassword_t:="" PasswordAttuale_t:="" : (Form event=On Before Keystroke ) `il metodo Handle keystroke è da copiare dalla faq corrispondente Handle keystroke (-> userPassword_t;-> PasswordAttuale_t) If (Position(Keystroke;Char(Backspace )+Char(Left Arrow Key )+Char(Right Arrow Key )+Char(Up Arrow Key )+Char(Down Arrow Key ))=0) FILTER KEYSTROKE(Char(65+(Random%26))) End if End case |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Il font Password
Se si vuole nascondere il testo inserito in una variabile di un form, ad esempio perché vogliamo gestire autonomamente delle password, è possibile assegnare all'oggetto il font "password" di 4D, che non è un font rintracciabile nei menu dei font, ma deve essere assegnato attraverso il lunguaggio di programmazione di 4th Dimension con un'istruzione del tipo: FONT(userpassword_t;"%Password") |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Print form e PDF
A partire dalla versione 2003, 4D mette a disposizione numerosi strumenti per il controllo delle stampe complesse, in aggiunta e a completamento del comando Print form. In particolare questi comandi risultano molto utili nella gestione dei PDF da generare con Print form. Molto spesso si ha il problema di non poter gestire correttamente il salto pagina, il che comporta o la generazione di un numero considerevole di file pdf o la stampa di solo alcune pagine. Una soluzione può essere quella di ottenere la dimensione della parte stampabile della pagina col comando GET PRINTABLE AREA e utilizzare la caratteristica di Print form di restituire come risultato la dimensione del form stampato e/o il comando Get printed height per conoscere la dimensione complessiva della pagina stampata. In questa maniera, quando necessario e corretto, può essere invocato un PAGE BREAK(>) che forzi il cambio di pagina, in maniera tale che tale interruzione sia quindi gestita dal programmatore e non dal driver pdf. Al termine della generazione della stampa è sempre necessario il PAGE BREAK conclusivo. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Limitare l'inserimento di caratteri in una variabile
Inserendo del testo in un campo di tipo Alpha, all'utente viene automaticamente impedito di inserire un numero di caratteri maggiore del numero di caratteri che il campo stesso può contenere. È possibile sviluppare un metodo che simuli questa caratteristica anche nelle variabili intercettando gli eventi On Before Keystroke e On After Keystroke. Il metodo risultante, prendendo come parametri il puntatore alla variabile e il numero di caratteri consentiti, potrebbe avere questa forma: Case of :(Form event=On Before Keystroke) VecchiaVariabile_t:=Get edited text `il testo prima dell'inserimento :(Form event=On After Keystroke) If (Keystroke#Char(Backspace Key)) `escludo la cancellazione $attuale_t:=Get edited text If (Length($attuale_t)>$2) $1->:=VecchiaVariabile_t BEEP End if End if End case |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Visualizzare il dettaglio in una finestra diversa dalla lista
In automatico le applicazioni 4th Dimension visualizzano il layout di input nella stessa finestra in cui era visualizzato quello di output. Per fare in modo che invece venga aperta una nuova finestra è necessario abilitare l'evento On Double Clicked nel form di output e scrivere nel metodo del form alcune righe tipo queste: Case of :(Form event=On Double Clicked) FILTER EVENT IlMioMostraRecord(Current form table) End case Quando l'utente esegue un doppio clic su un record, 4D lo intercetta; a questo punto l'istruzione FILTER EVENT dice a 4D di non gestire in automatico l'evento e invece eseguire il mio metodo personalizzato di visualizzazione. Il metodo potrebbe avere una forma di questo tipo: C_POINTER($1;$table_ptr) $table_ptr:=$1 $recordNumber_l:=Record number($table_ptr->) UNLOAD RECORD($table_ptr->) $processName_t:="Input" $processNumber_l:=New process("MostraRecord2";64*1024;$processName_t;$table_ptr;$recordNumber_l;Current process;*) If ($processNumber_l>0) BRING TO FRONT($processNumber_l) End if |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novizi |
I cicli infiniti dei subform
Quando si usano i subform in un form di input, può capitare, durante la fase di sviluppo, di imbattersi in errori del tipo "Unable to Read Record" che vengono mostrati apparentemente all'infinito (questo capita solitamente quando la selezione del subform cambia in maniera inaspettata). Per uscire da questo ciclo, fare Command+Ctrl+Clic su Mac o Ctrl+ClicDestro+ClicSinistro Contemporaneamente su Win mentre viene mostrata la finestra di errore per spostare la finestra che contiene il subform in maniera tale che quest'ultimo non sia più visibile sullo schermo. 4D non cercherà più di caricare il record e il messaggio non verrà più mostrato. A questo punto è possibile premere il pulsante di chiusura (o Command+Punto o Ctrl+Punto) per chiudere la finestra. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Spostare una finestra di cui non vedo la barra del titolo
Una finestra di una applicazione 4D può essere spostata cliccandone un punto qualsiasi: - su Mac, cliccando tenendo premuti i tasti Control e Command; - su Win, cliccando con entrambi i tasti del mouse tenendo premuto il tasto Control. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Riconoscere l'OS 9 reale o Classic in OS X
Col comando PLATFORM PROPERTIES è possibile sapere se stiamo usando Mac OS 9 o OS X, ma non se il 9 che stiamo usando è in modalità nativa o compatibile (Classic). Per conoscere la versione di OS 9 in uso possiamo usare il comando Gestalt col parametro "bbox" in questo modo: C_LONGINT($gestaltVal;$error) C_BOOLEAN($isClassic) $error:=Gestalt("bbox";$gestaltVal) $isClassic:=(($error=0) & ($gestaltVal#0)) Fonte: Danis Georgiadis, Escape Technologies, 4DToday |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Metodo di Invio Mail da 4D
C_LONGINT($Smtp_l;Errore_l) C_STRING(30;$SmtpUser_s;30;$SmtpPassword_s) C_TEXT($SmtpServer_t;$Mittente_t;$Destinatario_t;$Titolo_t;$Testo_t) $SmtpServer_t:="mail.sviluppo4d.it" $Mittente_t:="sito@sviluppo4d.it" $Destinatario_t:="umigliore@nexusonline.it" $Titolo_t:="Messaggio di Prova" $Testo_t:="Ti sto inviando un messaggio di prova" ` queste due variabili servono se il server richiede l'autenticazione ` è possibile altrimenti lasciarle vuote $SmtpUser_s:="sito" $SmtpPassword_s:="miapassword" ` questi due comandi automatizzano la conversione dei caratteri accentati ` serve lanciarli una volta sola allo startup del programma SMTP_SetPrefs(1;1;0) $Errore_l:=SMTP_Charset(1;1) $Errore_l:=SMTP_New($Smtp_l) $Errore_l:=SMTP_Host($Smtp_l;$SmtpServer_t) $Errore_l:=SMTP_From($Smtp_l;$Mittente_t) $Errore_l:=SMTP_To($Smtp_l;$Destinatario_t) $Errore_l:=SMTP_Subject($Smtp_l;$Titolo_t) $Errore_l:=SMTP_Comments($Smtp_l;"Inviato con 4th Dimension") $Errore_l:=SMTP_Body($Smtp_l;$Testo_t) $Errore_l:=SMTP_Auth($Smtp_l;$SmtpUser_s;$SmtpPassword_s) $Errore_l:=SMTP_Send($Smtp_l) $Errore_l:=SMTP_Clear($Smtp_l) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
QGrid: un'introduzione
QGrid è il plug-in della Escape che permette la visualizzazione di un insieme immagini in un form 4D. L'approccio è agevole e la possibilità di personalizzazione elevata. Ogni cella può contenere due elementi: l'immagine e il testo, le cui proprietà come posizione e dimensione sono modificabili al livello di pixel; sul testo è possibile inoltre controllare font, colore, allineamento. È possibile usare uno sfondo personalizzato per le immagini. QGrid permette di utilizzare il drag and drop degli oggetti, con un completo controllo da parte dello sviluppatore degli eventi. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novizi |
La finestra iniziale di una applicazione 4D
All'avvio di una applicazione, 4D mostra una finestra standard di avvio. Questa finestra è molto personalizzabile. È possibile, ad esempio cambiarne l'immagine contenuta così: - copiare negli appunti l'immagine che si vuole mostrare; - scegliere la gestione dei menu nel design environment dell'applicazione, il menu di partenza e poi la voce nel menu "custom menu"; - incollare l'immagine. A questo punto potrebbe essere necessario modificarne la dimensione all'avvio. Per fare questo si agisce sulla struttura aprendola col Customizer e scegliendo il tipo di "apertura" e, se serve, la dimensione. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novizi |
Nascondere la finestra iniziale di una applicazione 4D
E' possibile non mostrare completamente la finestra di avvio di una applicazione 4th Dimension. Basta aprire la struttura col Customizer e nella sezione Window scegliere Hide window nel pop-up menu "Choose screen size". Nascosta la finestra, è anche possibile ripristinarla andando nella modalità User della struttura e premendo Ctrl+U (Win) o Cmd+U (Mac) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novizi |
Creare automaticamente un messaggio di posta
Il comando OPEN WEB URL permette di aprire un link. Seguendo lo stesso principio, il comando si può usare anche in una qualsiasi applicazione 4th Dimension nella forma: OPEN WEB URL("mailto:nome@dominio.dom") per creare un messaggio di posta dall'interno di un programma 4D. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
DLL Wizard: un'introduzione
Se (solo su Windows) trovate una DLL che risolve un vostro problema, potete utilizzarla come se fosse un plug-in generando il codice relativo con DLL wizard. Tutto avviene molto semplicemente: dovete dare un nome al plugin, dire quale è la DLL di origine, il tipo di dati utilizzato dalla DLL come parametro. Eseguiti questi passaggi, vengono creati due file da inserire nella cartella win4dx e a questo punto la funzione della DLL scelta è "invocabile" come se fosse un plugin all'interno del vostro software 4th Dimension. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
La sintassi di MULTI SORT ARRAY
Con la versione 2003 è stato introdotto il comando MULTI SORT ARRAY, per permettere l'ordinamento multilivello di una serie di array sincronizzati. Inizialmente la sintassi di questo comando prevedeva il passaggio di due parametri, due array. Il primo array doveva contenere i puntatori agli array da ordinare, il secondo dei numeri che indicavano il tipo di ordinamento. A partire dalla versione 2003.2 la sintassi è stata notevolmente semplificata. Infatti ora è possibile usare una sintassi molto simile a quella che si usa per il comando ORDER BY, e cioè "nome_dell'array;{senso_di_orientamento};nome_dell'array2;{senso_di_orientamento};e_così_via", dove senso di orientamento o viene omesso (il che signifiva nessun ordinamento), oppure è uno dei due simboli ">" o "<"; con "ecc." indichiamo ovviamente l'infinito numero di array che il comando accetta come parametro. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Sviluppo plugin in modalità console
Quando si sviluppa del codice per creare dei plugin conviene sempre selezionare dal proprio tool preferito un progetto per console, anche quando si vuole creare un plugin che lavora con le aree. Questo facilita molto l'integrazione successiva del codice con il wizard di 4d, permettendo di dichiarare le funzioni e/o procedure che si vuole rendere disponibili solo nella fase finale. Generando prima il codice con il wizard di 4D, si rischia di doverlo rigenerare più volte per modificare le funzioni. L'altro vantaggio è che una prima fase di test può essere svolta indipendentemente da 4D. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Stile |
Dare un nome alle variabili
Scegliere il nome delle variabili è importante, anche se in certi casi sembra rallentare il processo produttivo. Propongo qui una serie di regole (come base di proposta) per uniformare lo stile dei nomi usati. 1. il nome dovrebbe essere indicativo del contenuto 2. se servono più parole si usa la prima lettera maiuscola per le parole successive alla prima (es. mioSetDiValori) 3. il nome degli indici dei cicli For può essere breve: si usa di solito $i, $j, $k, .. 4. la prima parte o prefisso serve a indicare il componente o il gruppo di metodi all'interno del quale viene usata la variabile. Ad esempio, se ho scritto un gruppo di procedure che servono a gestire il web chiamerò le variabili dentro questo gruppo con il prefisso "web_contatore", "web_user" 5. un seconda modalità di usare il prefisso (specialmente nel passato, prima dei componenti e delle variabili interprocesso) le regole suggerivano di usare una lettera di prefisso per indicare il tipo di variabile: ad esempio: - "bOk" è la variabile legata ad un oggetto di tipo pulsante - "kColoreSfondo" è una variabile usata come costante (non muta il contenuto) - "gNome" è una variabile condivisa da più maschere - "vNome" è una variabile normale all'interno di una maschera o un ciclo di procedure. 6. la parte finale o suffisso può servire ad indicare il tipo di variabile che si sta usando; è spesso usata una lettera o una sigla mnemonica (SanityCheck permette di controllare in automatico che il nome sia coerente con la dichiarazione) Tabella esempio dei suffissi intero_i interoLungo_l reale_r testo_t stringa_s data_d ora_h booleano_b immagine_pic puntatore_ptr blob_blb arrayInteri_ai arrayInteriLunghi_al arrayReale_ar arrayTesti_at arrayStringhe_as arrayDate_ad arrayTime_ah arrayBooleani_ab arrayImmagini_apic arrayPuntatori_aptr |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
4D ODBC: un'introduzione
Lo standard ODBC definisce un protocollo di comunicazione che permette ad una applicazione di interrogare in database attraverso istruzioni SQL. 4D OBBC fornisce un insieme di comandi che permettono a un database 4D (Mac e/o Win) di comunicare con un database ODBC. Per comprendere la semplicità di utilizzo del plugin, basti pensare che servono tre istruzioni per iniziare a utilizzarlo: - OC Login dialog per scegliere l'origine dei dati (questo comando restituisce un ID per la connessione ODBC); - OC Execute SQL per eseguire una query SQL; - OC LOGOUT per chiudere la connessione. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novizi |
Prima introduzione a 4d: SUBTABLE
Un ultimo consiglio per evitare difficolta' in cui cascano in molti, anche sviluppatori professionisti, e in cui a suo tempo caddi anch'io: avrai notato che quando si creano nuovi campi in un file, tra i molti tipi esiste anche il type Subtable che, come dice il nome stesso, e' un campo che a sua volta e' un file subordinato al primo in cui possono essere creati altri campi. Se un file ha un campo Subtable, ogni record avra' i suoi subrecord, per esempio: Nome : ALBERTO Nato : 23-10-1960 Interventi--------------(subtable) Tonsillectomia 16-09-1967 Appendicectomia 01-06-1980 Nome : GIUSEPPE Nato : 23-10-1940 Interventi--------------(subtable) Criptorchidia 21-05-1942 Ernia inguinale 13-02-1970 Nefrotomia 16-11-1995 Ecco, l'errore in cui si casca piu' o meno tutti e' quello di considerare il Subtable come un file a tutti gli effetti, come ho fatto nei due esempi di record che ho tracciato. NO, non farlo perche' i subrecords sono di difficile gestione (per esempio non possono essere indicizzati); in questi casi sempre creare un file vero e proprio, un file "figlio" collegato al "padre" con le potenti relazioni di 4D. I subtables vanno considerati solo come campi a valenza multipla, in cui accumulare dati solo descrittivi che non necessitano di ricerche veloci o elaborazioni complesse. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novizi |
Prima introduzione a 4d: METODI [procedure, scripts]
In 4D si puo' inserire codice eseguibile a molti livelli che sono ordinati in modo gerarchico. Analogamente a moltissimi altri ambienti di sviluppo il codice puo' essere associato ad eventi o eseguito su esplicito comando (o chiamata). Vediamo una panoramica di dove si puo' inserire codice eseguibile. DataBase Methods: Accessibili solo dall'Explorer, videata "Methods", aprire la voce "DataBase Methods", c'e' l'elenco. Sono Methods gia' presenti nella struttura e vengono eseguiti quando vengono generati eventi globali, come aprire la base dati o uscire da 4D. Se per esempio vuoi che il tuo programma saluti sempre l'utente quando finisce di lavorare, puoi mettere l'istruzione: Alert ("Bye bye.") nel Database Method "On Exit". Questo codice verra' eseguito ogni volta che si esce da 4D, indipendentemente da quale sia l'ambito o la procedura o il codice che abbia provocato l'uscita. I database method si usano solo per azioni di carattere generale e globale, come per esempio controllare su quale sistema operativo sta girando il programma, chiudere tutti i processi uscendo da 4D e cose del genere. Triggers: Accessibili dall'Explorer, videata "Methods", aprire la voce "Form Methods & Triggers", doppio clic sul nome di un Table per aprire il suo trigger. Sono Methods gia' presenti nella struttura e legati ai Tables, ogni Table ha il suo Trigger; il Trigger di un Table viene eseguito quando vengono generati eventi globali (Database Events) che accedono a quel table, come salvare un record, cancellare un record, ecc. Vedi il manuale alla voce Trigger per dettagli, ma non ora. Project Methods: Accessibili dall'Explorer, videata "Methods", aprire la voce "Project Methods", c'e' l'elenco; oppure quando il nome di un method e' usato nel codice basta selezionarlo e scegliere la voce Edit Method dal menu Design (su Mac tasti mela-P). Sono procedure create dallo sviluppatore, accessibili ovunque nella base dati e sono eseguite solo su esplicita chiamata, nel senso che ignorano gli eventi. Possono essere chiamate da un menu' o da un qualunque altro methods, ovunque si trovi. Per esempio, per accedere all'Archivio dei Clienti potrai scrivere un Method che organizza la cosa: dichiarare quale form usare per la lista dei record, quale form per editare il singolo record, scegliere una selezione di record, aprire una finestra e mostrare all'utente la schermata per permettere l'accesso alle registrazioni. Questo method che accede all'Archivio Clienti potra' poi essere eseguito da un menu o, come esempio, da un pulsante in un form: nell'archivio fatture puoi mettere un pulsante "Clienti" che chiama quel method ed apre la finestra con l'Archivio Clienti. Dato che i Project Methods sono accessibili ovunque, possono essere usati anche come subroutine o concepiti come funzioni perche' e' possibile passare dati da un Method ad un altro. I dati passati tra methods si chiamano parametri, vedi il manuale alla voce Project Methods. Per esempio, se in molti punti del tuo programma devi eseguire lo stesso calcolo su un campo, e' sciocco riscrivere ogni volta le stesse istruzioni, basta creare un method e usarlo ovunque serva, questo non solo fa risparmiare tempo ma - soprattutto - rende la struttura piu' modulare, piu' facile da mantenere e da correggere (ma queste sono linee guida generali per la programmazione che tutti conosciamo). Tutti i Project Methods creati dallo sviluppatore vengono aggiunti all'elenco dei comandi che compare nella finestra di editing dei method, proprio per inserirli agevolmente nel proprio codice. Form Methods: Accessibili dall'Explorer, videata "Methods", aprire la voce "Form Methods", c'e' l'elenco dei Tables, aprire un table e c'e' l'elenco dei form method (hanno lo stesso nome dei forms). Sono eseguiti quando vengono generati eventi nei Form, come cliccare, inserire dati e moltri altri. Object Method (contenuti negli oggetti presenti nei forms): Accessibili aprendo la finestra delle proprietà di un oggetto con doppio clic su di esso, oppure con un solo clic tenendo premuto il tasto opzione (su Mac). Sono eseguiti quando vengono generati eventi sull'oggetto, come cliccare o inserire dati. Possono essere eseguiti anche quando vengono generati eventi del form cui appartengono. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novizi |
Prima introduzione a 4d: EVENTI e gerarchia esecuzione
Lasciamo stare per ora i Database Method e i Triggers. I Project Method dovrebbero essere abbastanza chiari. Vediamo invece come fare in modo che 4D esegua quello che vogliamo quando lavoriamo in un form. Nelle finestre delle proprieta' dei Form esiste la videata degli eventi, che elenca tutti gli eventi a cui puo' reagire il Form Method; alcuni sono gia' attivati per default. Quando viene generato un evento, per esempio cliccare, se il form ha l'evento "On clicked" attivo, verra' subito eseguito il Form Event di quel form. Tutti gli eventi che sono attivati chiamano sempre il form event del form e non altro. Se provi ad inserire l'istruzione BEEP nel form event di un form e poi, passando in ambiente user, usi quel form per editare un record, sentirai una serie numerosa di beep, uno per ogni evento attivo: un beep quando il record viene caricato e prima di mostrarlo (On load), uno se clicchi, uno se modifichi un campo e cosi' via. Allora prova a inserire nel form event queste istruzioni: If (Form Event=On Clicked) beep End if il beep sara' udibile solo se clicchi e non se esegui altre azioni. Come vedi puoi eseguire delle istruzioni nel form method solo a seguito di eventi scelti da te: devi attivarli nella finestra delle proprieta' del form e scrivere istruzioni che eseguano quello che vuoi quando accade un determinato evento; anche per piu' eventi, ovviamente: Case of :(Form Event=On Load) istruzioni da eseguire prima che il record sia mostrato :(Form Event=On Clicked) istruzioni da eseguire se si clicca nel form (ovunque) :(Form Event=On Validate) istruzioni da eseguire dopo conferma del record End case Anche gli Object methods lavorano allo stesso modo, sono sensibili ai form event; devi attivare gli eventi nella finestra delle proprieta' dell'oggetto e poi scrivere le tue istruzioni. Per esempio, se vuoi eseguire un calcolo su un valore inserito dall'utente, immediatamente, appena riempito il campo, puoi attivare l'evento "On Data Change" e scrivere le tue istruzioni. Facciamo un esempio pratico prendendo spunto dalla richiesta di Pasquale. Devi calcolare a che eta' un paziente ha subito un intervento chirurgico. Nel form ci saranno diversi campi e un campo (o una variabile) in cui l'utente inserisce la data dell'intervento, chiamiamolo Data_Intervento e assumiamo che esista anche il campo Data_Nascita; nel definire il campo Data_Intervento attiviamo l'evento "On Data Change" (e disattiviamo gli altri eventi altrimenti il codice viene eseguito continuamente) e scriviamo questa istruzioni: $risultato:=year of(Data_Intervento) - year of(Data_Nascita) in questo esempio ho assegnato il risultato alla variabile locale $risultato, ma e' solo un esempio. Naturalmente il codice puo' essere piu' completo, con un minimo di controllo sulla coerenza dei dati inseriti dall'utente: If (Data_Intervento # !00-00-00!) se utente ha inserito una data If (Data_Nascita = !00-00-00!) se non inserita data di nascita beep alert("Devi prima inserire la data di nascita.") Data_Intervento:=!00-00-00! azzera il dato inserito goto area (Data_Nascita) porta il focus sulla data di nascita Else $risultato:=year of(Data_Intervento) - year of(Data_Nascita) If ($risultato<1) beep alert("Date incongruenti.") Data_Intervento:=!00-00-00! azzera il dato inserito goto area (Data_Nascita) porta il focus sulla data di nascita End if End if End if Nota pero' che affinche' un oggetto sia sensibile ad un evento non solo e' necessario attivare l'evento nelle proprieta' dell'oggetto ma anche nel form. Per esempio, se vuoi che un oggetto inseribile (campo o variabile) emetta un suono ad ogni tasto premuto, potresti scrivere un codice di questo tipo: If (Form Event=On After Keystroke) play("ClicSound";0) `dove ClicSound e' una risorsa suono End if pero' dovrai attivare l'evento On After Keystroke non solo nelle proprieta' dell'oggetto ma anche nelle proprieta' del Form. Una cosa molto importante. Esiste una gerarchia nella esecuzione dei methods. Per esempio quando clicchi sul pulsante OK che conferma una scheda, vengono eseguiti i seguenti methods, nell'ordine: 1) il method del pulsante che hai azionato (se attivato "On Clicked") 2) il method del form che contiene il pulsante, piu' volte: On clicked per il pulsante premuto On Validate per avere confermato le modifiche ... 3) il trigger del table cui appartiene il record, perche' e' stato registrato Quindi in conseguenza di uno stesso evento e' possibile eseguire prima il method dell'oggetto e poi del form. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Novizi |
Prima introduzione a 4d: FORMS [schermate]
Per creare i form conviene usare le funzioni messe a disposizione del "New Form Wizard", la finestra che compare quando da menu' scegli "New form...". Nel Wizard puoi definire le varie caratteristiche del form, prova per vedere come funziona. Puoi creare diversi form, e poi cancellarli (da Explorer). Nota che un form e' cancellabile sono se NON e' l'Input o l'OUTPUT FORM per quel file, nell'Explorer guarda se e' attivata l'opzione in fondo all'elenco; per esempio se un form e' l'INPUT FORM e vuoi eliminarlo seleziona un altro form di quel file (o creane uno se non ce ne sono altri), attiva il check per farlo diventare l'INPUT FORM e poi potrai cancellare il precedente. Le funzioni del Form Wizard sono solo facilitazioni per velocizzare la creazione di un form, ma tutte le caratteristiche possono ovviamente essere modificate e oggetti aggiunti o rimossi anche dopo la creazione. Puoi anche creare un form assolutamente vuoto e poi lavorarci come vuoi, oggetto per oggetto, basta cliccare edit senza impostare nessuna funzione, salvo scegliere il Table a cui deve appartenere quel form. Con il Wizard puoi anche definire un tuo template grafico (funzione avanzate) e salvarlo per utilizzarlo in tutti i forms creati successivamente, ma per il momento usane uno esistente. Nota che nel form saranno presenti solo i campi che hai selezionato dall'elenco al momento della creazione. Se ne salti qualcuno non sarà presente, se aggiungi dei campi al file DOPO la creazione del form, non saranno aggiunti automaticamente ma dovrai farlo a mano. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codice |
Rapido Trasferimento Dati
Quando dovete convertire una base dati da una versione precedente, o volete fare un backup rapido, ecco due metodi veloci da usare e sempre utili: `Metodo DB_ESPORTA `Nexus srl 30-3-2004 C_LONGINT($quantetabelle_l;quantirecords_l;$i;$j) C_POINTER($pointer_p) $quantetabelle_l:=Count tables For ($i;1;$quantetabelle_l) SET CHANNEL(10;Table name($i)+"_"+String($i)) $pointer_p:=Table($i) DEFAULT TABLE($pointer_p->) ALL RECORDS $quantirecords_l:=Records in selection FIRST RECORD MESSAGE("Esporta "+Table name($i)) For ($j;1;$quantirecords_l) GOTO XY(2;2) MESSAGE(String($j)+"/"+String($quantirecords_l)) SEND RECORD NEXT RECORD End for SET CHANNEL(11) End for `Metodo DB_IMPORTA `Nexus srl 30-3-2004 C_LONGINT($quantetabelle_l;$i;$j) C_POINTER($pointer_p) $quantetabelle_l:=Count tables For ($i;1;$quantetabelle_l) SET CHANNEL(10;Table name($i)+"_"+String($i)) $pointer_p:=Table($i) DEFAULT TABLE($pointer_p->) $j:=0 MESSAGE("Importo "+Table name($i)) While (ok=1) $j:=$j+1 RECEIVE RECORD If (ok=1) GOTO XY(2;2) MESSAGE("Record "+String($j)) SAVE RECORD End if End while SET CHANNEL(11) End for |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Come vengono registrati i record
Il file dati è composto di singoli blocchi da 128 byte: in ogni blocco c'è un unico tipo di dati (record, indici, mappa dei blocchi stessi), anche se il blocco non è del tutto pieno; piuttosto un dato può occupare più blocchi. Quindi un record occupa almeno 128 byte o un suo multiplo. Ogni record è composto da: 1. Header, sempre 22 byte a sua volta composto dal TAG - identificativo che il blocco è un record - un checksum per controllare l'integrità del record - data ultima registrazione dalla cache - numero tabella - numero record e di seguito altre info: - dimensione della parte fissa del record - numero dei campi nel record - dimensione totale del record - indicatori di campi a dimensione variabile o subrecords - altri dati riservati 2. Microstruttura del record Scheletro della struttura del record quando è stato salvato l'ultima volta: per ogni campo ci sono 2 byte per tipo di dati e 2 byte per la posizione dell'inizio del dato vero e proprio. Questo permette la modifica della struttura in ogni momento: ogni record verrà aggiornato solo quando salvato di nuovo sia se è stato modificato il tipo di un campo o se ne sono stati creati altri. 3. Dati del record I dati veri e propri vengono registrati uno di seguito all'altro senza separatori e occupando solo lo spazio usato. Integer = 2 byte Long Integer = 4 byte Real = 10 byte Date = 6 byte Time = 4 byte Boolean = 2 byte Alpha = 1 byte di lunghezza + 0-80 byte di dati + 1 di parità (min 2 - max 82) Text = 4 byte di lunghezza + 0-32000 byte di dati (min 4 - max 32004) Picture = 4 byte di lunghezza + 0-2MB byte di dati (min 4 - max 2MB) Blob = 4 byte di lunghezza + 0-2GB byte di dati (min 4 - max 2GB) Subtable = 8 byte per record, 4 byte per campo + le dimensioni sopra, 2 per l'ultimo subrecord di un record (min 4 - max 2GB) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Impostare la Memoria su 4D
Maximum e Minimum Cache C'è un area fissa, dove sta l'eseguibile di 4D che occupa dai 4 ai 6 MB e che non varia. Nella memoria tampone (Cache) 4d tiene i record, gli indici, le normali selezioni e le named selection. Nella memoria principale stanno le maschere, i metodi, i menu, i set, il contenuto delle variabili. Quindi anche se va bene avere tanta cache, occorre bilanciare la cosa lasciando spazio anche alla memoria principale, ad esempio se si usano pesantemente gli array. Windows Application Memory Per impostare quantità e dimensione dei blocchi di memoria seguire questa regola molto semplificata: in funzione della memoria principale scelta definire 5 blocchi della dimensione più grande possibile. Considera che se imposti un blocco tropp grosso, ad esempio 20MB, 4d potrebbe non riuscire ad allocarlo se sono liberi solo 19MB. Database Cache Memory Il flag "Use New Memory Scheme on Macintosh" va preferibilmente attivato su Mac OS X e Windows: 4d richiede lo spazio da usare come area di memoria tampone al sistema operativo piuttosto che usare quella dell'applicazione stessa. Su Mac OS 9 è invece più affidabile usare la memoria all'interno dell'applicazione, per evitare problemi causati da altre applicazioni che potrebbero scrivere sulla memoria condivisa. In questo caso va assegnata all'applicazione la memoria totale che gli si può dedicare sul particolare computer e poi con il Customizer la percentuale di Data Cache dovrebbe essere = data cache/(memoria assegnata - 5MB codice) Flush Data Buffers Il default è 15 minuti: occorre abbassare questo tempo solo se si prevede una grande quantità di inserimento dati: in questo modo diminuisce il rallentamento dovuto all'accesso al disco (più spesso registri meno dati hai ogni volta). |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Info |
Memoria occupata dalle Variabili
Le variabili a dimensione fissa occupano la memoria indicata anche se azzerate: boolean, integer, longint e time = 4 byte in memoria date = 6 byte real = 8 byte (10 sui 68k, cioè i Mac pre-Powerpc) puntatori = 16 byte string ((dimensione dichiarata+2)\2)*2 Le variabili a dimensioni variabile occupano solo 4 byte come indirizzo se vuote, più la dimensione effettiva usata: blob, picture, text = 4 byte + dimensione usata Gli array usano spazio in funzione del numero di elementi (NE) e del tipo: Array Boolean = (31+NE)\8 (cioè ogni 8 elementi sono i bit di 1 byte) Array Date = (1+NE)*6 Array Integer = (1+NE)*2 Array Longint = (1+NE)*4 Array Picture = (1+NE)*4 + Somma delle dimensioni delle immagini Array Pointer = (1+NE)*16 Array Real = (1+NE)*8 (10 sui 68k) Array String = (1+NE)*(((dimensione dichiarata+2)\2)*2) Array Text = (1+NE)*6 + Somma delle dimensioni di ogni testo Array 2D = (1+NE)*12 + Somma delle dimensioni di ogni array |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Plugin |
Gli stili predefiniti di 4DView
Come ogni software di elaborazione testi o foglio di calcolo, anche 4DWrite e 4DView permettono di definire degli stili personalizzati in modo da uniformare la formattazione del testo. A ogni stile creato dall'utente viene associato un ID. Inoltre, in ogni area di 4DView, esistono di default tre stili che è possibile solo modificare e non cancellare. Gli stili in questione sono: - lo stile per le celle, il cui ID è -1, che è anche il valore della relativa costante pv style cells; - lo stile per l'intestazione di righe e colonne, il cui ID è -2, che è anche il valore della relativa costante pv style col row headers; - lo stile per l'intestazione e piè di pagina, il cui ID è -3, che è anche il valore della relativa costante pv style page footer header. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Svuotare il contenuto di oggetti in memoria
Ecco una sintesi delle modalità di "svuotamento" degli oggetti per liberare la memoria; utile specialmente quando si hanno array, blob o picture di grosse dimensioni. Stringa_s:="" Testo_t:="" NumeroIntero_l:=0 NumeroReale_l:=0 data_d:=!00-00-00! ora_h:=?00:00? ARRAY TEXT(array_at;0) ARRAY LONGINT(array_al;0) ... SET BLOB SIZE(blob_blb;0) Immagine_pic:= Immagine_pic*0 Per i puntatori è necessario usare una variabile dichiarata e non usata : C_POINTER(<>puntatoreVuoto_ptr) puntatore_ptr:=<>puntatoreVuoto_ptr |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Rendere il software multilingua
Se avete già un software che volete rendere multilingua nell'ultima versione di webHome 1.0.1e in lnea potete vedere l'applicazione di un metodo che rende la trasformazione il più possibile trasparente (anche per il programmatore). Si basa su un metodo Translate e una tabella: il metodo è possibile inserirlo in modo trasparente nel software prima di aver fatto la traduzione di ogni stringa. Ad esempio: ALERT("There was an Error";"Ok") diventa ALERT(Translate("There was an Error");Translate("Ok") Questo metodo, in funzione di una variabile globale, se non trova la traduzione ritorna il primo parametro ma crea comunque un record nella tabella corrispondente, dando così la possibilità al programmatore di tradurre le stringhe necessarie di volta in volta. La procedura permette anche un secondo parametro per distnguere il contesto in situazioni ambigue: ad esempio Translate("set";"time") potrebbe essere differente da Translate("set";"of things") perché il primo "set" in italiano è "Imposta", ma il secondo "set" deve essere tradotto in "insieme" |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tecniche |
Eseguire metodi all'uscita di un database
Capita molto spesso che 4D debba "avvertire" l'utente che alcune operazioni che doveva eseguire prima dell'uscita dal programma non sono state eseguite o che alcuni dati hanno certe caratteristiche. Il metodo "On Exit Database" può contenere questo tipo di controlli. E' importante pero' notare che, mentre nelle versioni monoutente possono essere eseguite query anche in questo metodo, nelle versioni in client/server l'esecuzione di una query nel metodo "On Exit Database" impedisce la chiusura del client. La soluzione al problema è lanciare dal metodo "On Exit Database" dei nuovi processi separati, che eseguano queste operazioni di chiusura, e facendo attendere a quest'ultimo che questi nuovi processi finiscano, prima di poter continuare e dunque permettere l'uscita dall'applicazione. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Web |
Difendersi da virus Web come il Nimda
Nel sorgente di questo sito WebHome, trovate il metodo HTTP_RequestFilter che serve a filtrare i tentativi di attacchi da virus che cercano i web server windows. Poiche' questi virus provano centinaia di attacchi in contemporanea, in viaWeb ho implemtentato questa piccola variante che sposta sul chiamante l'onere del rallentamento: invece di rispondere con un --access denied--, io rispondo con un SEND HTTP REDIRECT("http://www.stop_that_virus.invalid") Cosi' il chiamante perde il suo tempo a cercare il dns inesistente e gli attacchi sul mio server si rilassano. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Stile |
Programmazione a Classi [2], esempio di Form Method
Il ciclo degli eventi rimane comunque ben diviso all'interno del Form Method, con il normale Case per la gestione di tutti gli eventi. $evento:=Form event Case of : ($evento =On Load ) C_Movimenti ("Carica Lista") : ($evento =On Printing Footer ) C_Movimenti ("Stampa Piu' Lista") : ($evento =On Outside Call ) C_Movimenti ("Chiamata Esterna") : ($evento =On Header ) C_Movimenti ("Aggiorna Lista") : ($evento =On Display Detail ) C_Movimenti ("Aggiorna Riga Lista") : ($evento =On Printing Detail ) C_Movimenti ("Aggiorna Riga Lista") `evento diverso, stesso metodo di sopra End case |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Stile |
Programmazione a Classi [3], passaggio dei parametri
Le chiamate hanno 1 o 2 parametri stringa, il primo per il metodo e il secondo per i parametri con una sintassi del tipo "parametro=valore[,parametro=valore]" Ad esempio: C_Ordine("Crea";"Articolo=H10,Quantita'=1,Descrizione=esempio 2,Pagato=False") AllÍinterno del metodo sara' possibile utilizzare una procedura scritta allo scopo: Case of :($1="Crea") $articolo:= getParametro($2;"Articolo ") $quantita:=Num(getParametro($2;"Quantita'")) $descrizione:= getParametro($2;"Descrizione") $pagato:=( getParametro($2;"Pagato")="true") `booleano ... Casi particolari: Il separatore , (virgola) potrebbe trovarsi all'interno del contenuto della variabile (ad esempio, passando un campo testo); in questo caso occorrera' passare il parametro fra virgolette. Ad esempio: C_Ordine("Crea";"Articolo=H10,Descrizione=\"esempio 2,5\",Pagato=True") Ovviamente per altri casi particolari e per il passaggio di blob o di puntatore array e' consentito di aggiungere un eventuale terzo parametro del tipo necessario. In questo caso pero' necessario ricordarsi sempre di passare un secondo parametro di tipo Text, anche se vuoto. Ad esempio: C_Ordine("Crea Gruppo";"";->Array) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Stile |
Programmazione a Classi [1]
Un'ipotesi di programmazione a classi che so già usata da molti programmatori è la seguente: le procedure che raccolgono un gruppo di funzioni idealmente assimilabili vengono raccolte in un metodo con la seguente struttura. `Classe C_nnnnnnnn `Autore Nexus srl `Creato il 17-7-2003 `Mod. aggiunto il metodo xx `Mod. aggiunto il metodo yy `Mod. corretto il calcolo zz Case of :($1="metodo uno") ... :($1="metodo due") ... :($1="metodo tre") ... Else Alert(Current method name+":metodo "+$1+" non disponibile.") End case La definizione dei nomi dei metodi seguira' queste regola generale: C_{nome tabella} per la gestione delle procedure di input e OUTPUT FORM oppure C_{nome funzione} per le altre gestioni; ad esempio C_Fatturazione. In generale quando una procedura raccoglie un numero di metodi oltre una certa soglia di leggibilita' e' necessario che il case principale richiami ad altre classi piu' specializzate; ad esempio C_Fatturazione potrebbe richiamare i metodi di C_FatturazioneIN e C_FatturazioneOUT. |
Mutuo Facile, iDigitalScout, iDigitalTags e altre app di Nexid srl per iPhone e iPad
Cidroid, distributore italiano lettori barcode per IOS Apple iPhone, iPod, iPad