Sviluppo4d.it
Sito indipendente di informazioni tecniche per sviluppatori 4th Dimension italiani  

Sviluppatori 4D

Utility 4D

Risorse 4D



4d logo
Naviga:

Faq

Ho trovato 103 faq.

Categoria Argomento Commenti
Tecniche 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")
Tecniche 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.
Tecniche 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
Tecniche 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.
Tecniche 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
Tecniche 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.
Tecniche 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.
Tecniche 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.
Tecniche 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.
Tecniche 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" .
Tecniche 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

  
Tecniche 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.
Tecniche 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)

Tecniche 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.
Tecniche 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
Tecniche 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à:
  • se sul server 4d è presente la licenza web si può preparare una chiamata in GET o POST che ritorni i valori in un formato elaborabile (tipo server REST)
  • se è presente la licenza WebService si può fare una chiamata SOAP usando l'indirizzo automatico http://indirizzoserver/4DWSDL
  • se si vuole accedere alle tabelle direttamente si può usare una chiamata ODBC dopo aver installato il corrispondente driver ODBC (disponibile gratuitamente)
  • via PHP utilizzando il driver PDO_4D incluso nelle ultime release di PHP


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
Tecniche 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
Tecniche 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;.....)

Tecniche 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
Tecniche 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.
Tecniche Tecniche Indirizzare la stampa su un cassetto della stampante
In linea di massima (solo sotto Windows):

  1. usi il comando PRINT OPTION VALUES ( Paper source option; array_Nomi; array_ID)
  2. il primo array contiene i nomi dei cassetti, il secondo il corrispondente ID
  3. prima di stampare scrivi SET PRINT OPTION ( Paper source option; array_ID{ x } ) dove x è il numero del cassetto scelto dalla lista array_Nomi
Tecniche 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
Tecniche 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)))


Tecniche 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.
Tecniche 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")
Tecniche 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 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 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 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
Tecniche 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")

Tecniche 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)

Tecniche 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.
Tecniche 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.

Tecniche Tecniche Deselezionare gli elementi di una listbox **
Le list box "ricordano" la riga selezionata, il che significa che visualizzando uan listbox già visualizzata potremmo trovare una riga già selezionata.
Per evitare ciò, se arrEsempio è uno degli array usati dalla listbox ListBox, basta scrivere:

SELECT LISTBOX ROW (ListBox; Size of array(arrEsempio)+1)



7
Tecniche 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.

Tecniche Tecniche Metodo di indirizzamento delle stampe [1]

Sottotitolo: [Bug] [Risolto] 2003.6 e 2003.7 OSX 10.3 e 10.4 non imposta la stampante richiesta, non preleva correttamente la carta

Ho finalmente avuto il tempo di affrontare questo argomento che nel mio ambiente di lavoro mi creava problemi da quando sono passato alla v 2003.
Qui da noi ogni giorno 10 client stampano parecchio materiale, saltando dalle etichette adesive da prelevare dai vassoi, al fogli standard nei cassetti, ai cartellini a colori per il self-service, alle etichette sempre a colori dei prodotti, utilizzando 3 stampati di rete postscript in TCP/IP, alcune stampanti inkjet USB e una Inkjet A3 condivisa. Tutti gli utenti erano costretti a impostare manualmente tutti i parametri per ogni stampa eseguita.

Ho esaminato le informazioni che mi è stato possibile trovare in ambito internazionale, sia note tecniche sia messaggi postati ai diversi NUG, testando le soluzioni proposte (alcune delle quali abbastanza astruse, come quella di creare diverse copie dei documenti PPD e di rinominarli al volo da method per costringere l’OS ad usare la configurazione voluta...).

Ho trovato una soluzione che finalmente funziona bene e che utilizza i comandi standard, soluzione basata sulle funzioni di salvataggio e recupero dei parametri di stampa in BLOB fornite dal plug-in ACI_Pack. Ciò implica il salvataggio del setup in una table ma a mio parere ne vale la pena. La soluzione è testata con tutte le funzioni di stampa, compresa PRINT FORM, ma non con i QuickReport che non uso.

Creazione e salvataggio impostazioni di stampa, è importante la corretta successione dei comandi:

1) eventuale impostazione del formato con PAGE SETUP, se necessario;
2) ottenimento di tutti i parametri di stampa con PRINT SETTINGS;
      istruendo l’utente a impostare tutti i parametri con attenzione, anche il numero delle copie
3) trasferimento del setup in una variabile BLOB con AP Print settings to BLOB;
4) salvataggio del nome della stampante selezionata;
5) salvataggio del BLOB con i parametri.

Esempio, assumendo di avere creato una table [ParametersTable] dove registrare i parametri di stampa

C_BLOB($mioBlob)
PAGE SETUP ([myTable];"PageSetupForm")
PRINT SETTINGS
If (OK=1)
    $error:=AP Print settings to BLOB ($mioBlob)
    If ($error#1)
           ALERT ("Errore generando il BLOB dei Parametri di stampa.")
    Else
           CREATE RECORD ([ParametersTable])
           [ParametersTable]PrinterName:=Get current printer
           [ParametersTable]ParametersBLOB:=$mioBlob
           SAVE RECORD ([ParametersTable])
    End if
End if

Nota: è indispensabile trasferire i parametri in una variabile BLOB e poi assegnarla al campo BLOB, non usare la funzione AP Print settings to BLOB con un campo quale argomento della funzione perché poi il BLOB può generare errori.



1
Tecniche 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 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 Tecniche Eseguire più 4DServer sulla stessa macchina *
È possibile far girare più di una applicazione 4DServer sulla stessa macchina. L'unico accorgimento che bisogna prendere è quello di "customizzare" ognuna delle sessioni.
4DServer pubblica i database sempre sulla stessa porta TCP/IP, e risulta dunque necessario modificare questo parametro per ognuno dei server da attivare.
La procedura da seguire inizia con l'individuazione del file tcp.opt nel cartella di sistema 4D; copiare questo file in ognuna delle cartelle dei 4DServer che vogliamo attivare; aprire ognuno dei file (al limite tranne uno, il 19813 standard) col Customizer e modificare il valore della porta con un numero vicino a quello visualizzato e comunque diverso da ognuno degli altri numeri assegnati.
A questo punto, lanciando 4DClient, basterà inserire come indirizzo del server xxx.zzz.yyy.aaa virgola numero della porta assegnata in precedenza.

2
Tecniche 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
Tecniche 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)
Tecniche 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

Tecniche 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.
Tecniche 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

Tecniche 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
Tecniche 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

Tecniche 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


Tecniche 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

Tecniche 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 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
Tecniche 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 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
Tecniche 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

Tecniche 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))

Tecniche 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 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 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
Tecniche Tecniche Tutte le faq sulla normalizzazione
Tecniche Tecniche Creare un'immagine lampeggiante *
Per creare un immagine lampeggiante in una maschera, segui questi passi::
1. Crea un nuova aimmagine nella Picture library.
2. Imposta l'immagine a 2 colonne e 1 riga
3. Incolla l'immagine nel secondo frame, lasciando il primo vuoto.
4. Trascina l'immagine così creata su un form per craere un picture button, chiamato ad esempio PulsanteImmagine.
5. Aggiungi il seguente codice nel metodo del form:
If (Form event=On Load)
  Set Timer(tickCount) `60esimi di secondo, da impostare secondo la velocità desiderata
End if
If (Form event=On Timer )
  If (PulsanteImmagine=0)
    PulsanteImmagine:=PulsanteImmagine +1
  Else
    PulsanteImmagine:= PulsanteImmagine -1
  End if
End if


1
Tecniche 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.
Tecniche 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
Tecniche 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.
Tecniche 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"
Tecniche 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)))
Tecniche 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.

Tecniche 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 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 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 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
Tecniche 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 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 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 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 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 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
Tecniche 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")
Tecniche 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.
Tecniche 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"
Tecniche 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 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

Tecniche 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.
  
Tecniche 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.
Tecniche 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>
Tecniche 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")
Tecniche 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.
Tecniche 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.
Tecniche 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)
Tecniche 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 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
Tecniche 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
Tecniche 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)
Tecniche 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 "\\".
Tecniche 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
Tecniche 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.

Tecniche 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.
Tecniche 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.
Tecniche 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 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.
Tecniche 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
Tecniche 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.
Tecniche 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 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 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.

Accesso

User:
Pass: Accedi

Cerca

Se non trovi le informazioni che cerchi scrivi a aiuto@sviluppo4d.it

4D Principali

4D Discussioni

Faq random


Crediti

Dominio registrato da ZetaNet
Sito realizzato da Nexus srl
4D SQL 11.9.0 offerto da 4D & Italsoftware
Icone di FAMFAMFAM
Moderato da Umberto Migliore
301 utenti registrati

Pagina servita il 19/03/24 alle 07:40:31 Valid HTML 4.01! Valid CSS!

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