Professional Documents
Culture Documents
programmazione
Borland®
Delphi 7 ™
per Windows ®
iii
Routine per data-ora . . . . . . . . . . . . 5-10 Restituzione di una variabile
Copia di un file . . . . . . . . . . . . . . . 5-10 locale PChar . . . . . . . . . . . . . . . 5-29
Operazioni con file ini e con Passaggio di una variabile
il Registro di sistema . . . . . . . . . . . . . . . 5-11 locale come PChar . . . . . . . . . . . . 5-30
Utilizzo di TIniFile e di TMemIniFile. . . 5-11 Direttive al compilatore per le stringhe . . . 5-31
Utilizzo di TRegistryIniFile . . . . . . . . 5-13 Creazione di spazi di disegno . . . . . . . . . . 5-31
Uso di TRegistry . . . . . . . . . . . . . . 5-13 Stampa . . . . . . . . . . . . . . . . . . . . . . . 5-32
Operazioni con le liste . . . . . . . . . . . . . . . 5-14 Conversione di misure . . . . . . . . . . . . . . 5-33
Operazioni comuni su elenchi . . . . . . . . 5-14 Esecuzione di conversioni . . . . . . . . . . 5-33
Aggiunta di elementi di un elenco . . . . 5-14 Esecuzione di conversioni semplici . . . 5-34
Cancellazione degli elementi Esecuzione di conversioni complesse . . 5-34
di un elenco . . . . . . . . . . . . . . . . 5-15 Aggiunta di nuovi tipi di misura . . . . . . 5-34
Accesso agli elementi di un elenco . . . . 5-15 Creazione di una semplice famiglia di
Riordinamento degli elementi conversione e aggiunta delle unità . . . . 5-35
di un elenco . . . . . . . . . . . . . . . . 5-16 Dichiarazione delle variabili . . . . . . . 5-35
Elenchi persistenti . . . . . . . . . . . . . . . 5-16 Registrazione della famiglia
Operazioni con elenchi di stringhe. . . . . . . . 5-16 di conversione . . . . . . . . . . . . . . 5-35
Caricamento e salvataggio Registrazione delle unità di misura . . . 5-36
di elenchi di stringhe . . . . . . . . . . . . . 5-17 Utilizzo delle nuove unità di misura . . 5-36
Creazione di un nuovo elenco di stringhe . . 5-17 Utilizzo di una funzione di conversione . . 5-36
Elenchi di stringhe di breve termine . . . 5-18 Dichiarazione delle variabili . . . . . . . 5-36
Elenchi di stringhe di lungo termine . . . 5-18 Registrazione della famiglia
Gestione di stringhe in un elenco. . . . . . . 5-19 di conversione . . . . . . . . . . . . . . 5-37
Conteggio di stringhe in un elenco . . . . 5-20 Registrazione dell’unità di misura
Accesso ad una particolare stringa . . . . 5-20 di base . . . . . . . . . . . . . . . . . . . 5-37
Individuazione di elementi Scrittura dei metodi per la conversione
in un elenco di stringhe . . . . . . . . . 5-20 in base all’unità di misura di base . . . 5-37
Analisi sequenziale di stringhe Registrazione delle altre unità
in un elenco . . . . . . . . . . . . . . . . 5-20 di misura . . . . . . . . . . . . . . . . . 5-37
Aggiunta di una stringa a un elenco . . . 5-20 Utilizzo delle nuove unità di misura . . 5-38
Spostamento di una stringa Utilizzo di una classe per gestire
all’interno di un elenco . . . . . . . . . . 5-21 le conversioni . . . . . . . . . . . . . . . . 5-38
Cancellazione di una stringa Creazione della classe di conversione . . 5-38
da un elenco . . . . . . . . . . . . . . . . 5-21 Dichiarazione delle variabili . . . . . . . 5-39
Associazione di oggetti ad un elenco di Registrazione della famiglia
stringhe. . . . . . . . . . . . . . . . . . . 5-22 di conversione e delle altre unità . . . . 5-40
Operazioni con stringhe. . . . . . . . . . . . . . 5-22 Utilizzo delle nuove unità di misura . . 5-41
Routine per wide character . . . . . . . . . . 5-22 Definizione di variant custom . . . . . . . . . . 5-41
Routine comunemente utilizzate Memorizzazione dei dati di un tipo
per long string . . . . . . . . . . . . . . . . 5-23 variant custom . . . . . . . . . . . . . . . . 5-42
Routine comunemente utilizzate Creazione di una classe per attivare
per stringhe terminate con null . . . . . . . 5-26 il tipo variant custom . . . . . . . . . . . . 5-43
Dichiarazione ed inizializzazione Abilitazione della conversione . . . . . . 5-43
di stringhe . . . . . . . . . . . . . . . . . . . 5-27 Implementazione di operazioni binarie . 5-44
Combinazione e conversione Implementazione di operazioni
di tipi di stringa . . . . . . . . . . . . . . . . 5-28 di confronto. . . . . . . . . . . . . . . . 5-46
Conversioni di stringa a PChar . . . . . . . . 5-29 Implementazione di operazioni unarie . 5-48
Dipendenze di stringhe . . . . . . . . . . 5-29 Copia e cancellazione di variant custom . . 5-48
iv
Caricamento e salvataggio dei valori Modifica del puntatore di trascinamento
dei variant custom . . . . . . . . . . . . 5-49 del mouse. . . . . . . . . . . . . . . . . . . . 7-4
Utilizzo del discendente Implementazione delle operazione
TCustomVariantType . . . . . . . . . . . 5-50 drag-and-dock nei controlli . . . . . . . . . . . 7-4
Scrittura di programmi di utilità Trasformazione di un controllo
per operare con un tipo variant custom . . 5-50 con finestra in una posizione di aggancio. . 7-5
Supporto di proprietà e metodi Come trasformare un controllo in un figlio
nei variant custom . . . . . . . . . . . . . . 5-52 agganciabile . . . . . . . . . . . . . . . . . . 7-5
Utilizzo di TInvokeableVariantType . . . 5-52 Controllo delle modalità di aggancio dei
Utilizzo di TPublishableVariantType . . . 5-53 controlli figlio . . . . . . . . . . . . . . . . . 7-5
Controllo della modalità di sgancio
Capitolo 6 dei controlli figlio . . . . . . . . . . . . . . . 7-6
Operazioni con componenti 6-1 Controllo della modalità di risposta
Impostazione delle proprietà dei componenti . 6-2 dei controlli figlio alle operazioni
Impostazione delle proprietà drag-and-dock . . . . . . . . . . . . . . . . . 7-7
in progettazione. . . . . . . . . . . . . . . . 6-2 Operazioni sul testo nei controlli . . . . . . . . . 7-7
Utilizzo di editor di proprietà . . . . . . . 6-3 Impostazione dell’allineamento del testo. . . 7-7
Impostazione di proprietà in esecuzione . . 6-3 Aggiunta di barre di scorrimento in fase di
Chiamate a metodi. . . . . . . . . . . . . . . . . 6-3 esecuzione . . . . . . . . . . . . . . . . . . . 7-8
Operazioni con eventi e gestori di evento . . . . 6-3 Aggiunta dell’oggetto clipboard. . . . . . . . 7-9
Generazione di nuovo gestore di evento. . . 6-4 Selezione del testo . . . . . . . . . . . . . . . . 7-9
Generazione di un gestore per l’evento Selezione di tutto il testo . . . . . . . . . . . 7-10
predefinito di un componente. . . . . . . . 6-4 Operazione taglia, copia e incolla del testo . 7-10
Individuazione dei gestori di evento. . . . . 6-4 Cancellazione del testo selezionato . . . . . 7-11
Associazione di un evento ad un gestore di Disattivazione delle voci di menu . . . . . . 7-11
evento esistente . . . . . . . . . . . . . . . . 6-5 Preparazione di un menu a comparsa. . . . 7-12
Utilizzo del parametro Sender . . . . . . 6-5 Gestione dell’evento OnPopup . . . . . . . 7-12
Visualizzazione e codifica Aggiunta di grafici ai controlli . . . . . . . . . 7-13
di eventi condivisi . . . . . . . . . . . . 6-6 Come indicare che un controllo
Associazione di eventi di menu è owner-drawn. . . . . . . . . . . . . . . . 7-14
a gestori di evento . . . . . . . . . . . . . . 6-6 Aggiunta di oggetti grafici ad un elenco
Cancellazione di gestori di evento . . . . . . 6-7 di stringhe . . . . . . . . . . . . . . . . . . 7-14
Componenti multipiattaforma e non Aggiunta di immagini
multipiattaforma . . . . . . . . . . . . . . . . . 6-7 ad un’applicazione. . . . . . . . . . . . 7-15
Aggiunta di componenti custom alla Aggiunta di immagini
Component palette . . . . . . . . . . . . . . 6-9 a un elenco di stringhe . . . . . . . . . 7-15
Disegno di elementi owner-drawn. . . . 7-16
Capitolo 7 Dimensionamento degli elementi
Uso dei controlli 7-1 owner-draw . . . . . . . . . . . . . . . . . 7-16
Implementazione del drag-and-drop Disegno di elementi owner-draw . . . . . . 7-17
nei controlli . . . . . . . . . . . . . . . . . . . . 7-1
Inizio di un’operazione di trascinamento . . 7-1
Capitolo 8
Accettazione degli elementi rilasciati . . . . 7-2 Creazione di applicazioni,
Rilascio di elementi . . . . . . . . . . . . . . 7-3 componenti e librerie 8-1
Fine di un’operazione di trascinamento . . . 7-3 Creazione di applicazioni . . . . . . . . . . . . . 8-1
Personalizzazione delle operazioni di Applicazioni GUI . . . . . . . . . . . . . . . . 8-1
trascinamento e di rilascio Modelli di interfaccia utente . . . . . . . . 8-2
con un oggetto drag . . . . . . . . . . . . . 7-3 Applicazioni SDI . . . . . . . . . . . . . . . 8-2
Applicazioni MDI . . . . . . . . . . . . . . 8-2
v
Impostazioni delle opzioni per l’IDE, il Attivazione dell’Help nelle applicazioni . . . . 8-24
progetto e per il compilatore. . . . . . . 8-3 Interfacce per il sistema di Help . . . . . . . 8-24
Modelli di programmazione . . . . . . . . . 8-3 Implementazione di ICustomHelpViewer . 8-25
Applicazioni per console . . . . . . . . . . . 8-4 Comunicazione con Help Manager . . . . . 8-25
Applicazioni di servizio . . . . . . . . . . . . 8-4 Richiesta di informazioni all’Help Manager 8-26
Thread dei servizi. . . . . . . . . . . . . . 8-7 Visualizzazione di Help in base
Proprietà del nome del servizio . . . . . . 8-8 a parole chiave . . . . . . . . . . . . . . . . 8-27
Debug delle applicazioni di servizio . . . 8-9 Visualizzazione degli indici . . . . . . . . . 8-28
Creazione di package e di DLL . . . . . . . . . . 8-10 Implementazione IExtendedHelpViewer . . 8-28
Quando usare i package e le DLL . . . . . . 8-10 Implementazione IHelpSelector . . . . . . . 8-29
Scrittura di applicazioni database . . . . . . . . 8-11 Registrazione di oggetti di sistema di Help 8-30
Distribuzione di applicazioni database . . . 8-12 Registrazione dei visualizzatori di Help 8-30
Creazione di applicazioni per Web server. . . . 8-12 Registrazione dei selettori di Help . . . . 8-30
Creazione di applicazioni con Web Broker . 8-13 Utilizzo dell’Help in un’applicazione VCL . . 8-30
Creazione di applicazioni WebSnap . . . . . 8-14 In che modo TApplication
Creazione di applicazioni Web Services . . . 8-14 elabora l’Help VCL . . . . . . . . . . . . . 8-31
Scrittura di applicazioni con COM. . . . . . . . 8-15 In che modo i controlli VCL
Utilizzo di COM e DCOM . . . . . . . . . . . 8-15 elaborano l’Help . . . . . . . . . . . . . . . 8-31
Utilizzo di MTS e COM+ . . . . . . . . . . . 8-15 Utilizzo dell’Help in un’applicazione CLX. . . 8-31
Utilizzo dei moduli dati . . . . . . . . . . . . . . 8-16 In che modo TApplication
Creazione e modifica di moduli dati elabora l’Help CLX . . . . . . . . . . . . . 8-32
standard . . . . . . . . . . . . . . . . . . . . 8-17 In che modo i controlli CLX
Attribuzione del nome a un modulo elaborano l’Help . . . . . . . . . . . . . . . 8-32
dati e al relativo file unit . . . . . . . . . 8-17 Chiamata diretta a un sistema di Help . . . . . 8-32
Posizionamento e assegnazione Utilizzo di IHelpSystem . . . . . . . . . . . . . 8-33
del nome ai componenti . . . . . . . . . 8-18 Personalizzazione del sistema di Help
Utilizzo delle proprietà e degli eventi dell’IDE. . . . . . . . . . . . . . . . . . . . . . 8-33
dei componenti di un modulo dati . . . 8-19
Creazione di regole di gestione Capitolo 9
in un modulo dati . . . . . . . . . . . . . 8-19 Sviluppo dell’interfaccia utente
Accesso a un modulo dati da una scheda . . 8-20
Aggiunta di un modulo dati remoto a un
dell’applicazione 9-1
Controllo del comportamento
progetto di application server . . . . . . . . 8-20
dell’applicazione . . . . . . . . . . . . . . . . . 9-1
Utilizzo dell’Object Repository . . . . . . . . . . 8-21
Il lavoro a livello di applicazione . . . . . . . 9-2
Condivisione di elementi all’interno
Gestione dello schermo . . . . . . . . . . . . . 9-2
di un progetto . . . . . . . . . . . . . . . . . 8-21
Impostazione delle schede . . . . . . . . . . . . . 9-2
Aggiunta di elementi all’Object Repository . 8-21
Uso della scheda principale . . . . . . . . . . 9-3
Condivisione di oggetti in un team
Occultamento della scheda principale . . . . 9-3
di lavoro . . . . . . . . . . . . . . . . . . . . 8-21
Aggiunta di schede . . . . . . . . . . . . . . . 9-3
Utilizzo di un elemento
Collegamento delle schede . . . . . . . . . 9-4
dell’Object Repository in un progetto . . . 8-22
Evitare riferimenti circolari di unit. . . . . 9-4
Copia di un elemento. . . . . . . . . . . . 8-22
Gestione del layout . . . . . . . . . . . . . . . 9-4
Ereditare un elemento . . . . . . . . . . . 8-22
Uso delle schede . . . . . . . . . . . . . . . . . . 9-5
Utilizzo di un elemento . . . . . . . . . . 8-22
Controllo delle schede in memoria . . . . . . 9-6
Utilizzo di modelli di progetto . . . . . . . . 8-23
Visualizzazione di una scheda creata
Modifica di elementi condivisi . . . . . . . . 8-23
automaticamente . . . . . . . . . . . . . . 9-6
Specifica di un progetto predefinito,
Creazione dinamica delle schede . . . . . 9-6
di una nuova scheda e della scheda
Creazione di schede non modali come
principale . . . . . . . . . . . . . . . . . . . 8-23
finestre . . . . . . . . . . . . . . . . . . . 9-8
vi
Creazione di un’istanza di scheda Assegnazione dei nomi delle voci
mediante una variabile locale . . . . . . 9-8 di menu . . . . . . . . . . . . . . . . . . 9-35
Passaggio di altri argomenti alle schede . . . 9-8 Aggiunta, inserimento e cancellazione
Recupero dei dati dalle schede . . . . . . . . 9-9 delle voci di menu . . . . . . . . . . . . 9-36
Recupero dei dati da schede Aggiunta di barre separatrici . . . . . . . 9-37
non modali. . . . . . . . . . . . . . . . . 9-9 Specifica dei tasti di scelta rapida
Recupero dei dati da schede modali . . . 9-11 e delle scorciatoie di tastiera . . . . . . 9-38
Riutilizzo di componenti e Creazione di sottomenu . . . . . . . . . . . 9-38
gruppi di componenti . . . . . . . . . . . . . . 9-13 Creazione di sottomenu
Creazione e utilizzo di modelli di componenti . 9-13 per retrocessione dei menu esistenti . . 9-39
Operazioni con i frame . . . . . . . . . . . . . . 9-14 Spostamento delle voci di menu . . . . . 9-39
Creazione di frame . . . . . . . . . . . . . . . 9-14 Aggiunta di immagini alle voci di menu 9-40
Aggiunta di frame alla Component palette . 9-15 Visualizzazione del menu. . . . . . . . . 9-40
Uso e modifica di frame . . . . . . . . . . . . 9-15 Editing delle voci di menu
Condivisione di frame . . . . . . . . . . . . . 9-16 nell’Object Inspector . . . . . . . . . . . . 9-41
Sviluppo di finestre di dialogo . . . . . . . . . . 9-17 Uso del menu contestuale Menu Designer . 9-41
Utilizzo delle finestre di dialogo I comandi del menu contestuale . . . . . 9-42
di tipo Open . . . . . . . . . . . . . . . . . . 9-17 Passaggio da un menu all’altro
Organizzazione delle azioni per barre e menu . 9-18 in fase di progettazione . . . . . . . . . 9-42
Che cosa è un’ azione . . . . . . . . . . . . . 9-19 Uso dei modelli di menu . . . . . . . . . . . 9-43
Configurazione delle bande di azione . . . . 9-20 Salvataggio di un menu come modello . . . 9-44
Creazione di barre di strumenti e menu . . . 9-21 Convenzioni per l’assegnazione
Aggiunta di colori, motivi o immagini a dei nomi delle voci di menu e
menu, pulsanti e barre di strumenti. . . 9-22 dei gestori di evento di un modello . . 9-45
Aggiunta di icone a menu e barre di Manipolazione delle voci di menu
strumenti. . . . . . . . . . . . . . . . . . 9-23 in fase di esecuzione. . . . . . . . . . . . . 9-45
Selezione degli stili per i menu Fusione dei menu . . . . . . . . . . . . . . . 9-45
e le barre strumenti . . . . . . . . . . . . 9-23 Specifica del menu attivo:
Creazione di menu dinamici. . . . . . . . 9-24 proprietà Menu. . . . . . . . . . . . . . 9-46
Creazione di barre di strumenti e menu Determinazione dell’ordine delle voci
personalizzabili dagli utenti . . . . . . . 9-25 di menu fuse: proprietà GroupIndex . 9-46
Occultamento di elementi e categorie Importazione dei file risorsa . . . . . . . . . 9-46
inutilizzate nelle bande di azioni . . . . 9-25 Progettazione di barre strumenti e di coolbar . 9-47
Creazione degli elenchi Aggiunta di una barra strumenti
di dati recenti (MRU) . . . . . . . . . . . 9-26 usando un componente panel . . . . . . . 9-48
Uso delle liste di azioni . . . . . . . . . . . . . . 9-27 Aggiunta di un pulsante di scelta
Configurazione delle liste di azioni . . . . . 9-27 rapida a un pannello. . . . . . . . . . . 9-49
Cosa accade quando si scatena un’azione . . 9-28 Assegnazione del glifo a un pulsante
Risposta con eventi . . . . . . . . . . . . . 9-28 di scelta rapida . . . . . . . . . . . . . . 9-49
Come le azioni trovano le proprie Impostazione della condizione iniziale
destinazioni . . . . . . . . . . . . . . . . 9-30 di un pulsante di scelta rapida . . . . . 9-49
Aggiornamento delle azioni. . . . . . . . . . 9-30 Creazione di un gruppo di pulsanti
Classi di azione predefinite . . . . . . . . . . 9-30 di scelta rapida . . . . . . . . . . . . . . 9-50
Scrittura di componenti azione . . . . . . . . 9-32 Come consentire la commutazione dei
Registrazione delle azioni . . . . . . . . . . . 9-33 pulsanti . . . . . . . . . . . . . . . . . . 9-50
Creazione e gestione dei menu . . . . . . . . . . 9-33 Aggiunta di una barra strumenti
Apertura di Menu Designer. . . . . . . . . . 9-34 usando il relativo componente . . . . . . . 9-50
Costruzione di menu. . . . . . . . . . . . . . 9-35 Aggiunta di un pulsante strumento . . . 9-51
Assegnazione dei nomi dei menu. . . . . 9-35
vii
Assegnazione di immagini ai pulsanti Viste ad albero . . . . . . . . . . . . . . . . 10-14
strumento . . . . . . . . . . . . . . . . . 9-51 Viste ad elenco . . . . . . . . . . . . . . . . 10-14
Impostazione dell’aspetto di un Viste di Icone (solo CLX) . . . . . . . . . . 10-15
pulsante strumento e delle condizioni Selettore data-ora e calendari mensili . . . 10-15
iniziali . . . . . . . . . . . . . . . . . . . 9-51 Controlli di raggruppamento . . . . . . . . . 10-15
Creazione di gruppi di pulsanti Caselle di gruppo e gruppi
strumento . . . . . . . . . . . . . . . . . 9-52 di pulsanti di opzione . . . . . . . . . . . 10-15
Come consentire pulsanti strumento Pannelli . . . . . . . . . . . . . . . . . . . . 10-16
commutati . . . . . . . . . . . . . . . . . 9-52 Caselle a scorrimento . . . . . . . . . . . . 10-16
Aggiunta di un componente coolbar . . . . . 9-53 Controlli separatore . . . . . . . . . . . . . 10-17
Impostazione dell’aspetto della coolbar . 9-53 Controlli pagina . . . . . . . . . . . . . . . 10-17
Risposta ai clic . . . . . . . . . . . . . . . . . 9-54 Controlli intestazione . . . . . . . . . . . . 10-17
Assegnazione di un menu Controlli di visualizzazione . . . . . . . . . . 10-17
a un pulsante strumento . . . . . . . . . 9-54 Barre di stato . . . . . . . . . . . . . . . . . 10-18
Aggiunta di barre strumenti nascoste . . . . 9-54 Barre di avanzamento. . . . . . . . . . . . 10-18
Come nascondere e mostrare Proprietà Help e Hint . . . . . . . . . . . . 10-19
le barre strumenti . . . . . . . . . . . . . . . 9-54 Griglie . . . . . . . . . . . . . . . . . . . . . . 10-19
Programmi dimostrativi . . . . . . . . . . . . 9-55 Griglie grafiche . . . . . . . . . . . . . . . 10-19
Controlli comuni e temi di XP . . . . . . . . . . 9-55 Griglie per stringhe . . . . . . . . . . . . . 10-20
Editor di liste di valori (solo VCL) . . . . . . 10-20
Capitolo 10 Controlli grafici . . . . . . . . . . . . . . . . . 10-21
Tipi di controlli 10-1 Immagini . . . . . . . . . . . . . . . . . . . 10-21
Controlli di testo . . . . . . . . . . . . . . . . . . 10-1 Forme . . . . . . . . . . . . . . . . . . . . . 10-21
Controlli di editing . . . . . . . . . . . . . . . 10-2 Linee smussate. . . . . . . . . . . . . . . . 10-21
Proprietà dei controlli di editing . . . . . . . 10-3 Caselle di disegno . . . . . . . . . . . . . . 10-22
Controlli memo e rich edit . . . . . . . . . 10-3 Controlli Animation (solo VCL) . . . . . . 10-22
Controlli per la visualizzazione del testo . . 10-4
Etichette . . . . . . . . . . . . . . . . . . . . . 10-5 Capitolo 11
Controlli specializzati per l’input . . . . . . . . 10-6 Progettazione di classi e componenti
Barre di scorrimento . . . . . . . . . . . . . . 10-6 con ModelMaker 11-1
Barre di regolazione . . . . . . . . . . . . . . 10-6 Nozioni di base su ModelMaker . . . . . . . . 11-2
Controlli up-down . . . . . . . . . . . . . . . 10-7 Modelli di ModelMaker . . . . . . . . . . . 11-2
Controlli spin edit (solo CLX) . . . . . . . . . 10-7 Utilizzo di ModelMaker con l’IDE. . . . . . 11-2
Controlli Hot key (solo VCL) . . . . . . . . . 10-7 Creazione di modelli . . . . . . . . . . . . . 11-3
Controlli splitter . . . . . . . . . . . . . . . . 10-8 Utilizzo delle viste di ModelMaker . . . . . . . 11-3
Pulsanti e controlli simili . . . . . . . . . . . . . 10-8 Pannello Collections . . . . . . . . . . . . . 11-4
Controlli pulsante . . . . . . . . . . . . . . . 10-9 Vista Classes . . . . . . . . . . . . . . . . 11-5
Pulsanti bitmap . . . . . . . . . . . . . . . . . 10-9 Vista Units . . . . . . . . . . . . . . . . . 11-5
Pulsanti di scelta rapida . . . . . . . . . . . . 10-9 Vista Diagrams . . . . . . . . . . . . . . . 11-6
Caselle di controllo . . . . . . . . . . . . . . 10-10 Pannello Members. . . . . . . . . . . . . . . 11-7
Pulsanti di opzione. . . . . . . . . . . . . . 10-10 Pannello Editors . . . . . . . . . . . . . . . . 11-7
Barre strumenti . . . . . . . . . . . . . . . . 10-11 Implementation Editor . . . . . . . . . . 11-7
Cool bar (solo VCL) . . . . . . . . . . . . . 10-11 Unit Code Editor. . . . . . . . . . . . . . 11-8
Controlli elenco . . . . . . . . . . . . . . . . . 10-12 Diagram Editor. . . . . . . . . . . . . . . 11-9
Caselle di riepilogo e caselle Altri Editor . . . . . . . . . . . . . . . . . 11-9
di riepilogo con spunta . . . . . . . . . . 10-12 Per ulteriori informazioni . . . . . . . . . . . .11-10
Caselle combinate . . . . . . . . . . . . . . 10-13
viii
Capitolo 12 Aggiunta di clip audio e/o video a
Operazioni con elementi grafici e un’applicazione . . . . . . . . . . . . . . 12-32
Esempio di aggiunta di clip
multimediali 12-1 audio e/o video (solo VCL). . . . . . 12-34
Panoramica sulla programmazione dei grafici . 12-1
Aggiornamento dello schermo . . . . . . . . 12-2 Capitolo 13
Tipi di oggetti grafici . . . . . . . . . . . . . . 12-3 Scrittura di applicazioni multi-thread 13-1
Proprietà e metodi comuni
Definizione di oggetti thread . . . . . . . . . . 13-1
dell’oggetto Canvas . . . . . . . . . . . . . 12-4
Inizializzazione del thread . . . . . . . . . . 13-3
Uso delle proprietà dell’oggetto Canvas. . . 12-5
Assegnazione di una priorità
Uso delle penne . . . . . . . . . . . . . . . 12-6
predefinita . . . . . . . . . . . . . . . . 13-3
Uso dei pennelli. . . . . . . . . . . . . . . 12-8
Come indicare quando i thread
Lettura e impostazione dei pixel . . . . 12-10
vengono rilasciati . . . . . . . . . . . . 13-4
Uso dei metodi Canvas per disegnare
Scrittura della funzione thread. . . . . . . . 13-4
oggetti grafici . . . . . . . . . . . . . . . . 12-10
Utilizzo del thread VCL/CLX principale 13-4
Disegno di linee e spezzate . . . . . . . 12-10
Uso delle variabili locali al thread . . . . 13-5
Disegno di figure . . . . . . . . . . . . . 12-11
Controllo del termine da parte
Gestione di più oggetti di disegno in
di altri thread . . . . . . . . . . . . . . . 13-6
un’applicazione . . . . . . . . . . . . . . . 12-12
Gestione delle eccezioni
Come tenere la traccia dello strumento
nella funzione di thread . . . . . . . . . 13-6
di disegno da usare . . . . . . . . . . . 12-12
Scrittura del codice di pulizia . . . . . . . . 13-7
Modifica degli strumenti di disegno . . 12-14
Coordinamento dei thread . . . . . . . . . . . . 13-7
Uso dello strumento
Come evitare l’accesso simultaneo . . . . . 13-7
con i pulsanti rapidi . . . . . . . . . . 12-14
Blocco di oggetti . . . . . . . . . . . . . . 13-8
Disegno su un grafico . . . . . . . . . . . . 12-17
Uso di sezioni critiche . . . . . . . . . . . 13-8
Come rendere scorrevoli i grafici . . . . 12-17
Uso di un sincronizzatore multilettura
Aggiunta di un controllo immagine . . 12-17
a scrittura esclusiva . . . . . . . . . . . 13-8
Caricamento e salvataggio dei file grafici . 12-19
Altre tecniche per la condivisione della
Caricamento di un’immagine da un file 12-20
memoria. . . . . . . . . . . . . . . . . . 13-9
Salvataggio di un’immagine in un file . 12-20
Attesa di altri thread . . . . . . . . . . . . . 13-9
Sostituzione dell’immagine . . . . . . . 12-21
Attesa che un thread termini
Uso della clipboard con i grafici . . . . . . 12-22
l’esecuzione . . . . . . . . . . . . . . . 13-10
Operazioni di copia dei grafici nella
Attesa che venga completata
clipboard . . . . . . . . . . . . . . . . . 12-22
un’operazione . . . . . . . . . . . . . 13-10
Operazioni di taglio di grafici
Esecuzione di oggetti thread. . . . . . . . . . .13-11
nella clipboard. . . . . . . . . . . . . . 12-23
Ridefinizione della priorità predefinita . . 13-12
Operazioni di incollaggio di grafici
Avvio e interruzione dei thread . . . . . . 13-12
della clipboard. . . . . . . . . . . . . . 12-23
Debug delle applicazioni multi-thread . . . . 13-13
Esempio di effetto elastico. . . . . . . . . . 12-24
Assegnazione di un nome al thread . . . . 13-13
Risposta al mouse. . . . . . . . . . . . . 12-24
Conversione di un thread
Risposta ad un’azione mouse-down . . 12-26
senza nome in uno con nome . . . . . 13-13
Aggiunta di un campo a un oggetto
Assegnazione di nomi differenti
scheda per tracciare le
a thread simili . . . . . . . . . . . . . 13-15
azioni del mouse . . . . . . . . . . . . 12-27
Affinamento del disegno delle linee . . 12-28 Capitolo 14
Uso di componenti multimediali. . . . . . . . 12-30
Aggiunta di video clip senza suono ad
Gestione delle eccezioni 14-1
un’applicazione . . . . . . . . . . . . . . . 12-30 Definizione dei blocchi protetti . . . . . . . . . 14-2
Esempio di aggiunta di clip video Scrittura del blocco try . . . . . . . . . . . . 14-2
senza sonoro . . . . . . . . . . . . . . . 12-31 Sollevare un’eccezione . . . . . . . . . . 14-3
ix
Scrittura dei gestori di eccezione . . . . . . . 14-4 Differenze a livello di interfaccia utente . 15-25
Istruzioni del gestore delle eccezioni . . . 14-4 Porting di applicazioni database in Linux 15-26
Gestione delle classi di eccezioni . . . . . 14-6 Aggiornamento dei dati in applicazioni
Campo d’azione dei gestori di eccezioni . 14-6 dbExpress. . . . . . . . . . . . . . . . . . 15-28
Risollevare le eccezioni. . . . . . . . . . . 14-7 Applicazioni Internet multipiattaforma . . . 15-30
Scrittura dei blocchi finally . . . . . . . . . . 14-8 Porting di applicazioni Internet in Linux . 15-30
Scrittura di un blocco finally. . . . . . . . 14-9
Gestione delle eccezioni in applicazioni VCL. . 14-9 Capitolo 16
Classi di eccezione VCL . . . . . . . . . . . 14-10 Uso di package e di componenti 16-1
Gestione predefinita di eccezioni in VCL . 14-11 Perché usare i package? . . . . . . . . . . . . . 16-2
Eccezioni silenziose . . . . . . . . . . . . . 14-12 Package e DLL standard . . . . . . . . . . . 16-2
Definizione delle eccezioni VCL . . . . . . 14-13 Package di esecuzione . . . . . . . . . . . . . . 16-3
Caricamento dei package
Capitolo 15 in un’applicazione . . . . . . . . . . . . . . 16-3
Utilizzo di CLX per lo sviluppo Caricamento dei package
multipiattaforma 15-1 tramite la funzione LoadPackage . . . . 16-4
Creazione di applicazioni CLX . . . . . . . . . . 15-2 Scelta di quali package di esecuzione usare 16-4
Porting di applicazioni VCL . . . . . . . . . . . 15-2 Package custom . . . . . . . . . . . . . . . . 16-5
Tecniche di porting . . . . . . . . . . . . . . . 15-2 Package di progettazione . . . . . . . . . . . . 16-5
Porting specifico per una piattaforma . . 15-3 Installazione di package di componenti . . 16-6
Porting per più piattaforme . . . . . . . . 15-3 Creazione ed editing dei package . . . . . . . . 16-7
Porting in emulazione Windows . . . . . 15-3 Creazione di un package . . . . . . . . . . . 16-7
Modifica di applicazioni VCL. . . . . . . . . 15-4 Editing di un package esistente . . . . . . . 16-8
WinCLX e VisualCLX . . . . . . . . . . . . . 15-5 Struttura dei package . . . . . . . . . . . . . 16-8
Differenze nella VisualCLX . . . . . . . . 15-6 Assegnazione del nome ai package . . . 16-8
Funzionalità mancanti o di cui La clausola Requires . . . . . . . . . . . . 16-9
non è possibile eseguire il porting diretto . 15-7 La clausola Contains. . . . . . . . . . . . 16-9
Confronto fra le unit WinCLX e VisualCLX . 15-8 Editing manuale dei file sorgente
Differenze nei costruttori di oggetti CLX . 15-12 dei package. . . . . . . . . . . . . . . . . 16-10
Gestione degli eventi di sistema Compilazione di package. . . . . . . . . . .16-11
e di widget. . . . . . . . . . . . . . . . . . 15-13 Direttive al compilatore specifiche
Scrittura di codice portabile . . . . . . . . . 15-13 per il packaging . . . . . . . . . . . . .16-11
Utilizzo di direttive condizionali . . . . 15-14 Compilazione e link dalla riga comandi 16-13
Terminazione delle direttive File package creati durante
condizionali . . . . . . . . . . . . . . . 15-15 la compilazione. . . . . . . . . . . . . 16-13
Inclusione di codice assembler in linea. 15-16 Distribuzione dei package . . . . . . . . . . . 16-14
Differenze di programmazione in Linux. . 15-17 Distribuzione di applicazioni
Trasferimento di applicazioni che usano package. . . . . . . . . . . . . 16-14
fra Windows e Linux. . . . . . . . . . . . . . 15-18 Distribuzione di package
Condivisione di file sorgente ad altri sviluppatori . . . . . . . . . . . . 16-14
tra Windows e Linux . . . . . . . . . . . . 15-19 File di raccolta di package . . . . . . . . . 16-14
Differenze di ambiente
fra Windows e Linux . . . . . . . . . . . . 15-19 Capitolo 17
Registry . . . . . . . . . . . . . . . . . . 15-21 Creazione di applicazioni
Look and feel . . . . . . . . . . . . . . . 15-22 internazionali 17-1
Struttura delle directory in Linux. . . . . . 15-22 Internazionalizzazione e localizzazione . . . . 17-1
Applicazioni database multipiattaforma . . . 15-23 L’internazionalizzazione . . . . . . . . . . . 17-1
Differenze in dbExpress . . . . . . . . . . . 15-24 Localizzazione . . . . . . . . . . . . . . . . . 17-2
Differenze a livello di componenti . . . . . 15-25 Internazionalizzazione delle applicazioni . . . 17-2
x
Abilitazione del codice dell’applicazione . . 17-2 Considerazioni sul ridimensionamento
Set di caratteri . . . . . . . . . . . . . . . . 17-2 non dinamico . . . . . . . . . . . . . . 18-12
Set di caratteri OEM e ANSI . . . . . . . . 17-3 Considerazioni sul ridimensionamento
Set di caratteri multibyte . . . . . . . . . . 17-3 dinamico di schede e controlli . . . . 18-13
Caratteri estesi . . . . . . . . . . . . . . . 17-4 Regolazione in funzione del numero
Inclusione di funzionalità bidirezionali di colori disponibili . . . . . . . . . . 18-14
nelle applicazioni . . . . . . . . . . . . . 17-4 Font . . . . . . . . . . . . . . . . . . . . . . 18-14
Proprietà BiDiMode . . . . . . . . . . . . 17-4 Versioni del sistema operativo . . . . . . . 18-15
Funzioni specifiche della località . . . . . 17-7 Requisiti per la licenza d’uso del software . . 18-15
Progettazione di un’interfaccia utente . . . . 17-7 DEPLOY . . . . . . . . . . . . . . . . . . . 18-15
Testo . . . . . . . . . . . . . . . . . . . . . 17-7 README . . . . . . . . . . . . . . . . . . . 18-16
Immagini. . . . . . . . . . . . . . . . . . . 17-8 Accordo di licenza. . . . . . . . . . . . . . 18-16
Formati e ordinamento . . . . . . . . . . . 17-8 Documentazione sui prodotti di terze parti18-16
Configurazione della tastiera . . . . . . . 17-8
Isolamento delle risorse . . . . . . . . . . . . 17-8 Parte II
Creazione di DLL di risorse . . . . . . . . . . 17-9 Sviluppo di applicazioni database
Uso delle DLL di risorse . . . . . . . . . . . 17-10
Sostituzione dinamica delle DLL di risorse 17-11 Capitolo 19
Localizzazione delle applicazioni . . . . . . . 17-12
Localizzazione delle risorse . . . . . . . . . 17-12 Progettazione di applicazioni
database 19-1
Capitolo 18 Uso dei database . . . . . . . . . . . . . . . . . 19-1
Distribuzione di applicazioni 18-1 Tipi di database . . . . . . . . . . . . . . . . 19-3
Distribuzione di applicazioni generiche. . . . . 18-1 Sicurezza del database . . . . . . . . . . . . 19-4
Uso di programmi di installazione . . . . . . 18-2 Transazioni . . . . . . . . . . . . . . . . . . . 19-5
Identificazione dei file dell’applicazione . 18-2 Integrità referenziale, procedure
File di applicazione . . . . . . . . . . . . . 18-3 memorizzate e trigger. . . . . . . . . . . . 19-5
File package . . . . . . . . . . . . . . . . . 18-3 Architettura di un database . . . . . . . . . . . 19-6
Moduli di fusione . . . . . . . . . . . . . . 18-3 Struttura generale . . . . . . . . . . . . . . . 19-6
Controlli ActiveX . . . . . . . . . . . . . . 18-5 La scheda dell’interfaccia utente . . . . . 19-6
Applicazioni di ausilio . . . . . . . . . . . 18-5 Il modulo dati . . . . . . . . . . . . . . . 19-7
Ubicazione delle DLL . . . . . . . . . . . 18-6 Connessione diretta a un server
Distribuzione di applicazioni CLX . . . . . . . . 18-6 di database . . . . . . . . . . . . . . . . . . 19-8
Distribuzione di applicazioni database . . . . . 18-6 Utilizzo di un file dedicato su disco . . . . 19-10
Distribuzione di applicazioni database Collegamento a un altro dataset . . . . . . .19-11
dbExpress . . . . . . . . . . . . . . . . . . . 18-7 Connessione di un dataset client
Distribuzione di applicazioni BDE . . . . . . 18-8 a un altro dataset nella stessa
Borland Database Engine . . . . . . . . . 18-9 applicazione . . . . . . . . . . . . . . 19-12
Distribuzione di applicazioni Utilizzo di un’architettura multi-tier . 19-13
database multi-tier (DataSnap) . . . . . . . 18-9 Combinazione dei vari approcci . . . . . . 19-15
Distribuzione di applicazioni Web . . . . . . . . 18-9 Progettazione dell’interfaccia utente . . . . . 19-16
Distribuzione su server Apache . . . . . . 18-10 Analisi dei dati. . . . . . . . . . . . . . . . 19-16
Abilitazione dei moduli . . . . . . . . . 18-10 Scrittura di report . . . . . . . . . . . . . . 19-17
Applicazioni CGI . . . . . . . . . . . . . 18-11
Programmazione per ambienti Capitolo 20
di destinazione diversi. . . . . . . . . . . . . 18-12 Utilizzo dei controlli dati 20-1
Risoluzione dello schermo Uso delle funzioni comuni ai controlli dati . . 20-2
e numero di colori . . . . . . . . . . . . . 18-12 Associazione di un controllo dati
a un dataset. . . . . . . . . . . . . . . . . . 20-3
xi
Modifica del dataset Inserimento di un pulsante
associato in esecuzione . . . . . . . . . . 20-4 in una colonna . . . . . . . . . . . . . 20-23
Attivazione e disattivazione Ripristino dei valori predefiniti in una
del datasource . . . . . . . . . . . . . . . 20-4 colonna . . . . . . . . . . . . . . . . . 20-24
Risposta alle modifiche mediate dal Visualizzazione dei campi ADT e array . 20-24
datasource . . . . . . . . . . . . . . . . . 20-4 Impostazione delle opzioni per la griglia . 20-27
Modifica e aggiornamento dei dati . . . . . . 20-5 Editing nella griglia . . . . . . . . . . . . . 20-28
Attivazione dell’editing nei controlli Controllo del disegno della griglia . . . . 20-29
in fase di esecuzione . . . . . . . . . . . 20-5 Risposta alle azioni dell’utente
Modifica dei dati in un controllo . . . . . 20-5 in esecuzione . . . . . . . . . . . . . . . . 20-29
Disabilitazione e abilitazione della Creazione di una griglia contenente
visualizzazione dei dati . . . . . . . . . . . 20-6 altri controlli associati ai dati . . . . . . . . 20-30
Aggiornamento della visualizzazione Spostamento e gestione dei record . . . . . . 20-31
dei dati . . . . . . . . . . . . . . . . . . . . . 20-7 Scelta dei pulsanti del navigatore da
Abilitazione degli eventi mouse, visualizzare. . . . . . . . . . . . . . . . . 20-32
tastiera e timer . . . . . . . . . . . . . . . . 20-7 Come nascondere e mostrare i pulsanti
Scelta del modo in cui organizzare i dati . . . . 20-8 del navigatore in esecuzione . . . . . 20-33
Visualizzazione di un singolo record. . . . . 20-8 Visualizzazione del fumetto guida . . . . 20-33
Visualizzazione dei dati come etichette . 20-8 Uso di un singolo navigatore
Visualizzazione e modifica di campi per più dataset . . . . . . . . . . . . . . . 20-34
in una casella di testo . . . . . . . . . . . 20-9
Visualizzazione e modifica del testo Capitolo 21
in un controllo memo . . . . . . . . . . . 20-9 Creazione di report
Visualizzazione e modifica del testo
in un controllo rich edit . . . . . . . . 20-10
con Rave Reports 21-1
Panoramica . . . . . . . . . . . . . . . . . . . . 21-1
Visualizzazione e modifica di campi
Primi passi . . . . . . . . . . . . . . . . . . . . . 21-2
grafici in un controllo immagine . . . 20-10
Rave Visual Designer . . . . . . . . . . . . . . . 21-3
Visualizzazione e modifica di dati
Panoramica sui componenti . . . . . . . . . . . 21-4
in caselle combinate e di riepilogo . . 20-11
Componenti VCL/CLX. . . . . . . . . . . . 21-4
Gestione dei valori di campo booleani
Componenti Engine . . . . . . . . . . . . 21-4
con le caselle di controllo. . . . . . . . 20-14
Componenti Render . . . . . . . . . . . . 21-4
Restrizione dei valori del campo
Componenti Data connection . . . . . . 21-4
con controlli di opzione . . . . . . . . 20-15
Componenti Rave project . . . . . . . . . 21-5
Visualizzazione di più record . . . . . . . . 20-16
Componenti per i report . . . . . . . . . . . 21-5
Visualizzazione e modifica dei dati
Componenti di progetto. . . . . . . . . . 21-5
con TDBGrid . . . . . . . . . . . . . . . . . . 20-17
Data objects. . . . . . . . . . . . . . . . . 21-5
Uso di un controllo griglia nel suo stato
Componenti Standard . . . . . . . . . . . 21-5
predefinito. . . . . . . . . . . . . . . . . . 20-17
Componenti Drawing . . . . . . . . . . . 21-5
Creazione di una griglia personalizzata . . 20-18
Componenti Report . . . . . . . . . . . . 21-6
Caratteristiche delle colonne
Componenti Bar code . . . . . . . . . . . 21-6
persistenti . . . . . . . . . . . . . . . . 20-19
Per maggiori informazioni . . . . . . . . . . . . 21-6
Creazione di colonne persistenti . . . . 20-20
Cancellazione di colonne persistenti . . 20-21 Capitolo 22
Sistemazione dell’ordine delle colonne
persistenti . . . . . . . . . . . . . . . . 20-21 Uso dei componenti di supporto
Impostazione delle proprietà decisionale 22-1
di una colonna in progettazione . . . . 20-22 Panoramica . . . . . . . . . . . . . . . . . . . . 22-1
Definizione di una colonna elenco di I crosstab . . . . . . . . . . . . . . . . . . . . . . 22-2
consultazione . . . . . . . . . . . . . . 20-23 Crosstab monodimensionali . . . . . . . . . 22-3
xii
Crosstab multidimensionali . . . . . . . . . . 22-3 Componenti di supporto decisionale
Regole generali per l’uso dei componenti e controllo della memoria . . . . . . . . . . 22-20
di supporto decisionale . . . . . . . . . . . . . 22-3 Impostazione dei valori massimi per
Uso dei dataset con i componenti di supporto dimensioni, riepiloghi e celle. . . . . . . 22-21
decisionale . . . . . . . . . . . . . . . . . . . . 22-5 Impostazione dello stato della dimensione 22-21
Creazione di dataset decisionali Utilizzo delle dimensioni paginate . . . . 22-21
con TQuery o TTable . . . . . . . . . . . . . 22-5
Creazione di dataset decisionali Capitolo 23
con l’editor Decision Query . . . . . . . . . 22-6 Connessione ai database 23-1
Uso dei cubi decisionali . . . . . . . . . . . . . . 22-7 Uso di connessioni implicite . . . . . . . . . . . 23-2
Proprietà del cubo decisionale e eventi . . . 22-7 Controllo delle connessioni . . . . . . . . . . . 23-3
Uso di Decision Cube editor . . . . . . . . . 22-8 Connessione a un server di database . . . . 23-3
Visualizzazione e modifica delle Scollegamento da un server di database . . 23-4
impostazioni delle dimensioni . . . . . 22-8 Controllo del login al server . . . . . . . . . . . 23-4
Impostazione del numero massimo di Gestione delle transazioni . . . . . . . . . . . . 23-6
dimensioni e di riepiloghi disponibili . 22-9 Avvio di una transazione . . . . . . . . . . . 23-7
Visualizzazione e modifica Chiusura di una transazione . . . . . . . . . 23-8
delle opzioni di progetto . . . . . . . . . 22-9 Chiusura di una transazione
Uso delle sorgenti decisionali. . . . . . . . . . . 22-9 andata a buon fine . . . . . . . . . . . . 23-8
Proprietà ed eventi . . . . . . . . . . . . . . . 22-9 Chiusura di una transazione
Uso dei pivot decisionali . . . . . . . . . . . . 22-10 non andata a buon fine . . . . . . . . . 23-9
Proprietà dei pivot decisionali . . . . . . . 22-10 Specifica del livello di isolamento delle
Creazione e uso delle griglie decisionali . . . 22-11 transazioni . . . . . . . . . . . . . . . . . 23-10
Creazione di griglie decisionali . . . . . . . 22-11 Invio di comandi al server . . . . . . . . . . . .23-11
Uso delle griglie decisionali . . . . . . . . . 22-11 Operazioni con i dataset associati . . . . . . . 23-13
Apertura e chiusura dei campi Chiusura dei dataset senza scollegarsi
della griglia decisionale . . . . . . . . 22-12 dal server . . . . . . . . . . . . . . . . . . 23-13
Riorganizzazione di righe e colonne Scansione di tutti i dataset associati . . . . 23-13
in griglie decisionali . . . . . . . . . . 22-12 Ottenimento di metadati . . . . . . . . . . . . 23-14
Espansione dei dettagli nelle griglie Elenco delle tabelle disponibili . . . . . . 23-14
decisionali . . . . . . . . . . . . . . . . 22-12 Elenco dei campi in una tabella . . . . . . 23-15
Limitazione della selezione Elenco delle procedure registrate
delle dimensioni in griglie decisionali 22-12 disponibili . . . . . . . . . . . . . . . . . 23-15
Proprietà della griglia decisionale . . . . . 22-13 Elenco degli indici disponibili . . . . . . . 23-15
Creazione e uso dei grafici decisionali. . . . . 22-14 Elenco dei parametri delle procedure
Creazione di grafici decisionali . . . . . . . 22-14 registrate . . . . . . . . . . . . . . . . . . 23-15
Uso dei grafici decisionali . . . . . . . . . . 22-14
Visualizzazione del grafico decisionale . . 22-16 Capitolo 24
Personalizzazione dei grafici decisionali . 22-16 I dataset 24-1
Impostazioni predefinite dei modelli Utilizzo dei discendenti di TDataSet . . . . . . 24-2
di grafico decisionale . . . . . . . . . . 22-17 Determinazione degli stati del dataset . . . . . 24-3
Personalizzazione delle serie Apertura e chiusura di dataset . . . . . . . . . 24-4
del grafico decisionale . . . . . . . . . 22-18 Spostamenti nei dataset . . . . . . . . . . . . . 24-5
Componenti di supporto decisionale Uso dei metodi First e Last . . . . . . . . . . 24-6
in esecuzione . . . . . . . . . . . . . . . . . . 22-19 Uso dei metodi Next e Prior . . . . . . . . . 24-7
Pivot decisionali in esecuzione . . . . . . . 22-19 Uso del metodo MoveBy . . . . . . . . . . . 24-7
Griglie decisionali in esecuzione . . . . . . 22-20 Uso delle proprietà Eof e Bof. . . . . . . . . 24-8
Grafici decisionali in esecuzione . . . . . . 22-20 Eof . . . . . . . . . . . . . . . . . . . . . . 24-8
Bof . . . . . . . . . . . . . . . . . . . . . . 24-9
xiii
Contrassegno e ritorno ai record . . . . . . . 24-9 Specifica del record corrente dopo
La proprietà Bookmark. . . . . . . . . . 24-10 una ricerca andata a buon fine . . . . 24-31
Il metodo GetBookmark . . . . . . . . . 24-10 Ricerca in base a chiavi parziali . . . . 24-31
I metodi GotoBookmark Ripetizione o ampliamento
e BookmarkValid . . . . . . . . . . . . 24-10 di una ricerca . . . . . . . . . . . . . . 24-31
Il metodo CompareBookmarks . . . . . 24-10 Limitazione dei record con gli intervalli . 24-32
Il metodo FreeBookmark. . . . . . . . . 24-10 Differenze fra intervalli e filtri . . . . . 24-32
Un esempio di utilizzo dei segnalibri. . 24-10 Specifica degli intervalli. . . . . . . . . 24-33
Ricerche nei dataset . . . . . . . . . . . . . . . 24-11 Modifica di un intervallo . . . . . . . . 24-35
Uso di Locate . . . . . . . . . . . . . . . . . 24-11 Applicazione o annullamento di un
Uso di Lookup . . . . . . . . . . . . . . . . 24-12 intervallo . . . . . . . . . . . . . . . . 24-36
Visualizzazione e modifica di un Creazione di relazioni master/detail . . . 24-37
sottoinsieme di dati usando i filtri . . . . . . 24-13 Trasformazione della tabella nella
Attivazione e disattivazione dei filtri . . . 24-13 tabella dettaglio di un altro dataset. . 24-37
Creazione di filtri . . . . . . . . . . . . . . . 24-14 Utilizzo di tabelle dettaglio annidate . 24-39
Impostazione della proprietà Filter . . . 24-14 Controllo dell’accesso alle tabelle
Scrittura di un gestore di eventi in lettura/scrittura. . . . . . . . . . . . . 24-39
OnFilterRecord . . . . . . . . . . . . . 24-15 Creazione e cancellazione di tabelle. . . . 24-40
Commutazione dei gestori evento Creazione di tabelle . . . . . . . . . . . 24-40
di filtro in esecuzione . . . . . . . . . . 24-16 Cancellazione di tabelle . . . . . . . . . 24-43
Impostazione delle opzioni del filtro. . . . 24-16 Svuotamento di tabelle . . . . . . . . . . . 24-43
Spostamento tra i record in un dataset Sincronizzazione di tabelle . . . . . . . . . 24-44
filtrato . . . . . . . . . . . . . . . . . . . . 24-17 Utilizzo di dataset di tipo query. . . . . . . . 24-44
Modifica dei dati . . . . . . . . . . . . . . . . . 24-17 Specifica della query . . . . . . . . . . . . 24-45
Modifica dei record . . . . . . . . . . . . . 24-18 Specifica di una query utilizzando la
Aggiunta di nuovi record . . . . . . . . . . 24-19 proprietà SQL. . . . . . . . . . . . . . 24-46
Inserimento di record. . . . . . . . . . . 24-20 Specifica di una query utilizzando la
Aggiunta di record . . . . . . . . . . . . 24-20 proprietà CommandText . . . . . . . 24-47
Cancellazione di record . . . . . . . . . . . 24-21 Utilizzo dei parametri nelle query. . . . . 24-47
Registrazione dei dati . . . . . . . . . . . . 24-21 Fornitura dei parametri
Annullamento delle modifiche . . . . . . . 24-22 in progettazione . . . . . . . . . . . . 24-48
Modifica di interi record. . . . . . . . . . . 24-22 Fornitura dei parametri in esecuzione. 24-49
Calcolo dei campi . . . . . . . . . . . . . . . . 24-24 Impostazione di relazioni master/detail
Tipi di dataset . . . . . . . . . . . . . . . . . . 24-24 mediante parametri . . . . . . . . . . . . 24-49
Utilizzo dei dataset di tipo tabella . . . . . . . 24-26 Preparazione di query . . . . . . . . . . . 24-51
Vantaggi dell’utilizzo di dataset Esecuzione di query che non restituiscono
di tipo tabella . . . . . . . . . . . . . . . . 24-27 un set risultato . . . . . . . . . . . . . . . 24-51
Ordinamento dei record con indici . . . . . 24-27 Utilizzo di set risultato unidirezionali . . 24-52
Ottenimento di informazioni Utilizzo di dataset di tipo procedura
sugli indici . . . . . . . . . . . . . . . . 24-28 registrata . . . . . . . . . . . . . . . . . . . . 24-52
Specifica di un indice con IndexName . 24-28 Operazioni con i parametri
Creazione di un indice delle procedure registrate. . . . . . . . . 24-54
con IndexFieldNames . . . . . . . . . 24-29 Impostazione dei parametri
Utilizzo di Indexes per cercare record . . . 24-29 in progettazione . . . . . . . . . . . . 24-54
Esecuzione di una ricerca Utilizzo di parametri in esecuzione . . 24-56
con metodi Goto. . . . . . . . . . . . . 24-30 Preparazione delle procedure registrate . 24-57
Esecuzione di una ricerca Esecuzione di procedure registrate
con metodi Find . . . . . . . . . . . . . 24-31 che non restituiscono un set risultato . . 24-57
Prelievo di più set risultato. . . . . . . . . 24-57
xiv
Capitolo 25 Utilizzo dei vincoli . . . . . . . . . . . . . . . 25-22
Operazioni con i componenti campo 25-1 Creazione di un vincolo custom . . . . . .
Uso dei vincoli del server. . . . . . . . . .
25-22
25-23
Componenti campo dinamici. . . . . . . . . . . 25-2
Uso dei campi oggetto . . . . . . . . . . . . . 25-24
Componenti campo persistenti . . . . . . . . . . 25-3
Visualizzazione di campi ADT e array . . 25-24
Creazione di campi persistenti . . . . . . . . 25-4
Uso dei campi ADT . . . . . . . . . . . . . 25-25
Disposizione dei campi persistenti . . . . . . 25-5
Utilizzo di componenti campo
Definizione di nuovi campi persistenti . . . 25-5
persistenti . . . . . . . . . . . . . . . . 25-25
Definizione di un campo dati . . . . . . . 25-7
Utilizzo del metodo FieldByName
Definizione di un campo calcolato . . . . 25-7
del dataset . . . . . . . . . . . . . . . 25-26
Programmazione di un campo calcolato . 25-8
Utilizzo della proprietà FieldValues
Definizione di un campo
del dataset . . . . . . . . . . . . . . . 25-26
di consultazione . . . . . . . . . . . . . . 25-9
Utilizzo della proprietà FieldValues
Definizione di un campo
del campo ADT. . . . . . . . . . . . . 25-26
di aggregazione . . . . . . . . . . . . . 25-10
Utilizzo della proprietà Fields
Cancellazione di componenti campo
del campo ADT. . . . . . . . . . . . . 25-26
persistenti . . . . . . . . . . . . . . . . . . 25-11
Uso dei campi array. . . . . . . . . . . . . 25-26
Impostazione di proprietà
Utilizzo di campi persistenti . . . . . . 25-27
ed eventi dei campi persistenti . . . . . . 25-11
Uso della proprietà FieldValues
Impostazione delle proprietà di
del campo array . . . . . . . . . . . . 25-27
visualizzazione
Uso della proprietà Fields
e modifica in progettazione . . . . . . 25-12
del campo array . . . . . . . . . . . . 25-27
Impostazione delle proprietà del
Uso dei campi dataset. . . . . . . . . . . . 25-28
componente campo in esecuzione. . . 25-13
Visualizzazione dei campi dataset . . . 25-28
Creazione di set di attributi
Accesso ai dati in un dataset annidato 25-28
per i componenti campo . . . . . . . . 25-14
Uso dei campi riferimento . . . . . . . . . 25-29
Associazione di set di attributi
Visualizzazione dei campi riferimento 25-29
ai componenti campo . . . . . . . . . . 25-14
Accesso ai dati di un campo
Rimozione delle associazioni
riferimento . . . . . . . . . . . . . . . 25-29
degli attributi . . . . . . . . . . . . . . 25-15
Controllo e mascheratura dell’input . . 25-15
Uso dei formati predefiniti per i campi
Capitolo 26
numerici, data e ora. . . . . . . . . . . 25-16 Uso di Borland Database Engine 26-1
Gestione degli eventi . . . . . . . . . . . 25-16 L’architettura BDE . . . . . . . . . . . . . . . . 26-1
Operazioni con i metodi del componente Impiego di dataset per BDE . . . . . . . . . 26-2
campo in esecuzione . . . . . . . . . . . . . . 25-17 Associazione di un dataset a
Visualizzazione, conversione e accesso connessioni di database e di sessione . 26-3
ai valori di campo . . . . . . . . . . . . . . . 25-18 Cache dei BLOB . . . . . . . . . . . . . . 26-4
Visualizzazione dei valori Ottenimento degli handle BDE. . . . . . 26-4
dei componenti campo Utilizzo di TTable . . . . . . . . . . . . . . . 26-5
nei controlli standard. . . . . . . . . . . . 25-19 Specifica del tipo di tabella
Conversione dei valori di campo . . . . . . 25-19 per tabelle locali . . . . . . . . . . . . . 26-5
Accesso ai valori dei campi Controllo dell’accesso a tabelle locali
con la proprietà predefinita del dataset . 25-21 in lettura/scrittura . . . . . . . . . . . . 26-6
Accesso ai valori dei campi con Specifica di file indice dBASE . . . . . . 26-6
la proprietà Fields di un dataset . . . . . 25-21 Come rinominare tabelle locali . . . . . . 26-8
Accesso ai valori dei campi con il metodo Importazione di dati da altre tabelle. . . 26-8
FieldByName di un dataset . . . . . . . . 25-21 Utilizzo di TQuery . . . . . . . . . . . . . . 26-9
Impostazione del valore predefinito Creazione di query eterogenee . . . . . . 26-9
di un campo. . . . . . . . . . . . . . . . . . . 25-22
xv
Ottenimento di un set risultato Creazione di un gestore di evento
modificabile . . . . . . . . . . . . . . . 26-10 OnUpdateRecord. . . . . . . . . . . . 26-38
Aggiornamento di set risultato Gestione degli errori di aggiornamento 26-40
a sola lettura . . . . . . . . . . . . . . . 26-11 Aggiornamento di dataset mediante
Utilizzo di TStoredProc . . . . . . . . . . . 26-12 oggetti update . . . . . . . . . . . . . . . 26-42
Inglobamento dei parametri . . . . . . . 26-12 Creazione di istruzioni SQL
Operazioni con procedure registrate per componenti update . . . . . . . . 26-43
ridefinite Oracle . . . . . . . . . . . . . 26-13 Utilizzo di più oggetti update . . . . . 26-47
Collegamento ai database Esecuzione delle istruzioni SQL . . . . 26-48
tramite TDatabase . . . . . . . . . . . . . 26-13 Utilizzo di TBatchMove . . . . . . . . . . . . 26-50
Associazione di un componente Creazione di un componente batch move 26-51
database a una sessione . . . . . . . . 26-13 Specifica della modalità
Interazioni tra il componente Session di spostamento batch . . . . . . . . . . . 26-52
e i database . . . . . . . . . . . . . . . 26-14 Aggiunta di record. . . . . . . . . . . . 26-52
Identificazione del database . . . . . . . 26-14 Aggiornamento di record . . . . . . . . 26-52
Apertura di una connessione Aggiunta e aggiornamento di record . 26-53
utilizzando TDatabase . . . . . . . . . 26-16 Copia di dataset . . . . . . . . . . . . . 26-53
Impiego di componenti database Cancellazione di record . . . . . . . . . 26-53
nei moduli dati . . . . . . . . . . . . . 26-17 Mappatura dei tipi di dati . . . . . . . . . 26-53
Gestione delle sessioni di database . . . . . 26-17 Esecuzione di spostamenti batch . . . . . 26-54
Attivazione di una sessione . . . . . . . 26-18 Gestione degli errori di spostamento batch 26-55
Specifica del comportamento predefinito Il Data Dictionary . . . . . . . . . . . . . . . . 26-55
della connessione al database . . . . . 26-19 Strumenti per operare con BDE . . . . . . . . 26-57
Gestione delle connessioni
con il database . . . . . . . . . . . . . . 26-20 Capitolo 27
Operazioni con tabelle Paradox Operazioni con componenti ADO 27-1
e dBASE protette da password . . . . 26-22 Panoramica dei componenti ADO . . . . . . . 27-1
Specifica delle ubicazioni Connessione a datastore ADO. . . . . . . . . . 27-2
delle directory di Paradox . . . . . . . 26-25 Connessione a un datastore mediante
Operazioni con gli alias BDE . . . . . . 26-26 TADOConnection . . . . . . . . . . . . . . 27-3
Reperimento di informazioni Accesso all’oggetto connessione . . . . . 27-4
su una sessione . . . . . . . . . . . . . 26-27 Messa a punto di una connessione . . . . . 27-5
Creazione di sessioni supplementari . . 26-28 Come forzare connessioni asincrone. . . 27-5
Attribuzione del nome a una sessione . 26-29 Controllo del timeout . . . . . . . . . . . 27-5
Gestione di sessioni multiple . . . . . . 26-30 Indicazione dei tipi di operazione che la
Utilizzo delle transazioni con BDE. . . . . . . 26-32 connessione supporta . . . . . . . . . . 27-6
Utilizzo di passthrough SQL . . . . . . . . 26-32 Come specificare se la connessione
Utilizzo delle transazioni locali . . . . . . . 26-33 avvia in automatico le transazioni . . . 27-7
Utilizzo di BDE per gli aggiornamenti Accesso ai comandi della connessione . . . 27-7
in cache . . . . . . . . . . . . . . . . . . . . . 26-34 Eventi di connessione ADO . . . . . . . . . 27-8
Attivazione degli aggiornamenti Eventi quando si stabilisce
in cache con BDE . . . . . . . . . . . . . . 26-35 una connessione . . . . . . . . . . . . . 27-8
Applicazione degli aggiornamenti Eventi alla chiusura del collegamento . . 27-8
in cache basati su BDE . . . . . . . . . . . 26-36 Eventi durante la gestione
Applicazione degli aggiornamenti nella delle transazioni . . . . . . . . . . . . . 27-9
cache mediante un database . . . . . . 26-37 Altri eventi . . . . . . . . . . . . . . . . . 27-9
Applicazione degli aggiornamenti Uso di dataset ADO . . . . . . . . . . . . . . . 27-9
in cache con i metodi dei componenti Connessione di un dataset ADO
dataset . . . . . . . . . . . . . . . . . . 26-38 a un datastore. . . . . . . . . . . . . . 27-10
xvi
Operazioni con set di record. . . . . . . 27-11 La struttura dei dataset di metadati . . 28-14
Filtraggio di record mediante segnalibri 27-11 Debug di applicazioni dbExpress . . . . . . . 28-18
Prelievo di record in modalità asincrona27-12 Utilizzo di TSQLMonitor per controllare
Uso di aggiornamenti batch . . . . . . . 27-12 i comandi SQL . . . . . . . . . . . . . . . 28-18
Caricamento e salvataggio di dati Utilizzo di una callback per controllare
su file . . . . . . . . . . . . . . . . . . . 27-15 i comandi SQL . . . . . . . . . . . . . . . 28-19
Utilizzo di TADODataSet . . . . . . . . . . 27-16
Uso di oggetti Command . . . . . . . . . . . . 27-18 Capitolo 29
Specifica del comando . . . . . . . . . . . . 27-18 Utilizzo dei dataset client 29-1
Utilizzo del metodo Execute . . . . . . . . 27-19 Utilizzo dei dati tramite un dataset client . . . 29-2
Annullamento di comandi . . . . . . . . . 27-19 Come spostarsi tra i dati nei dataset client . 29-2
Reperimento di set risultato con comandi . 27-20 Come limitare i record da visualizzare . . . 29-2
Gestione dei parametri dei comandi . . . . 27-20 Editing di dati . . . . . . . . . . . . . . . . . 29-5
Annullamento delle modifiche . . . . . . 29-5
Capitolo 28 Salvataggio delle modifiche . . . . . . . 29-6
Uso di dataset unidirezionali 28-1 Vincoli sui valori dei dati . . . . . . . . . . . 29-7
Tipi di dataset unidirezionali . . . . . . . . . . . 28-2 Specifica di vincoli custom . . . . . . . . 29-7
Connessione al server di database . . . . . . . . 28-2 Ordinamento e indicizzazione . . . . . . . . 29-8
Configurazione di TSQLConnection . . . . . 28-3 Aggiunta di un nuovo indice . . . . . . . 29-8
Identificazione del driver . . . . . . . . . 28-3 Cancellazione e cambio degli indici . . . 29-9
Specifica dei parametri di connessione . . 28-4 Uso degli indici per il
Assegnazione di un nome raggruppamento dei dati . . . . . . . 29-10
a una descrizione della connessione . . 28-4 Rappresentazione dei valori calcolati . . . .29-11
Utilizzo di Connection Editor . . . . . . . 28-5 Uso di campi calcolati internamente
Specifica dei dati da visualizzare. . . . . . . . . 28-6 nei dataset client . . . . . . . . . . . . .29-11
Rappresentazione dei risultati di una query 28-6 Uso delle aggregazioni di manutenzione . 29-12
Rappresentazione dei record in una tabella . 28-7 Specifica delle aggregazioni . . . . . . 29-12
Rappresentazione di una tabella Aggregazione di gruppi di record . . . 29-13
utilizzando TSQLDataSet . . . . . . . . 28-7 Come ottenere valori di aggregazione. 29-14
Rappresentazione di una tabella Copia dei dati da un altro dataset . . . . . 29-14
utilizzando TSQLTable . . . . . . . . . . 28-7 Assegnazione diretta dei dati. . . . . . 29-15
Rappresentazione dei risultati Clonazione di un cursor di un dataset
di una procedura registrata . . . . . . . . . 28-8 client . . . . . . . . . . . . . . . . . . . 29-15
Reperimento dei dati . . . . . . . . . . . . . . . 28-8 Aggiunta di informazioni specifiche per
Preparazione del dataset. . . . . . . . . . . . 28-9 l’applicazione ai dati . . . . . . . . . . . 29-16
Reperimento di più dataset . . . . . . . . . . 28-9 Utilizzo di un dataset client
Esecuzione di comandi per registrare in cache gli aggiornamenti. . 29-16
che non restituiscono record . . . . . . . . . 28-10 Panoramica sull’utilizzo
Specifica del comando da eseguire . . . . . 28-10 degli aggiornamenti in cache. . . . . . . 29-17
Esecuzione del comando . . . . . . . . . . 28-11 Scelta del tipo di dataset
Creazione e modifica dei metadati per gli aggiornamenti in cache . . . . . . 29-19
del server . . . . . . . . . . . . . . . . . . 28-11 Indicazione dei record modificati . . . . . 29-20
Configurazione di cursor master/detail Aggiornamento dei record . . . . . . . . . 29-21
collegati . . . . . . . . . . . . . . . . . . . . . 28-12 Applicazione degli aggiornamenti. . . 29-22
Accesso a informazioni di schema . . . . . . . 28-13 Interventi durante l’applicazione degli
Prelievo di metadati in un dataset aggiornamenti . . . . . . . . . . . . . 29-23
unidirezionale. . . . . . . . . . . . . . . . 28-13 Riconciliazione degli errori
Ottenimento dei dati dopo aver di aggiornamento . . . . . . . . . . . 29-24
utilizzato il dataset per i metadati. . . 28-14
xvii
Uso di un dataset client Configurazione di
con un provider di dati . . . . . . . . . . . . 29-26 TRemoteDataModule . . . . . . . . . 30-14
Specifica di un provider . . . . . . . . . . . 29-26 Configurazione dei TMTSDataModule 30-15
Richiesta di dati da un dataset sorgente Configurazione di TSoapDataModule. 30-16
o da un documento . . . . . . . . . . . . . 29-27 Estensione dell’interfaccia
Recupero incrementale . . . . . . . . . . 29-28 dell’application server . . . . . . . . . . 30-16
Recupero in automatico . . . . . . . . . 29-28 Aggiunta di callback all’interfaccia
Ottenimento dei parametri dell’application server . . . . . . . . . 30-17
dal dataset sorgente . . . . . . . . . . . . 29-29 Estensione dell’interfaccia
Passaggio di parametri al dataset sorgente 29-30 transazionale di un application server 30-17
Invio dei parametri di una query Gestione delle transazioni
o di una procedura memorizzata . . . 29-30 nelle applicazioni multi-tiered . . . . . . 30-18
Delimitazione dei record Supporto delle relazioni master/detail . . 30-19
con i parametri . . . . . . . . . . . . . 29-31 Supporto delle informazioni di stato
Gestione dei vincoli dal server . . . . . . . 29-31 nei moduli dati remoti . . . . . . . . . . 30-19
Rinnovo dei record . . . . . . . . . . . . . . 29-32 Uso di più moduli dati remoti . . . . . . . 30-21
Comunicazione con i provider Registrazione dell’application server . . . . . 30-22
tramite eventi custom . . . . . . . . . . . 29-33 Creazione dell’applicazione client . . . . . . 30-23
Ridefinizione del dataset sorgente . . . . . 29-34 Connessione all’application server . . . . 30-24
Uso di un dataset client con dati basati su file 29-35 Specifica di una connessione
Creazione di un nuovo dataset . . . . . . . 29-35 con DCOM . . . . . . . . . . . . . . . 30-24
Caricamento dei dati da un file Specifica di una connessione
o da uno stream . . . . . . . . . . . . . . . 29-35 con i socket . . . . . . . . . . . . . . . 30-25
Fusione delle modifiche nei dati . . . . . . 29-36 Specifica di una connessione con HTTP 30-26
Salvataggio dei dati in un file Specifica di una connessione con SOAP 30-26
o in uno stream . . . . . . . . . . . . . . . 29-37 Brokering delle connessioni . . . . . . 30-27
Utilizzo di un dataset semplice. . . . . . . . . 29-37 Gestione delle connessioni al server. . . . 30-28
Quando utilizzare TSimpleDataSet. . . . . 29-38 Connessione al server . . . . . . . . . . 30-28
Configurazione di un dataset semplice . . 29-38 Abbandono o modifica di una
connessione a un server . . . . . . . . 30-29
Capitolo 30 Chiamata delle interfacce del server . . . 30-29
Creazione di applicazioni multi-tier 30-1 Uso del binding anticipato con DCOM 30-30
Vantaggi di un modello database multi-tier . . 30-2 Uso di interfacce dispatch
Applicazioni multi-tier su database . . . . . . . 30-2 con TCP/IP o HTTP . . . . . . . . . . 30-30
Panoramica di un’applicazione three-tier . . 30-3 Chiamata all’interfaccia di un server
Struttura dell’applicazione client . . . . . . . 30-4 basato su SOAP . . . . . . . . . . . . 30-30
La struttura dell’application server . . . . . 30-5 Connessione a un application server
Contenuti del modulo dati remoto . . . . 30-6 che utilizza più moduli dati . . . . . . . 30-31
Uso di moduli dati transazionali . . . . . 30-6 Scrittura di applicazioni client basate su Web 30-32
Centralizzazione di moduli dati remoti . 30-8 Distribuzione di un’applicazione client
Scelta di un protocollo di connessione . . . . 30-9 come controllo ActiveX . . . . . . . . . . 30-33
Uso di connessioni DCOM. . . . . . . . . 30-9 Creazione di una scheda Active Form
Uso delle connessioni socket . . . . . . . 30-9 per l’applicazione client . . . . . . . . 30-33
Uso di connessioni Web . . . . . . . . . 30-10 Creazione di applicazioni Web con
Utilizzo di connessioni SOAP . . . . . . 30-11 InternetExpress . . . . . . . . . . . . . . 30-34
Costruzione di un’applicazione multi-tier . . 30-11 Creazione di un’applicazione
Creazione dell’application server . . . . . . . 30-12 InternetExpress . . . . . . . . . . . . . . 30-35
Impostazione del modulo dati remoto . . . 30-13 Uso delle librerie javascript . . . . . . . 30-36
xviii
Concessione dei permessi per l’accesso e Capitolo 32
l’avvio dell’application server . . . . . 30-37
Uso di un broker XML . . . . . . . . . . . . 30-37
Uso di XML nelle applicazioni
Recupero di pacchetti dati XML. . . . . 30-37 database 32-1
Applicazione degli aggiornamenti da Definizione della trasformazione . . . . . . . . 32-1
pacchetti delta XML . . . . . . . . . . 30-38 Mappatura tra nodi XML e campi di un
Creazione di pagine web con produttori di pacchetto dati . . . . . . . . . . . . . . . . 32-2
pagine InternetExpress. . . . . . . . . . . 30-40 Utilizzo di XMLMapper . . . . . . . . . . . 32-4
Utilizzo di Web page editor . . . . . . . 30-40 Caricamento di uno schema XML
Impostazione delle proprietà o di un pacchetto dati . . . . . . . . . . 32-4
degli elementi Web . . . . . . . . . . . 30-41 Definizione delle mappature . . . . . . . 32-5
Personalizzazione del modello del Generazione dei file di trasformazione . 32-6
produttore di pagine InternetExpress. 30-42 Conversione di documenti XML
in pacchetti dati . . . . . . . . . . . . . . . . . 32-6
Capitolo 31 Specifica del documento XML di origine . . 32-6
Uso di componenti provider 31-1 Specifica della trasformazione . . . . . . . . 32-7
Generazione del pacchetto dati risultante . 32-7
Individuazione della sorgente dati. . . . . . . . 31-2
Conversione dei nodi definiti dall’utente. . 32-7
Uso di un dataset come sorgente dati . . . . 31-2
Impiego di un documento XML
Uso di un documento XML
come origine di un provider . . . . . . . . . . 32-8
come sorgente dati . . . . . . . . . . . . . . 31-2
Utilizzo di documenti XML come client di un
Comunicazione con il dataset client . . . . . . . 31-3
provider . . . . . . . . . . . . . . . . . . . . . 32-9
Come applicare gli aggiornamenti usando un
Prelievo di un documento XML
provider di dataset . . . . . . . . . . . . . . . . 31-4
da un provider . . . . . . . . . . . . . . . . 32-9
Controllo delle informazioni incluse
Applicazione degli aggiornamenti da un
nei pacchetti dati . . . . . . . . . . . . . . . . . 31-4
documento XML ad un provider . . . . 32-10
Specifica dei campi inclusi
in un pacchetto dati . . . . . . . . . . . . . 31-5
Impostazione di opzioni che influenzano i
Parte III
pacchetti dati . . . . . . . . . . . . . . . . . 31-5 Creazione di applicazioni Internet
Aggiunta di informazioni personali
ai pacchetti dati . . . . . . . . . . . . . . . . 31-7 Capitolo 33
Risposta alle richieste di dati del client . . . . . 31-7 Creazione di applicazioni server
Risposta alle richieste di aggiornamento
del client. . . . . . . . . . . . . . . . . . . . . . 31-8
per Internet 33-1
Web Broker e WebSnap. . . . . . . . . . . . . . 33-1
Modifica dei pacchetti delta prima
Terminologia e standard . . . . . . . . . . . . . 33-3
dell’aggiornamento del database . . . . . . 31-9
Parti di uno Uniform Resource Locator. . . 33-4
Come influenzare la modalità
URI e URL . . . . . . . . . . . . . . . . . 33-4
di applicazione degli aggiornamenti . . . 31-10
Informazioni dell’header
Vaglio dei singoli aggiornamenti . . . . . . 31-11
della richiesta HTTP. . . . . . . . . . . . . 33-4
Risoluzione degli errori di aggiornamento
Attività di un server HTTP . . . . . . . . . . . 33-5
sul provider . . . . . . . . . . . . . . . . . 31-12
Composizione delle richieste del client . . . 33-5
Applicazione di aggiornamenti a dataset che
Soddisfacimento delle richieste del client . 33-6
non rappresentano una singole tabella. . 31-12
Risposta alle richieste del client . . . . . . . 33-6
Risposta agli eventi generati dal client . . . . 31-13
Tipi di applicazioni per server Web . . . . . . . 33-6
Gestione dei vincoli del server . . . . . . . . . 31-13
ISAPI e NSAPI . . . . . . . . . . . . . . . 33-7
CGI indipendente . . . . . . . . . . . . . 33-7
Apache . . . . . . . . . . . . . . . . . . . 33-7
Web App Debugger . . . . . . . . . . . . 33-8
xix
Conversione del tipo di destinazione per Creazione di messaggi di risposta HTTP. . . .34-11
applicazioni Web server . . . . . . . . . . . 33-8 Compilazione dell’intestazione
Debug di applicazioni server . . . . . . . . . . . 33-9 della risposta . . . . . . . . . . . . . . . . .34-11
Utilizzo di Web Application Debugger . . . 33-9 Indicazione dello stato della risposta . 34-12
Avvio dell’applicazione con Indicazione della necessità di azione
Web Application Debugger . . . . . . 33-10 da parte del client . . . . . . . . . . . 34-12
Conversione dell’applicazione in un altro Descrizione dell’applicazione server . 34-12
tipo di applicazione per Web server . 33-10 Descrizione del contenuto . . . . . . . 34-13
Debug di applicazioni Web Impostazione del contenuto della risposta 34-13
sotto forma di DLL . . . . . . . . . . . . . 33-10 Invio della risposta . . . . . . . . . . . . . 34-13
Diritti utente necessari Generazione del contenuto dei messaggi
per il debug di DLL . . . . . . . . . . . 33-11 di risposta . . . . . . . . . . . . . . . . . . . 34-14
Utilizzo di componenti
Capitolo 34 produttori di pagine. . . . . . . . . . . . 34-14
Utilizzo di Web Broker 34-1 Modelli HTML . . . . . . . . . . . . . . 34-14
Creazione di applicazioni per Web server Specifica del modello HTML . . . . . . 34-15
con Web Broker. . . . . . . . . . . . . . . . . . 34-1 Conversione dei tag HTML trasparenti 34-15
Il modulo Web . . . . . . . . . . . . . . . . . 34-2 Utilizzo dei produttori di pagine
L’oggetto Application Web . . . . . . . . . . 34-3 partendo da un elemento di azione . 34-16
Struttura delle applicazioni Web Broker. . . . . 34-3 Concatenamento di produttori
Il dispatcher Web. . . . . . . . . . . . . . . . . . 34-4 di pagine . . . . . . . . . . . . . . . . 34-17
Aggiunta di azioni al dispatcher . . . . . . . 34-5 Utilizzo di informazioni di database
Dispatch dei messaggi di richiesta . . . . . . 34-5 nelle risposte. . . . . . . . . . . . . . . . . . 34-18
Elementi di azione . . . . . . . . . . . . . . . . . 34-6 Aggiunta di una sessione
Determinazione dell’attivazione a un modulo Web . . . . . . . . . . . . . 34-18
degli elementi di azione . . . . . . . . . . . 34-6 Rappresentazione di informazioni
L’URL di destinazione . . . . . . . . . . . 34-6 di database in HTML . . . . . . . . . . . 34-19
Il tipo di metodo della richiesta . . . . . . 34-7 Utilizzo dei produttori
Attivazione e disattivazione di pagine di dataset . . . . . . . . . . 34-19
di elementi di azione . . . . . . . . . . . 34-7 Utilizzo dei produttori di tabelle. . . . 34-19
Scelta di un elemento di azione Specifica degli attributi di una tabella . 34-20
predefinito . . . . . . . . . . . . . . . . . 34-7 Specifica degli attributi di riga . . . . . 34-20
Risposta a messaggi di richiesta mediante Specifica delle colonne . . . . . . . . . 34-20
elementi di azione . . . . . . . . . . . . . . 34-8 Inserimento di tabelle
Invio della risposta . . . . . . . . . . . . . 34-8 nei documenti HTML . . . . . . . . . 34-21
Utilizzo di più elementi di azione. . . . . 34-9 Impostazione di un produttore
Accesso alle informazioni della richiesta client. 34-9 di tabelle di dataset . . . . . . . . . . 34-21
Proprietà contenenti informazioni Configurazione di un produttore
dello header della richiesta . . . . . . . . . 34-9 di tabelle di query . . . . . . . . . . . 34-21
Proprietà che identificano
la destinazione. . . . . . . . . . . . . . . 34-9 Capitolo 35
Proprietà che descrivono il client Web . 34-10 Creazione di applicazioni
Proprietà che identificano Web Server con WebSnap 35-1
lo scopo della richiesta . . . . . . . . . 34-10 Componenti fondamentali di WebSnap . . . . 35-2
Proprietà che descrivono Moduli Web . . . . . . . . . . . . . . . . . . 35-2
la risposta prevista . . . . . . . . . . . 34-10 Tipi di modulo Web application . . . . . 35-3
Proprietà che descrivono il contenuto . 34-11 Moduli pagina Web . . . . . . . . . . . . 35-4
Il contenuto dei messaggi Moduli dati Web . . . . . . . . . . . . . . 35-5
di richiesta HTTP . . . . . . . . . . . . . . 34-11 Adattatori . . . . . . . . . . . . . . . . . . . 35-5
xx
Campi . . . . . . . . . . . . . . . . . . . . 35-6 Capitolo 36
Azioni . . . . . . . . . . . . . . . . . . .
Errori . . . . . . . . . . . . . . . . . . . .
. 35-6
. 35-6
Creazione di applicazioni
Record . . . . . . . . . . . . . . . . . . . . 35-6 Web server con IntraWeb 36-1
Produttori di pagina . . . . . . . . . . . . . . 35-7 Utilizzo dei componenti di IntraWeb . . . . . . 36-2
Creazione di applicazioni per Web server Introduzione a IntraWeb . . . . . . . . . . . . . 36-3
con WebSnap . . . . . . . . . . . . . . . . . . . 35-8 Creazione di una nuova applicazione
Selezione di un tipo server . . . . . . . . . . 35-9 IntraWeb . . . . . . . . . . . . . . . . . . . 36-4
Specifica dei componenti del modulo Modifica della scheda principale . . . . . . 36-4
applicazione . . . . . . . . . . . . . . . . . . 35-9 Scrittura di un gestore di evento
Selezione delle opzioni del modulo Web per il pulsante . . . . . . . . . . . . . . . . 36-5
application. . . . . . . . . . . . . . . . . . 35-11 Esecuzione dell’applicazione completata. . 36-6
Progettazione HTML evoluta. . . . . . . . . . 35-12 Uso di IntraWeb con Web Broker e WebSnap . 36-7
Trattamento dello script lato server nei file Per maggiori informazioni . . . . . . . . . . . . 36-8
HTML . . . . . . . . . . . . . . . . . . . . 35-13
Supporto per il login. . . . . . . . . . . . . . . 35-14 Capitolo 37
Aggiunta del supporto per il login . . . . . 35-14 Operazioni con documenti XML 37-1
Utilizzo del servizio per le sessioni. . . . . 35-15 Utilizzo del Document Object Model . . . . . . 37-2
Pagine di login . . . . . . . . . . . . . . . . 35-16 Operazioni con i componenti XML . . . . . . . 37-4
Impostazione delle pagine in modo che Utilizzo di TXMLDocument . . . . . . . . . 37-4
richiedano il login . . . . . . . . . . . . . 35-18 Operazioni con i nodi XML . . . . . . . . . 37-4
Diritti di accesso degli utenti . . . . . . . . 35-18 Operazioni con il valore di un nodo . . . 37-5
Visualizzazione dinamica di campi Operazioni con gli attributi di un nodo . 37-5
come caselle di testo o di modifica . . 35-19 Aggiunta e cancellazione di nodi figlio . 37-6
Occultamento dei campi Astrazione di documenti XML
e del loro contenuto. . . . . . . . . . . 35-20 con Data Binding wizard . . . . . . . . . . . . 37-6
Come evitare l’accesso alla pagina . . . 35-20 Utilizzo di XML Data Binding wizard . . . 37-8
Scripting lato server in WebSnap. . . . . . . . 35-20 Utilizzo del codice generato da XML Data
Active scripting . . . . . . . . . . . . . . . . 35-21 Binding wizard . . . . . . . . . . . . . . . 37-9
Motore di script. . . . . . . . . . . . . . . . 35-21
Blocchi di script. . . . . . . . . . . . . . . . 35-21 Capitolo 38
Creazione di script . . . . . . . . . . . . . . 35-22 Utilizzo dei Web Services 38-1
Modelli di wizard . . . . . . . . . . . . . 35-22 Le interfacce richiamabili . . . . . . . . . . . . 38-2
TAdapterPageProducer . . . . . . . . . 35-22 Utilizzo di tipi non scalari nelle interfacce
Modifica e visualizzazione di script . . . . 35-22 richiamabili. . . . . . . . . . . . . . . . . . 38-4
Inclusione di script in una pagina . . . . . 35-22 Registrazione di tipi non scalari . . . . . 38-5
Oggetti script . . . . . . . . . . . . . . . . . 35-23 Utilizzo di oggetti remotable . . . . . . . 38-6
Indirizzamento di richieste e risposte . . . . . 35-24 Rappresentazione degli allegati . . . . . 38-7
Componenti dispatcher . . . . . . . . . . . 35-24 Gestione della durata
Operazioni dell’adapter dispatcher . . . . 35-24 degli oggetti remotable . . . . . . . . . 38-7
Utilizzo di componenti adapter Esempio di oggetto Remotable . . . . . . 38-8
per generare contenuti . . . . . . . . . 35-24 Scrittura di server che supportano
Ricezione di richieste dell’adapter e i Web Services . . . . . . . . . . . . . . . . . . 38-9
generazione delle risposte . . . . . . . 35-26 Creazione di un server Web Service . . . . . 38-9
Richiesta di immagine . . . . . . . . . . 35-28 Utilizzo di SOAP application wizard . . . 38-10
Risposta di immagine . . . . . . . . . . 35-28 Aggiunta di nuovi Web Services. . . . . . 38-12
Indirizzamento degli elementi di azione . 35-29 Editing del codice generato . . . . . . . 38-12
Operazione del dispatcher di pagine. . . . 35-30 Utilizzo di una classe di base differente 38-12
Utilizzo di Web Services Importer . . . . . 38-14
xxi
Esame dei Business services. . . . . . . . . 38-15 Connessione con i client. . . . . . . . . . 39-8
Presentazione di UDDI. . . . . . . . . . 38-15 Chiusura delle connessioni server . . . . 39-8
Utilizzo del browser UDDI . . . . . . . 38-16 Risposta agli eventi socket . . . . . . . . . . . . 39-8
Definizione e utilizzo degli header SOAP . 38-16 Eventi di errore . . . . . . . . . . . . . . . . 39-8
Definizione delle classi header . . . . . 38-16 Eventi del client . . . . . . . . . . . . . . . . 39-9
Invio e ricezione degli header . . . . . . 38-17 Eventi del server. . . . . . . . . . . . . . . . 39-9
Comunicazione ad altre applicazioni Eventi durante l’ascolto . . . . . . . . . . 39-9
della struttura degli header . . . . . . 38-18 Eventi con connessioni client . . . . . . . 39-9
Creazione di classi di eccezione custom Lettura e scrittura sulle connessioni socket . 39-10
per Web Services . . . . . . . . . . . . . . 38-19 Connessioni non bloccanti . . . . . . . . . 39-10
Generazione di documenti WSDL per Eventi di lettura e scrittura . . . . . . . 39-10
un’applicazione Web Service . . . . . . . 38-19 Connessioni bloccanti. . . . . . . . . . . . 39-10
Scrittura di client per Web Services . . . . . . 38-20
Importazione di documenti WSDL . . . . . 38-20 Parte IV
Chiamata a interfacce richiamabili . . . . . 38-21 Sviluppo di applicazioni COM
Ottenimento di un’interfaccia
richiamabile dalla funzione generata . 38-21 Capitolo 40
Utilizzo di un oggetto connesso remoto 38-22
Elaborazione degli header Panoramica sulle tecnologie COM 40-1
nelle applicazioni client . . . . . . . . . . 38-23 COM come specifica e implementazione 40-2
Estensioni COM . . . . . . . . . . . . . . 40-2
Capitolo 39 Parti di un’applicazione COM. . . . . . . . . . 40-3
Operazioni con i socket 39-1 Interfacce COM . . . . . . . . . . . . . . . . 40-3
L’interfaccia COM fondamentale,
Implementazione dei servizi . . . . . . . . . . . 39-1
IUnknown . . . . . . . . . . . . . . . . 40-4
I protocolli di servizio . . . . . . . . . . . . . 39-2
Puntatori di interfaccia COM. . . . . . . 40-5
Comunicare con le applicazioni . . . . . . 39-2
Server COM . . . . . . . . . . . . . . . . . . 40-5
Servizi e porte. . . . . . . . . . . . . . . . . . 39-2
CoClass e class factory . . . . . . . . . . 40-6
Tipi di connessioni socket . . . . . . . . . . . . . 39-2
Server in-process, out-of-process
Connessioni client . . . . . . . . . . . . . . . 39-3
e remoti . . . . . . . . . . . . . . . . . . 40-6
Connessioni di ascolto . . . . . . . . . . . . . 39-3
Il meccanismo di smistamento . . . . . . 40-8
Connessioni server . . . . . . . . . . . . . . . 39-3
Aggregazione. . . . . . . . . . . . . . . . 40-9
Descrizione dei socket . . . . . . . . . . . . . . . 39-3
Client COM . . . . . . . . . . . . . . . . . 40-10
Descrizione dell’host . . . . . . . . . . . . . . 39-4
Estensioni COM . . . . . . . . . . . . . . . . . 40-10
Scelta tra un nome di host
Server Automation . . . . . . . . . . . . . 40-12
e un indirizzo IP. . . . . . . . . . . . . . 39-5
Active Server Pages . . . . . . . . . . . . . 40-13
Uso delle porte . . . . . . . . . . . . . . . . . 39-5
Controlli ActiveX . . . . . . . . . . . . . . 40-13
Utilizzo dei componenti socket. . . . . . . . . . 39-5
Active Document . . . . . . . . . . . . . . 40-14
Ottenimento di informazioni
Oggetti transazionali . . . . . . . . . . . . 40-14
sulla connessione . . . . . . . . . . . . . . . 39-6
Librerie di tipi . . . . . . . . . . . . . . . . 40-15
Utilizzo di socket client . . . . . . . . . . . . 39-6
Contenuto delle librerie di tipi . . . . . 40-16
Specifica del server desiderato . . . . . . 39-6
Creazione di librerie di tipi . . . . . . . 40-16
Formazione della connessione . . . . . . 39-7
Quando usare le librerie di tipi. . . . . 40-17
Ottenimento di informazioni sulla
Accesso alle librerie di tipi . . . . . . . 40-17
connessione . . . . . . . . . . . . . . . . 39-7
Vantaggi dell’uso delle librerie di tipi . 40-18
Chiusura della connessione . . . . . . . . 39-7
Uso degli strumenti della libreria di tipi 40-18
Uso dei socket server. . . . . . . . . . . . . . 39-7
Implementazione degli oggetti COM
Specifica della porta . . . . . . . . . . . . 39-7
con i wizard . . . . . . . . . . . . . . . . . . 40-19
Ascolto delle richieste provenienti
Codice generato dai wizard . . . . . . . . 40-22
da client . . . . . . . . . . . . . . . . . . 39-7
xxii
Capitolo 41 Uso della finestra di dialogo
Operazioni con le librerie di tipi 41-1 Import Type Library. . . . . . . . . . . . . 42-3
Uso della finestra di dialogo
Il Type Library editor . . . . . . . . . . . . . . . 41-2
Import ActiveX . . . . . . . . . . . . . . . 42-4
Elementi del Type Library editor . . . . . . . 41-3
Codice generato durante l’importazione delle
Barra strumenti . . . . . . . . . . . . . . . 41-4
informazioni di una libreria di tipi . . . . 42-5
Pannello Object list . . . . . . . . . . . . . 41-5
Controllo di un oggetto importato . . . . . . . 42-6
Barra di stato . . . . . . . . . . . . . . . . 41-6
Uso di wrapper di componenti . . . . . . . 42-6
Pagine di informazioni di tipo. . . . . . . 41-6
Wrapper ActiveX. . . . . . . . . . . . . . 42-7
Elementi del Type Library editor . . . . . . . 41-9
Wrapper di oggetti Automation . . . . . 42-7
Interfacce. . . . . . . . . . . . . . . . . . . 41-9
Uso di controlli ActiveX associati ai dati . . 42-8
Dispinterface . . . . . . . . . . . . . . . 41-10
Esercitazione: stampa di un documento
CoClass . . . . . . . . . . . . . . . . . . 41-10
con Microsoft Word . . . . . . . . . . . . 42-10
Definizioni di tipo . . . . . . . . . . . . 41-11
Preparazione di Delphi
Moduli . . . . . . . . . . . . . . . . . . . 41-11
per l’esercitazione . . . . . . . . . . . 42-10
Uso del Type Library editor . . . . . . . . . 41-12
Importazione della libreria
Tipi consentiti . . . . . . . . . . . . . . . 41-12
di tipi di Word . . . . . . . . . . . . . .42-11
Uso della sintassi Delphi o IDL . . . . . 41-14
Uso di un oggetto interfaccia VTable o
Creazione di una nuova libreria di tipi . 41-20
dispatch per il controllo
Apertura di un libreria di tipi esistente 41-20
di Microsoft Word . . . . . . . . . . . .42-11
Aggiunta di un’interfaccia
Ripristino dello stato originario . . . . 42-13
alla libreria di tipi . . . . . . . . . . . . 41-21
Scrittura del codice del client in base alle
Modifica di un'interfaccia
definizioni
con il Type Library editor . . . . . . . 41-22
della libreria di tipi . . . . . . . . . . . . 42-13
Aggiunta di proprietà e metodi ad una
Connessione a un server . . . . . . . . 42-13
interface o dispinterface . . . . . . . . 41-22
Controllo di un server Automation
Aggiunta di una CoClass
usando un’interfaccia duale . . . . . 42-14
alla libreria di tipi . . . . . . . . . . . . 41-24
Controllo di un server Automation
Aggiunta di un'interfaccia
usando un’interfaccia dispatch . . . . 42-14
a una CoClass . . . . . . . . . . . . . . 41-24
Gestione degli eventi in un controller
Aggiunta di una enumeration
Automation . . . . . . . . . . . . . . . 42-15
alla libreria di tipi . . . . . . . . . . . . 41-25
Creazione di client per server
Aggiunta di un alias alla libreria di tipi 41-25
che non hanno una libreria di tipi . . . . . . 42-17
Aggiunta di un record o di una union
Utilizzo degli assembly .NET con Delphi . . 42-18
alla libreria di tipi . . . . . . . . . . . . 41-25
Requisiti per l’interoperabilità COM . . . 42-18
Aggiunta di un modulo
Componenti .NET e librerie di tipi . . . . 42-19
alla libreria di tipi . . . . . . . . . . . . 41-26
Accesso ai componenti .NET
Salvataggio e registrazione delle
definiti dall’utente . . . . . . . . . . . . . 42-21
informazioni della libreria di tipi . . . 41-26
Finestra di dialogo Apply Updates . . . 41-27
Salvataggio di una libreria di tipi . . . . 41-27
Capitolo 43
Aggiornamento della libreria di tipi . . 41-28 Creazione di Active Server Page 43-1
Registrazione della libreria di tipi. . . . 41-28 Creazione di Active Server Object . . . . . . . 43-2
Esportazione di un file IDL . . . . . . . 41-28 Utilizzo degli intrinsics di ASP . . . . . . . 43-3
Distribuzione di librerie di tipi . . . . . . . . . 41-29 Application . . . . . . . . . . . . . . . . . 43-4
Request . . . . . . . . . . . . . . . . . . . 43-4
Capitolo 42 Response . . . . . . . . . . . . . . . . . . 43-5
Creazione di client COM 42-1 Session . . . . . . . . . . . .
Server . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
43-6
43-7
Importazione di informazioni
della libreria di tipi. . . . . . . . . . . . . . . . 42-2
xxiii
Creazione di ASP per server Elementi di un controllo ActiveX . . . . . . 45-2
in-process o out-of-process . . . . . . . . . 43-7 Il controllo VCL . . . . . . . . . . . . . . 45-3
Registrazione di Active Server Object . . . . . . 43-8 Wrapper ActiveX. . . . . . . . . . . . . . 45-3
Registrazione di un server in-process . . . . 43-8 La libreria di tipi . . . . . . . . . . . . . . 45-3
Registrazione di un server out-of-process . . 43-8 Pagina di proprietà . . . . . . . . . . . . 45-3
Collaudo e debug dell’applicazione Progettazione di un controllo ActiveX . . . . . 45-4
Active Server Page . . . . . . . . . . . . . . . . 43-9 Generazione di un controllo ActiveX da un
controllo VCL . . . . . . . . . . . . . . . . . . 45-4
Capitolo 44 Generazione di un controllo ActiveX
Creazione di semplici server COM 44-1 basato su una scheda VCL . . . . . . . . . . . 45-6
Panoramica sulla creazione Concessione in licenza di controlli ActiveX . . 45-7
di un oggetto COM . . . . . . . . . . . . . . . 44-1 Personalizzazione dell’interfaccia
Progettazione di un oggetto COM . . . . . . . . 44-2 del controllo ActiveX . . . . . . . . . . . . . . 45-8
Utilizzo di COM object wizard . . . . . . . . . . 44-2 Aggiunta di ulteriori proprietà, metodi ed
Uso di Automation object wizard . . . . . . . . 44-4 eventi . . . . . . . . . . . . . . . . . . . . . 45-9
Tipi di istanziazione di oggetti COM. . . . . 44-5 Aggiunta di proprietà e metodi . . . . . 45-9
Scelta di una modello di threading . . . . . . 44-6 Aggiunta di eventi . . . . . . . . . . . . 45-10
Scrittura di un oggetto che supporta il Attivazione dell’associazione di dati
modello free threading . . . . . . . . . . 44-7 semplici con la libreria di tipi . . . . . . .45-11
Scrittura di un oggetto che supporta il Creazione di una pagina di proprietà per un
modello apartment threading . . . . . . 44-8 controllo ActiveX . . . . . . . . . . . . . . . 45-12
Scrittura di un oggetto che supporta il Creazione di una nuova pagina
modello di threading neutral . . . . . . 44-9 di proprietà. . . . . . . . . . . . . . . . . 45-13
Definizione dell’interfaccia di un oggetto COM44-9 Aggiunta di controlli ad una pagina
Aggiunta di una proprietà all’interfaccia di proprietà. . . . . . . . . . . . . . . . . 45-13
dell’oggetto . . . . . . . . . . . . . . . . . . 44-9 Associazione dei controlli di una pagina di
Aggiunta di un metodo all’interfaccia proprietà alle proprietà del
dell’oggetto . . . . . . . . . . . . . . . . . 44-10 controllo ActiveX . . . . . . . . . . . . . 45-14
Esposizione di eventi ai client. . . . . . . . 44-11 Aggiornamento della pagina
Gestione degli eventi nell’oggetto di proprietà . . . . . . . . . . . . . . . 45-14
Automation . . . . . . . . . . . . . . . 44-12 Aggiornamento dell’oggetto . . . . . . 45-14
Interfacce di Automation . . . . . . . . . . . . 44-13 Collegamento di una pagina di proprietà
Interfacce duali . . . . . . . . . . . . . . . . 44-13 ad un controllo ActiveX. . . . . . . . . . 45-15
Interfacce di dispatch . . . . . . . . . . . . 44-14 Registrazione di un controllo ActiveX . . . . 45-15
Interfacce custom . . . . . . . . . . . . . . . 44-15 Collaudo di un controllo ActiveX . . . . . . . 45-16
Marshaling dei dati . . . . . . . . . . . . . . . 44-15 Distribuzione di un controllo ActiveX su Web 45-16
Tipi compatibili con Automation . . . . . . 44-16 Impostazione delle opzioni. . . . . . . . . 45-17
Restrizioni di tipo per il marshaling
automatico. . . . . . . . . . . . . . . . . . 44-16 Capitolo 46
Marshaling personalizzato . . . . . . . . . 44-17 Creazione di oggetti MTS o COM+ 46-1
Registrazione di un oggetto COM . . . . . . . 44-17 Gli oggetti transazionali . . . . . . . . . . . . . 46-2
Registrazione di un server in-process . . . 44-17 Requisiti di un oggetto transazionale . . . . 46-3
Registrazione di un server out-of-process . 44-17 Gestione delle risorse . . . . . . . . . . . . . . 46-3
Verifica e debug dell’applicazione . . . . . . . 44-18 Accesso al contesto dell’oggetto . . . . . . . 46-4
Attivazione just-in-time. . . . . . . . . . . . 46-4
Capitolo 45 Condivisione delle risorse . . . . . . . . . . 46-5
Creazione di un controllo ActiveX 45-1 Distributori di risorse di database . . . . 46-6
Panoramica sulla creazione Shared property manager. . . . . . . . . 46-6
di controlli ActiveX . . . . . . . . . . . . . . . 45-2 Rilascio delle risorse . . . . . . . . . . . . 46-9
xxiv
Condivisione degli oggetti . . . . . . . . . . 46-9 Scelta di un modello di threading
Supporto delle transazioni MTS e COM+ . . . 46-10 per un oggetto transazionale . . . . . . . 46-19
Attributi di transazione . . . . . . . . . . . 46-11 Attività . . . . . . . . . . . . . . . . . . 46-20
Impostazione dell’attributo Generazione di eventi in ambiente COM+ . . 46-21
di transazione . . . . . . . . . . . . . . 46-12 Uso di Event Object wizard . . . . . . . . 46-23
Oggetti con e senza stato . . . . . . . . . . 46-12 Uso di COM+ Event Subscription
Come influenzare la modalità object wizard . . . . . . . . . . . . . . . . 46-24
di completamento delle transazioni . . . 46-13 Attivazione di eventi utilizzando
Inizio di transazioni . . . . . . . . . . . . . 46-14 un oggetto evento di COM+ . . . . . . . 46-25
Impostazione di un oggetto Passaggio di riferimenti a oggetti . . . . . . . 46-26
transazionale sul lato client . . . . . . 46-14 Uso del metodo SafeRef . . . . . . . . . 46-26
Impostazione di un oggetto Callback. . . . . . . . . . . . . . . . . . 46-27
transazionale sul lato server . . . . . . 46-15 Debug e collaudo di oggetti transazionali . . 46-27
Durata della transazione. . . . . . . . . . . 46-16 Installazione di oggetti transazionali . . . . . 46-28
Sicurezza basata sul ruolo. . . . . . . . . . . . 46-16 Amministrazione di oggetti transazionali . . 46-29
Panoramica sulla creazione
di oggetti transazionali . . . . . . . . . . . . 46-17 Indice I-1
Uso di Transactional Object wizard . . . . . . 46-18
xxv
Tabelle
1.1 Caratteri tipografici e simboli . . . . . . . 1-2 9.8 Impostazione dell’aspetto di pulsanti
3.1 Sottolibrerie di componenti. . . . . . . . . 3-1 strumento . . . . . . . . . . . . . . . . . . 9-51
3.2 Classi di base importanti . . . . . . . . . . 3-5 9.9 Impostazione dell’aspetto
5.1 Valori per i parametri Origin . . . . . . . . 5-4 di un pulsante cool . . . . . . . . . . . . . 9-53
5.2 Modalità Open . . . . . . . . . . . . . . . . 5-6 10.1 Proprietà dei controlli di testo. . . . . . . 10-3
5.3 Modalità Share . . . . . . . . . . . . . . . . 5-7 12.1 Tipi di oggetti grafici . . . . . . . . . . . . 12-3
5.4 Modalità shared disponibili 12.2 Proprietà e metodi comuni dell’oggetto
per ogni modalità open . . . . . . . . . . . 5-7 Canvas . . . . . . . . . . . . . . . . . . . . 12-4
5.5 Costanti di attributo e valori . . . . . . . . 5-9 12.3 Metodi comuni dell’oggetto Canvas . . . 12-4
5.6 Classi per la gestione di elenchi . . . . . . 5-14 12.4 CLX MIME: tipi e costanti . . . . . . . . 12-22
5.7 Routine per il confronto delle stringhe . . 5-24 12.5 Eventi del mouse . . . . . . . . . . . . . 12-25
5.8 Routine di conversione 12.6 Parametri degli eventi mouse . . . . . 12-25
maiuscole/minuscole . . . . . . . . . . . . 5-25 12.7 Tipi di dispositivi multimediali e le loro
5.9 Routine per la modifica di stringhe . . . . 5-25 funzioni . . . . . . . . . . . . . . . . . . 12-33
5.10 Routine per le sottostringhe . . . . . . . . 5-25 13.1 Priorità del thread . . . . . . . . . . . . . 13-3
5.11 Routine di confronto 13.2 Valori restituiti da Wait For . . . . . . . .13-11
per stringhe terminate con null . . . . . . 5-26 14.1 Classi di eccezione selezionate . . . . . 14-10
5.12 Routine di conversione 15.1 Tecniche di porting . . . . . . . . . . . . . 15-2
maiuscole/minuscole per stringhe 15.2 Funzioni modificate o differenti. . . . . . 15-7
terminate con null . . . . . . . . . . . . . . 5-27 15.3 Unit solo per WinCLX ed equivalenti
5.13 Routine per la modifica di stringhe . . . . 5-27 VisualCLX . . . . . . . . . . . . . . . . . . 15-9
5.14 Routine per le sottostringhe . . . . . . . . 5-27 15.4 Unit solo in VisualCLX . . . . . . . . . . 15-10
5.15 Routine per la copia di stringhe . . . . . . 5-27 15.5 Unit solo in WinCLX . . . . . . . . . . . 15-10
5.16 Direttive del compilatore per le stringhe . 5-31 15.6 Differenze fra gli ambienti dei sistemi
6.1 Pagine della Component palette . . . . . 6-7 operativi Linux e Windows . . . . . . . 15-19
7.1 Proprietà del testo selezionato . . . . . . . 7-9 15.7 Directory Linux comuni . . . . . . . . . 15-22
7.2 Confronto dello stile owner-draw 15.8 Comparable data-access components . 15-25
fisso con quello variabile . . . . . . . . . . 7-14 15.9 Proprietà, metodi ed eventi per gli
8.1 Direttive al compilatore per le librerie. . . 8-10 aggiornamenti in cache . . . . . . . . . 15-29
8.2 Pagine di database 16.1 File di package compilati . . . . . . . . . 16-2
sulla Component palette . . . . . . . . . . 8-11 16.2 Direttive al compilatore specifiche per il
8.3 Applicazioni Web server . . . . . . . . . . 8-13 packaging . . . . . . . . . . . . . . . . . .16-11
8.4 Opzioni del menu contestuale 16.3 Opzioni del compilatore da riga comandi
dei moduli dati. . . . . . . . . . . . . . . . 8-17 specifiche per i package . . . . . . . . . 16-13
8.5 Metodi Help in TApplication. . . . . . . . 8-31 17.1 Metodi VCL che supportano BiDi . . . . 17-6
9.1 Terminologia per la configurazione 17.2 Lunghezza stimata delle stringhe. . . . . 17-7
delle azioni . . . . . . . . . . . . . . . . . . 9-18 18.1 File di applicazione . . . . . . . . . . . . . 18-3
9.2 Valori predefiniti della proprietà 18.2 Moduli di fusione e rispettive
PrioritySchedule del gestore di azioni. . . 9-26 dipendenze . . . . . . . . . . . . . . . . . 18-4
9.3 Classi di azioni . . . . . . . . . . . . . . . . 9-31 18.3 Distribuzione di dbExpress
9.4 Metodi ridefiniti da classi base di azioni come eseguibile indipendente. . . . . . . 18-7
specifiche . . . . . . . . . . . . . . . . . . . 9-32 18.4 Distribuzione dbExpress
9.5 Esempi di caption e loro nomi derivati . . 9-36 con DLL di driver. . . . . . . . . . . . . . 18-8
9.6 Comandi del menu contestuale Menu 20.1 Controlli dati . . . . . . . . . . . . . . . . 20-2
Designer . . . . . . . . . . . . . . . . . . . 9-42 20.2 Proprietà delle colonne. . . . . . . . . . 20-22
9.7 Impostazione dell’aspetto di pulsanti 20.3 Proprietà espanse di Title di TColumn . 20-23
scelta rapid a . . . . . . . . . . . . . . . . . 9-49
xxvi
20.4 Proprietà che influiscono sul modo in cui i 27.4 Opzioni di esecuzione dei dataset ADO 27-12
campi compositi vengono visualizzati . 20-26 27.5 Confronto tra gli aggiornamenti
20.5 Proprietà Options espanse di TDBGrid . 20-27 in cache di ADO e gli aggiornamenti
20.6 Eventi del controllo Grid . . . . . . . . . 20-29 nel dataset client . . . . . . . . . . . . . 27-13
20.7 Alcune proprietà del controllo griglia per 28.1 Colonne nelle tabelle di metadati
database. . . . . . . . . . . . . . . . . . . 20-31 che elencano tabelle . . . . . . . . . . . 28-15
20.8 Pulanti di TDBNavigator . . . . . . . . . 20-32 28.2 Colonne nelle tabelle di metadati
21.1 Documentazione Rave Reports . . . . . . 21-6 che elencano procedure registrate . . . 28-15
23.1 Componenti database connection . . . . . 23-1 28.3 Colonne nelle tabelle di metadati
24.1 Valori della proprietà State di un dataset . 24-3 che elencano campi . . . . . . . . . . . . 28-16
24.2 Metodi di spostamento dei dataset . . . . 24-5 28.4 Colonne nelle tabelle di metadati
24.3 Proprietà per gli spostamenti nei dataset . 24-6 che elencano indici . . . . . . . . . . . . 28-17
24.4 Operatori logici e di confronto 28.5 Colonne nelle tabelle di metadati
che possono apparire in un filtro. . . . . 24-15 che elencano parametri. . . . . . . . . . 28-17
24.5 Valori di FilterOptions . . . . . . . . . . 24-16 29.1 Supporto per i filtri nei dataset client. . . 29-3
24.6 Metodi di spostamento 29.2 Operatori di riepilogo per le
nei dataset filtrati . . . . . . . . . . . . . 24-17 aggregazioni di manutenzione . . . . . 29-12
24.7 Metodi dei dataset per inserire, 29.3 Dataset client specializzati per gli
aggiornare e cancellare dati. . . . . . . . 24-18 aggiornamenti in cache . . . . . . . . . 29-19
24.8 Metodi che funzionano con interi record 24-22 30.1 Componenti usati nelle
24.9 Metodi di ricerca basati su indice . . . . 24-29 applicazioni multi-tier . . . . . . . . . . . 30-3
25.1 Proprietà di TFloatField che 30.2 Componenti connection . . . . . . . . . . 30-5
influenzano la visualizzazione dei dati . . 25-1 30.3 Librerie javascript. . . . . . . . . . . . . 30-36
25.2 Tipi speciali di campo persistenti . . . . . 25-6 31.1 Membri dell’interfaccia AppServer . . . . 31-3
25.3 Proprietà dei componenti campo . . . . 25-12 31.2 Opzione del provider. . . . . . . . . . . . 31-5
25.4 Routine di formattazione 31.3 Valori di UpdateStatus . . . . . . . . . . . 31-9
dei componenti campo . . . . . . . . . . 25-16 31.4 Valore UpdateMode . . . . . . . . . . . 31-10
25.5 Eventi dei componenti campo . . . . . . 25-17 31.5 Valori di ProviderFlags. . . . . . . . . . .31-11
25.6 Metodi dei componenti 33.1 Web Broker e WebSnap. . . . . . . . . . . 33-2
campo selezionati . . . . . . . . . . . . . 25-18 34.1 Valori di MethodType . . . . . . . . . . . 34-7
25.7 Risultati di conversioni speciali . . . . . 25-20 35.1 Tipi di modulo Web application. . . . . . 35-3
25.8 Tipi di componenti campo oggetto . . . 25-24 35.2 Tipi di applicazione per Web server . . . 35-9
25.9 Proprietà comuni dei discendenti 35.3 Componenti Web application . . . . . . 35-10
dei campi oggetto . . . . . . . . . . . . . 25-24 35.4 Oggetti script . . . . . . . . . . . . . . . 35-23
26.1 Tipi di tabella riconosciuti da BDE in base 35.5 Informazioni di richiesta presenti nelle
all’estensione del file . . . . . . . . . . . . 26-5 richieste di azioni . . . . . . . . . . . . . 35-26
26.2 Valori di TableType . . . . . . . . . . . . . 26-6 36.1 Componenti VCL/CLX e IntraWeb. . . . 36-2
26.3 Modalità di importazione di BatchMove 26-8 38.1 Classi Remotable . . . . . . . . . . . . . . 38-6
26.4 Metodi informativi correlati al database 40.1 Requisiti degli oggetti COM. . . . . . . 40-12
dei componenti session . . . . . . . . . . 26-28 40.2 Wizard di Delphi per
26.5 Proprietà e metodi di TSessionList . . . 26-31 l’implementazione di oggetti COM,
26.6 Proprietà , metodi ed eventi degli Automation e ActiveX . . . . . . . . . . 40-20
aggiornamenti in cache . . . . . . . . . . 26-34 40.3 Classi DAX di base per le classi di
26.7 Valori di UpdateKind . . . . . . . . . . . 26-41 implementazione generate. . . . . . . . 40-22
26.8 Modalità di spostamento batch . . . . . 26-52 41.1 File del Type Library editor . . . . . . . . 41-3
26.9 Interfaccia del Data Dictionary. . . . . . 26-56 41.2 Elementi del Type Library editor . . . . . 41-3
27.1 Componenti ADO . . . . . . . . . . . . . . 27-2 41.3 Pagine del Type Library editor . . . . . . 41-6
27.2 Nomi dei parametri per la connessione . . 27-4 41.4 Tipi consentiti . . . . . . . . . . . . . . . 41-13
27.3 Modalità di connessione ADO . . . . . . 27-6 41.5 Sintassi degli attributi . . . . . . . . . . 41-15
xxvii
43.1 IMembri dell’interfaccia 46.1 Metodi IObjectContext per il supporto
IApplicationObject . . . . . . . . . . . . . 43-4 delle transazioni . . . . . . . . . . . . . 46-13
43.2 Membri dell’interfaccia IRequest . . . . . 43-5 46.2 Modelli di threading per oggetti
43.3 Membri dell’interfaccia IResponse. . . . . 43-5 transazionali. . . . . . . . . . . . . . . . 46-19
43.4 Membri dell’interfaccia ISessionObject . . 43-6 46.3 Opzioni di sincronizzazione
43.5 Membri dell’interfaccia IServer . . . . . . 43-7 della chiamata. . . . . . . . . . . . . . . 46-21
46.4 Codici di ritorno dei publisher di evento 46-25
xxviii
Figure
3.1 Diagramma semplificato della gerarchia 3-5 22.2 Un crosstab mono-dimensionale . . . . . 22-3
4.1 Una semplice scheda . . . . . . . . . . . . 4-3 22.3 Crosstab tridimensionale . . . . . . . . . 22-3
9.1 Un frame con controlli data-aware e un 22.4 Grafici decisionali collegati a sorgenti
componente datasource . . . . . . . . . . . 9-16 decisionali diverse . . . . . . . . . . . . 22-15
9.3 Terminologia dei menu . . . . . . . . . . . 9-34 26.1 Componenti in un’applicazione BDE. . . 26-2
9.4 Componenti MainMenu e PopupMenu . . 9-34 30.1 Applicazione database multi-tier
9.6 Aggiunta di voci di menu a un menu basata su web . . . . . . . . . . . . . . . 30-32
principale . . . . . . . . . . . . . . . . . . . 9-37 33.1 Parti di uno Uniform Resource Locator . 33-4
9.7 Strutture di menu annidate . . . . . . . . . 9-39 34.1 Struttura di un’applicazione server. . . . 34-4
10.2 Una barra di avanzamento . . . . . . . . 10-18 35.2 Finestra di dialogo
11.1 Parte della barra strumenti Web App Component . . . . . . . . . . 35-10
ModelMaker . . . . . . . . . . . . . . . . . 11-3 35.3 Finestra di dialogo
11.2 ModelMaker con un modello di esempio . 11-4 Web App Components con le opzioni
11.3 La vista Classes . . . . . . . . . . . . . . . 11-5 per supporto del login selezionate . . . 35-15
11.4 La vista Units. . . . . . . . . . . . . . . . . 11-5 35.4 Un esempio di pagina di login visto
11.5 La vista Diagrams . . . . . . . . . . . . . . 11-6 nell’editor della pagina web . . . . . . . 35-17
11.6 La vista Members . . . . . . . . . . . . . . 11-7 35.5 Generazione del flusso dei contenuti . . 35-26
11.7 La vista Implementation Editor . . . . . . 11-8 35.6 Action request e response . . . . . . . . 35-28
11.8 Unit Code Editor. . . . . . . . . . . . . . . 11-8 35.7 Risposta di immagine a una richiesta . 35-29
11.9 Diagram Editor . . . . . . . . . . . . . . . 11-9 35.8 Indirizzamento di una pagina. . . . . . 35-30
12.1 Finestra di dialogo 36.2 La scheda principale dell’applicazione
Bitmap Dimension dalla unit BMPDlg... 12-21 IntraWeb . . . . . . . . . . . . . . . . . . . 36-5
19.1 Architettura generale di un database . . . 19-6 40.1 Un’interfaccia COM . . . . . . . . . . . . 40-3
19.2 Connessione diretta a un server 40.2 Vtable dell’interfaccia . . . . . . . . . . . 40-5
di database . . . . . . . . . . . . . . . . . . 19-8 40.3 Server in-processr. . . . . . . . . . . . . . 40-7
19.3 Un’applicazione database basata su file. 19-10 40.4 Server out-of-process e remoto . . . . . . 40-8
19.4 Architettura che combina un dataset 40.5 Tecnologie basate su COM. . . . . . . . .40-11
client e un altro dataset . . . . . . . . . . 19-13 40.6 Interfaccia di un semplice oggetto COM 40-19
19.5 Architettura multi-tier di un database. . 19-14 40.7 Interfaccia di un oggetto Automation . 40-19
20.1 Controllo TDBGrid . . . . . . . . . . . . 20-17 40.8 Interfaccia di un oggetto ActiveX . . . . 40-20
20.2 Controllo TDBGrid con 40.9 Framework ActiveX di Delphi . . . . 40-22
ObjectView impostata a False . . . . . . 20-25 41.1 Il Type Library editor. . . . . . . . . . . . 41-4
20.3 Controllo TDBGrid con 41.2 Pannello Object list . . . . . . . . . . . . . 41-6
Expanded impostata a False . . . . . . . 20-26 44.1 Modelli di threading per gli oggetti COM 44-6
20.4 Controllo TDBGrid con 44.2 VTable di un’interfaccia duale. . . . . . 44-14
Expanded impostata a True. . . . . . . . 20-26 45.1 La pagina di proprietà Mask Edit in modalità
20.5 TDBCtrlGrid in progettazione . . . . . . 20-31 progetto . . . . . . . . . . . . . . . . . . 45-14
20.6 Pulsanti del controllo TDBNavigator . . 20-32 46.1 Il sistema a eventi di COM+ . . . . . . . 46-23
22.1 I componenti di supporto decisionale
in fase di progetto . . . . . . . . . . . . . . 22-2
xxix
xxx
Copyright © 11/29/00, Inprise Corporation. All rights reserved. INPRISE CONFIDENTIAL
November 29, 2000 2:20 pm (J:\source\Devguide\BOOK\Delphonly\1_intro.fm5)
Capitolo
1
Introduzione
Capitolo1
Il manuale Guida alla programmazione descrive gli argomenti connessi allo sviluppo
intermedio e avanzato, come la costruzione di applicazioni database client/server, la
creazione di applicazioni server Web per Internet e la scrittura di componenti
personalizzati. Essa consente di costruire applicazioni che soddisfano le specifiche
standard, quali SOAP,TCP/IP, MTS, COM e ActiveX. La maggior parte delle
funzioni avanzate che supportano lo sviluppo per Web, le tecnologie evolute XML e
lo sviluppo di database richiedono componenti o wizard che non sono disponibili in
tutte le edizioni di Delphi.
Il manuale Guida alla programmazione presuppone che si abbia familiarità con l’uso di
Delphi e che si abbia una sufficiente padronanza delle tecniche fondamentali di
programmazione in Delphi. Per un’introduzione alla programmazione in Delphi e
all’ambiente di sviluppo integrato (IDE), consultare il manuale Per iniziare o la Guida
in linea.
Introduzione 1-1
Copyright © 11/29/00, Inprise Corporation. All rights reserved. INPRISE CONFIDENTIAL
November 29, 2000 2:20 pm (J:\source\Devguide\BOOK\Delphonly\1_intro.fm5)
Introduzione 1-3
Copyright © 11/29/00, Inprise Corporation. All rights reserved. INPRISE CONFIDENTIAL
November 29, 2000 2:20 pm (J:\source\Devguide\BOOK\Delphonly\1_intro.fm5)
I
Programmazione con Delphi
Parte I
• Form Designer, una finestra vuota, detta anche scheda, in cui progettare
l’interfaccia utente (UI) dell’applicazione.
• Component palette per la visualizzazione di componenti visuali e non, che è
possibile utilizzare per progettare l’interfaccia utente.
• Object Inspector per esaminare e modificare le proprietà e gli eventi degli oggetti.
• Object TreeView per visualizzare e modificare le relazioni logiche dei componenti.
• Code editor per la stesura e la modifca della logica sottostante di un programma.
• Project Manager per gestire i file che costituiscono uno o più progetti.
• Debugger integrato per ricercare e corregere gli errori nel codice.
• Molti altri strumenti, come gli editor di proprietà per modificare i valori delle
properietà di un oggetto.
• Strumenti per la riga comandi che comprendono compilatori, linker e altri
programmi di utilità.
• Complete librerie di classi con moltissimi oggetti riutilizzabili. La maggior parte
degli oggetti forniti nella libreria di classi sono accessibili nell’IDE dalla
Component palette. Per convenzione, i nomi degli oggetti nella libreria di classi
iniziano con una T, come TStatusBar. I nomi degli oggetti che cominciano con la
lettera Q sono basati sulla libreria Qt e vengono utilizzati per applicazioni
multipiattaforma.
Alcuni strumenti potrebbero non essere inclusi in tutte le edizioni del prodotto.
Nel manuale Per iniziare, incluso nel prodotto, viene presentata una panoramica più
completa sull’ambiente di sviluppo. Inoltre, il sistema di Guida in linea contiene la
descrizione completa dei menu, delle finestre di dialogo e delle finestre
dell’applicazione.
Progettazione di applicazioni
Delphi può essere usato per progettare qualsiasi tipo di applicazione a 32 bit—dai
programmi di utilità per scopi generici ai sofisticati programmi per l’accesso ai dati o
ad applicazioni distribuite.
Quando si progetta in modo visuale l’interfaccia utente per l’applicazione, il Form
Designer genera il codice Delphi sottostante. Quando si selezionano e si modificano
le proprietà di componenti e schede, i risultati di queste modifiche vengono
visualizzati automaticamente nel codice sorgente e viceversa. È possibile modificare i
file sorgente direttamente con qualsiasi editor di testo, compreso il Code editor
integrato. Le modifiche apportate vengono immediatamente riportate nell’ambiente
visuale.
È possibile creare dei propri componenti utilizzando il linguaggio Delphi. La
maggior parte dei componenti forniti è scritta in Delphi. È possibile aggiungere alla
Component palette i propri componenti oppure personalizzarla in base alle proprie
preferenze inserendo, ad esempio, nuove pagine.
Creazione di progetti
Tutte le attività relative allo sviluppo di applicazioni ruotano intorno ai progetti.
Quando si crea un’applicazione in Delphi si crea un progetto. Un progetto è una
raccolta di file che compongono un’applicazione. Alcuni di questi file sono creati in
fase di progettazione. Gli altri vengono generati automaticamente quando si compila
il codice sorgente del progetto.
È possibile visualizzare il contenuto di un progetto in uno strumento per la gestione
dei progetti di nome Project Manager. Il Project Manager elenca, in una vista
gerarchica, i nomi delle unit, le schede contenute nella unit (nel caso ve ne siano) e
mostra i percorsi dei file nel progetto. Benché sia possibile modificare direttamente la
maggior parte di questi file, spesso è più semplice e affidabile utilizzare gli strumenti
visuali.
In cima alla gerarchia del progetto, vi è un file di gruppo. È possibile combinare più
progetti in un gruppo di progetti.Ciò permette di aprire nel Project Manager più di
un progetto per volta. I gruppi di progetti permettono organizzare e operare su
progetti correlati, come le applicazioni che funzione in combinazione fra di loro o che
fanno parte di un’applicazione multi-tier. Se si lavora su un solo progetto, per creare
un’applicazione non è necessario un file di gruppo di progetti.
I file di progetto, che descrivono i singoli progetti, i file e le opzioni associate, hanno
l’estensione .bpr. I file di progetto contengono indicazioni per la generazione di
un’applicazione o di un oggetto condiviso. Quando si aggiungono e rimuovono file
utilizzando il Project Manager, il file di progetto viene aggiornato. Le opzioni di
progetto vengono specificate utilizzando una finestra di dialogo, Project Options,
contenente varie pagine per i diversi aspetti del progetto come le schede,
l’applicazione o il compilatore. Queste opzioni di progetto vengono memorizzate nel
file di progetto assieme al progetto.
Le unit e le schede sono i componenti di base di un’applicazione. Un progetto può
condividere tutti i file form e unit esistenti, inclusi quelli che risiedono esternamente
all’albero delle directory di progetto. Questo include le procedure e le funzioni
custom che sono state scritte come routine indipendenti.
Se si aggiunge a un progetto un file condiviso, è bene rendersi conto che il file non
viene copiato nella directory del progetto corrente; rimane nella sua ubicazione
attuale. L’aggiunta al progetto corrente di un file condiviso registra il nome del file e
il percorso nella clausola uses del file di progetto. Delphi gestisce automaticamente
questa operazione non appena si aggiungono delle unit a un progetto.
Quando si compila un progetto, non è importate la posizione in cui risiedono i file
che compongono il progetto. Il compilatore tratta i file condivisi esattamente come
quelli creati dal progetto stesso.
Compilazione di applicazioni
Una volta terminata la progettazione sulla scheda dell’interfaccia dell’applicazione e
la scrittura di tutto il codice aggiuntivo, in modo che l’applicazione faccia ciò che ci si
era prefissi, è possibile compilare il progetto dall’IDE o dalla riga comandi.
Tutti i progetti hanno come destinazione un singolo file eseguibile distribuibile. È
possibile visualizzare o provare l’applicazione a diversi stadi dello sviluppo
compilandola, rigenerandola o mandandola in esecuzione:
• Quando si compila, vengono ricompilate solo le unit che sono state modificate
rispetto all’ultima compilazione.
Debug di applicazioni
È possibile trovare e correggere gli errori presenti nelle applicazioni, grazie al
debugger integrato. Il debugger integrato permette di controllare l’esecuzione del
programma, di tenere sotto controllo i valori delle variabili e gli elementi delle
strutture di dati, oltre che di modificare i valori dei dati durante la fase di debug.
Il debugger integrato può tracciare sia gli errori di esecuzione sia gli errori di logica.
Eseguendo il programma fino a determinati punti ed esaminando i valori delle
variabili, le funzioni nello stack delle chiamate e l’output del programma, è possibile
controllare il comportamento del programma e trovare le aree in cui il
comportamento non è quello progettato. Il debugger è descritto nella Guida in linea.
È anche possibile usare la gestione delle eccezioni per riconoscere, individuare e
trattare gli errori. Le eccezioni sono classi, identiche alle altre classi di Delphi, tranne
per il fatto che, per convenzione, il loro nome inizia con una E invece che con una T.
Distribuzione di applicazioni
Delphi include strumenti aggiuntivi che consentono la distribuzione delle
applicazioni. Ad esempio, InstallShield Express (non disponibile in tutte le edizioni)
aiuta a creare un package per l’installazione dell’applicazione, che include tutti i file
necessari per l’esecuzione di un’applicazione distribuita. È disponibile anche il
software TeamSource (non disponibile in tutte le edizioni) per tenere traccia degli
aggiornamenti apportati alle applicazioni.
Per distribuire un applicazione CLX su Linux è necessario Kylix.
La libreria di componenti
La libreria dei componenti è costituita da oggetti separati in diverse sotto libreria,
ognuna delle quali serve ad uno scopo differente. Queste sottolibrerie sono elencate
nella Tabella 3.1:
È possibile trovare referenze dettagliate su tutto ciò che riguarda oggetti VCL e CLX
nella Guida in linea durante la programmazione. Nel Code editor, posizionare il
cursore in qualunque parte di un oggetto e premere F1 per visualizzare l’argomento
nel Help. Gli oggetti, le proprietà, i metodi e gli eventi che si trovano in VCL sono
marcati “VCL Reference” e quelli che si trovano in CLX sono marcati “CLX
Reference.”
Proprietà
Le proprietà sono le caratteristiche di un oggetto che influiscono o sul comportamento
visibile o sulle operazioni dell’oggetto. Ad esempio, la proprietà Visible determina se
un oggetto può essere visualizzato nell’interfaccia dell’applicazione. Proprietà ben
progettate consentono di semplificare l’utilizzo del componente da parte di altri
programmatori e la manutenzione da parte di chi l’ha progettato.
Di seguito sono riportare alcune utili caratteristiche delle proprietà:
• A differenza dei metodi, che sono disponibili solo in esecuzione, è possibile vedere
e modificare alcune proprietà nell’IDE in fase di progettazione e ottenere un
immediato riscontro visivo dei cambiamenti apportati.
• È possibile accedere ad alcune proprietà tramite l’Object Inspector, che consente di
modificare visivamente i valori dell’oggetto. L’impostazione delle proprietà in
fase di progettazione è più semplice della scrittura del codice e rende il codice più
semplice da gestire.
• Poiché i dati sono incapsulati, risultano protetti e privati all’interno dell’oggetto.
• Le chiamate volte a ottenere e a impostare i valori delle proprietà possono essere
metodi, rendendo pertanto invisibili all’utente dell’oggetto particolari
elaborazioni che non lo sono. Ad esempio, i dati potrebbero risiedere in una
tabella, ma potrebbero apparire al programmatore come normali membri dati.
• È possibile implementare la logica che innesca eventi o modifica altri dati durante
l’accesso ad una proprietà. Ad esempio, la modifica del valore di una proprietà
potrebbe richiedere la modifica di un’altra. È possibile modificare i metodi creati
per la proprietà.
• Le proprietà possono essere virtuali.
• Una proprietà non è limitata a un singolo oggetto. La modifica di una proprietà di
un oggetto può ripercuotersi su numerosi oggetti. Ad esempio, l’impostazione
Metodi
Un metodo è una funzione che è memebro di una classe. I metodi definiscono il
comportamento di un oggetto. I metodi di classe possono accedere a tutte le
proprietà pubbliche, protette e private e ai campi della classe e sono comunemente
menzionati come funzioni membro. Consultare “Controllo dell’accesso” a pagina 2-4
del manuale Guida alla scrittura di componenti. Nonostante la maggior parte dei
metodi appartenga ad un’istanza di una classe, alcuni metodi, invece, appartengono
al tipo class. Questi sono chiamati metodi di classe.
Eventi
Un evento è un’azione o un accadimento rilevato da un programma. Molte
applicazioni moderne vengono definite event-driven, perché sono progettate per
rispondere agli eventi. In un programma, il programmatore non ha alcun modo di
prevedere la sequenza esatta di azioni che sarà eseguita dall’utente. Ad esempio,
l’utente potrà scegliere una voce di menu, fare clic su un pulsante o selezionare del
testo. Il programmatore potrà scrivere il codice per gestire gli eventi che ritiene
importanti, invece di scrivere del codice che sarà eseguito sempre secondo lo stesso
ordine limitato.
Indipendentemente da come è stato scatenato l’evento, gli oggetti della VCL cercano
di individuare se è stato predisposto un qualsiasi codice per gestire quel determinato
evento. Nel caso sia stato predisposto, quel codice viene eseguito; altrimenti, ha
luogo il comportamento predefinito di gestione dell’evento.
I tipi di eventi che possono verificarsi possono essere suddivisi in due categorie
principali:
• Eventi utente
• Eventi di sistema
• Eventi interni
Eventi utente
Gli eventi utente sono azioni che vengono iniziate dall’utente. Esempi di eventi
utente sono OnClick (l’utente ha fatto clic col mouse), OnKeyPress (l’utente ha
premuto un tasto sulla tastiera), e OnDblClick (l’utente ha fatto doppio clic su un
pulsante del mouse).
Eventi di sistema
Gli eventi di sistema sono eventi generati automaticamente dal sistema operativo. Ad
esempio, l’evento OnTimer (che il componente TTimer genera ogni volta che è
trascorso un intervallo temporale predefinito), l’evento OnPaint (un componente o
una window devono essere ridisegnati), e così via. Di solito, gli eventi di sistema non
vengono avviati direttamente da un’azione dell’utente.
Eventi interni
Gli eventi interni sono eventi generati dagli oggetti dell’applicazione. Un esempio di
un evento interno è l’evento OnPost che viene generato da un dataset quando
l’applicazione ordina di registrare il record corrente.
[Objects]
[Objects] [Objects] TGraphicControl [Objects]
[Objects]
Ogni oggetto (class) eredita da TObject. Gli oggetti che possono essere visualizzati in
Form Designer ereditano da TPersistent o TComponent. I controlli, che appaiono
all’utente in fase di esecuzione, ereditano da TControl. Vi sono due tipi di controlli,
controlli grafici, che ereditano da TGraphicControl e controlli con finestra, che
ereditano da TWinControl o da TWidgetControl. Un controllo come TCheckBox eredita
tutte le funzionalità di TObject, TPersistent, TComponent, TControl, e TWinControl o
TWidgetControl e aggiunge le proprie capacità specifiche.
Nella figura vengono visualizzate diverse importanti classi base che sono descritte
nella tabella seguente:
Le prossime sezioni presentano una descrizione generale dei tipi di classi conytenuti
in ogni ramo. Per una panoramica completa della gerarchia degli oggetti della VCL e
della CLX, fare riferimento ai diagramma VCL Object Hierarchy e CLX Object
Hierarchy inclusi nel prodotto.
Il ramo TObject
Il ramo TObject include tutte le classi VCL e CLX che discendono da TObject ma non
da TPersistent. La maggior parte delle potenti capacità della libreria di componenti
deriva dai metodi introdotti da TObject. TObject incapsula il comportamento di base
comune a tutti le classi della libreria di componenti, introducendo metodi che
forniscono:
• La capacità di rispondere quando vengono create o distrutte le istanze di oggetti.
• Il tipo di classe e le informazioni sull’istanza di un oggetto, e le informazioni di
tipo in esecuzione (RTTI) relativamente alle proprietà rese pubbliche.
• Supporto per la gestione di messaggi (applicazioni VCL) oppure per la gestione
delle notifiche (applicazioni CLX).
TObject è l’antenato diretto di molte classi semplici. Le classi all’interno del ramo
TObject hanno un’importante caratteristica comune: sono transitorie. Ciò significa
che queste classi non hanno un metodo per salvare lo stato in cui sono prima di
essere distrutte, vale a dire che non sono persistenti.
Uno dei gruppi principali delle classi in questo ramo è la classe Exception. Questa
classe fornisce una vasta serie di classi di eccezioni predefinite per gestire
automaticamente errori di divisione per zero, errori di I/O su file, conversioni di tipo
non valide e molte altre condizioni di eccezione.
Un gruppo nel ramo TObject è rappresentato dalle classi che incapsulano strutture
dati, come:
• TBits, una classe che memorizza un “array” di valori booleani.
• TList, una classe di lista collegata.
Il ramo TPersistent
Il ramo TPersistent include tutte le classi VCL e CLX che discendono da TPersistent
ma non da TComponent. La persistenza determina che cosa viene salvato con un file
form o con un modulo dati e che cosa viene caricato nella scheda o nel modulo dati
quando li si ricupera dalla memoria.
Grazie alla loro persistenza, gli oggetti in questo ramo possono essere visualizzati in
fase di progettazione. Tuttavia, non possono esistere come oggetti indipendenti.
Invece, essi implementano le proprietà per i componenti. Le proprietà vengono
caricate e salvate con una scheda solo se hanno un possessore. Il possessore deve
essere qualche componente. TPersistent introduce il metodo GetOwner che permette
al Form Designer di determinare il possessore dell’oggetto.
Le classi in questo ramo sono anche i primi a includere una sezione published in cui è
possibile caricare e salvare automaticamente le proprietà. Il metodo DefineProperties
permette anche ad agni classe di indicare come caricare e salvare le proprietà.
Di seguito sono elencate alcune delle classi incluse nel ramo TPersistent della
gerarchia:
• Classi grafiche come TBrush, TFont, e TPen.
• Classi come TBitmap e TIcon, in grado di memorizzare e visualizzare immagini, e
TClipboard che contiene testo o grafici che sono stati copiati o tagliati da un
applicazione.
• Elenchi di stringhe come TStringList, che rappresenta un testo o un elenco di
stringhe che possono essere assegnate in fase di progettazione..
• Raccolte o elementi di raccolte che discendono da TCollection o da TCollectionItem.
Queste classi mantengono delle raccolte indicizzate di elementi specificatamente
definiti che appartengono ad un componente. Esempi sono THeaderSections e
THeaderSection o TListColumns e TListColumn
Il ramo TComponent
Il ramo TComponent contiene classi che scendono da TComponent ma non da TControl.
Gli oggetti in questo ramo sono componenti che è possibile manipolare sulle schede
in fase di progettazione, ma che non appaiono all’utente in fase di esecuzione. Essi
sono oggetti persistenti che possono fare quanto segue:
• Essere visualizzati sulla Component palette e modificati nella scheda.
• Possedere e gestire altri componenti.
• Caricare e salvare se stessi.
Diversi metodi introdotti da TComponent regolano il comportamento dei componenti
in fase di progettazione e quali informazioni vengono salvate con il componente. In
questo ramo viene introdotto il concetto di stream (il salvataggio e il caricamento di
file form, che memorizza le informazioni sui valori delle proprietà degli oggetti su
una scheda). Le proprietà sono persistenti se sono state rese pubbliche e le proprietà
rese pubbliche sono automaticamente soggette allo stream.
Il ramo TComponent introduce anche il concetto di possesso che è propagato in tutta
la libreria di componenti. Due proprietà supportano il possesso: Owner and
Components. Ogni componente ha una proprietà Owner che fa riferimento a un altro
componente come possessore. Un componente può possedere altri componenti. In
questo caso, tutti i componenti posseduti sono referenziati nella proprietà
Components del componente.
Il costruttore di ogni componente accetta un parametro che specifica il possessore del
nuovo componente. Se il possessore che viene passato esiste, il nuovo componente
viene aggiunto alla lista Components del possessore. Oltre all’utilizzo della lista
Components per referenziare i componenti posseduti, questa proprietà consente anche
la distruzione automatica dei componenti posseduti. Finché il componente ha un
possessore, sarà distrutto al momento della distruzione del possessore. Ad esempio,
poiché TForm è un discendente di TComponent, quando si distruggerà la scheda
saranno distrutti tutti i componenti posseduti dalla scheda e la memoria allocata sarà
liberata. (Si presuppone, ovviamente, che i componenti abbiano distruttori, progettati
appositamente, che li puliscano correttamente.
Se un tipo di proprietà è un TComponent o un discendente, il sistema di streaming
crea un’istanza di quel tipo al momento della sua lettura. Se un tipo di proprietà è
TPersistent ma non TComponent, il sistema di streaming utilizza l’istanza esistente
disponibile attraverso la proprietà e legge i valori delle proprietà di quell’istanza.
Alcune delle classi che si trovano nel ramo TComponent includono:
• TActionList, una classe che conserva un elenco di azioni, che forniscono
un’astrazione delle risposte che il programma può fornire all’input dell’utente.
• TMainMenu, una classe che fornisce alle schede una barra di menu e i relativi
menu a discesa.
• TOpenDialog, TSaveDialog, TFontDialog, TFindDialog, TColorDialog, e così via, sono
classi che visualizzano e raccolgono informazioni dalle finestre di dialogo
utilizzate più di frequente.
• TScreen, una classe che tiene traccia delle schede e dei moduli dati che vengono
creati da un’applicazione, della scheda attiva, del controllo attivo all’interno di
quella scheda, delle dimensioni e della risoluzione dello schermo, e dei cursori e
dei font disponibili e utilizzabili dall’applicazione.
Componenti che non hanno bisogno di un’interfaccia visuale possono essere derivati
direttamente da TComponent. Per creare uno strumento come un dispositivo TTimer, è
possibile derivarlo da TComponent. Questo tipo di componente risiede nella
Component palette, ma esegue funzioni interne a cui si accede mediante codice e non
viene visualizzato nell’interfaccia utente in fase di esecuzione.
Per i dettagli sull’impostazione delle proprietà, sulla chiamata ai metodi e sulle
operazioni con gli eventi dei componenti, consultare il Capitolo 6, “Operazioni con
componenti”,.
Il ramo TControl
Il ramo TControl è formato da componenti che discendono da TControl ma non da
TWinControl (TWidgetControl in applicazioni CLX). Le classi in questo ramo sono
controlli che sono oggetti visuali che l’utente può vedere e manipolare in esecuzione.
Tutti i controlli hanno proprietà, metodi ed eventi in comune che sono correlati
all’aspetto del controllo, come la posizione, il cursore associato alla finestra del
controllo, i metodi per colorare o spostare il controllo e gli eventi per rispondere alle
azioni del mouse. Tuttavia, i controlli in questo ramo non possono mai ricevere
l’input da tastiera.
Mentre TComponent definisce il comportamento di tutti i componenti, TControl
definisce il comportamento per tutti i controlli visuali. Ciò comprende le routine di
disegno, gli eventi standard e le relazioni contenuto-contenitore.
TControl introduce molte proprietà visuali che vengono ereditate da tutti i controlli.
Queste includono le proprietà Caption, Color, Font, e HelpContext o HelpKeyword.
Benché queste proprietà siano ereditate da TControl —esse vengono rese pubbliche, e
appaiono pertanto nell’Object Inspector— solo per quei controlli per cui sono
applicabili. Ad esempio, il componente TImage non pubblica la proprietà Color,
poiché il suo colore è determinato dall’immagine grafica visualizzata. TControl
introduce anche la proprietà Parent, che specifica un altro controllo che contiene
visualmente il controllo.
Le classi nel ramo TControl vengono chiamate spesso controlli grafici, poiché
discondono da TGraphicControl, che è un discendente diretto di TControl. Nonostante
questi controlli vengano visualizzati all’utente in fase di esecuzione, i controlli grafici
non hanno una propria finestra o widget sottostante. Invece, essi utilizzano la
finestra o il widget del genitore. A causa di questa limitazione i controlli grafici non
possono ricevere l’input di tastiera o agire come genitori nei confronti di altri
controlli. Tuttavia, dal momento che essi non hanno una propria finestra o widget, i
controlli grafici utilizzano meno risorse di sistema. Per maggiori informazioni su
molte classi incluse nel ramo TControl, vedere “Controlli grafici” a pagina 10-21.
Vi sono due versioni di TControl, una per applicazioni VCL (solo per Windows) e una
per applicazioni CLX (multipiattaforma). Anche la maggior parte dei controlli ha due
versioni, una versione solo per Windows, che deriva dalla versione solo per
Windows di TControl, e una versione multipiattaforma, che deriva dalla versione
Il ramo TWinControl/TWidgetControl
La maggior parte dei controlli si trova nel ramo TWinControl/ TWidgetControl. A
differenza dei controlli grafici, i controlli in questo ramo hanno una propria finestra o
widget. Per questo motivo, talvolta, essi vengono chiamati controlli con finestra o
controlli widget. I controlli con finestra discendono tutti da TWinControl, che deriva
dalla versione solo per windows di TControl. I controlli widget discendono tutti da
TWidgetControl, che deriva dalla versione multipiattaforma di TControl.
I controlli nel ramo TWinControl/TWidgetControl:
• Possono ricevere il fuoco durante l’esecuzione di un’applicazione, il che significa
che possono ricevere l’input da tastiera da parte dell’utente dell’applicazione. A
confronto, i controlli grafici possono solo visualizzare dati e rispondere al mouse.
• Possono essere genitori di uno o più controlli figlio.
• Hanno un handle, o un identificatore univoco, che permette loro di accedere alla
finestra o al widget sottostante.
Il ramo TWinControl/TwidgetControl include sia i controlli che vengono tracciati
automaticamente (come TEdit, TListBox, TComboBox, TPageControl, e così via) sia i
controlli custom che non corrispondono direttamente ad una singolo controllo di
Windows o widget sottostante. I controlli in questa categoria, che include classi come
TStringGrid e TDBNavigator, devono gestire in proprio i dettagli del disegno. A causa
di ciò, essi discendono da TCustomControl, che introduce una prioprietà Canvas ove
essi possono disegnare se stessi.
Per informazioni dettagliate su molti controlli del ramo TWinControl/TWidgetControl,
consultare il Capitolo 10, “Tipi di controlli”..
Cos’è un oggetto
Una classe è un tipo di dati che incapsula in una singola unit i dati e le operazioni su
dati. Prima della programmazione ad oggetti, dati e operazioni (funzioni) erano
trattati come elementi separati . Un oggetto è un’istanza di una classe. Cioè, è un
valore il cui tipo è una classe. Il termine oggetto è utilizzato spesso in modo più vago
in questa documentazione e, dove la distinzione fra una classe e un’istanza della
classe, non è importante, il termine “oggetto” può anche fare riferimento a una classe.
È possibile iniziare a capire gli oggetti se si capisconoi record in Pascal o le strutture in
C. I record sono composti da campi che contengono dati, e ogni campo ha il proprio
tipo. I record semplificano il modo con cui si fa riferimento a una raccolta di dati vari.
Gli oggetti sono anche raccolte di dati. Ma gli oggetti—a differenza dei record—
contengono le le procedure e le funzioni che operano sui dati. Queste procedure e
queste funzioni sono chiamate metodi.
Questa dichiarazione di variabile dichiara una variabile di nome Form1 del nuovo
tipo TForm1.
var
Form1: TForm1;
Form1 rappresenta un’istanza, o un oggetto, del tipo classe TForm1. È possibile
dichiarare più di un’istanza di un tipo classe; lo si potrebbe fare, ad esempio, per
creare più finestre figlio in un’applicazione MDI (Multiple Document Interface). Ogni
istanza gestisce i propri dati, ma tutte le istanze utilizzano lo stesso codice per
eseguire metodi.
Benché non si sia aggiunto alcun componente alla scheda e non sia stato scritto alcun
codice, già si ha un’applicazione GUI completa che è possibile compilare ed eseguire.
Tutto ciò che fa è visualizzare una scheda vuota.
Si supponga di aggiungere a questa scheda un componente pulsante e di scrivere un
gestore di evento OnClick che modifica il colore della scheda quando l’utente fa clic
sul pulsante. Il risultato potrebbe assomigliare a questo:
Figure 4.1 Una semplice scheda
Quando l’utente fa clic sul pulsante, il colore della scheda viene modificato in verde.
Questo è il codice di gestione evento per l’evento OnClick del pulsante:
procedure TForm1.Button1Click(Sender: TObject);
begin
Form1.Color := clGreen;
end;
Gli oggetti possono contenere altri oggetti come campi di dati. Ogni volta che si
mette un componente su una scheda, nella dichiarazione di tipo della scheda viene
visualizzato un nuovo campo. Se si crea l’applicazione descritta in precedenza e si
osserva il codice nel Code editor, questo è ciò che si vede:
unit Unit1;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs;
type
TForm1 = class(TForm)
pulsante su una nuova scheda, si potrebbe scrivere questo gestore di evento per
l’evento OnClick del pulsante:
procedure TForm1.Button1Click(Sender: TObject);
begin
Color := clFuchsia;
Button1.Color := clLime;
end;
La prima istruzione è equivalente a
Form1.Color := clFuchsia
Non è necessario qualificare Color con Form1 poiché il metodo Button1Click fa parte
di TForm1; gli identificatori nel corpo del metodo ricadono quindi all’interno
dell’ambito di visibilità dell’istanza TForm1 in cui il metodo viene chiamato . La
seconda istruzione, al contrario, fa riferimento al colore dell’oggetto pulsante (non
della scheda in cui è dichiarato il gestore di evento), e pertanto è necessario
qualificarlo.
L’IDE crea un file unit separato (codice sorgente) per ogni scheda. Se si desidera
accedere ai componenti di una scheda da un altro file unit della scheda, è necessario
qualificare i nomi dei componenti, come in questo esempio:
Form2.Edit1.Color := clLime;
Analogamente, è possibile accedere ai metodi di un componente da un’altra scheda.
Ad esempio,
Form2.Edit1.Clear;
Per accedere ai componenti di Form2 dal file unit di Form1, si deve anche aggiungere
la unit Form2 alla clausola uses della unit di Form1.
L’ambito di visibilità di una classe si estende ai suoi discendenti. È possibile, tuttavia,
ridichiarare un campo, una proprietà o un metodo in una classe discendente. Tali
nuove dichiarazioni nascondono o ridefiniscono il membro ereditato.
Per ulteriori informazioni sull’ambito di visibilità, sull’eredità e sulla clausola uses,
vedere il manuale Guida al linguaggio Delphi.
{private methods}
end;
• La sezione public dichiara campi e metodi senza limitazioni di accesso. Le istanze
della classe e le classi discendenti possono accedere a questi campi e a questi
metodi. Un membro pubblico è accessibile da un qualsiasi punto da cui è
accessibile la classe a cui appartiene —cioè, dalla unit in cui la classe è dichiarata e
da qualsiasi unit che utilizza quella unit.
• La sezione protected include campi e metodi con alcune limitazioni di accesso. Un
membro protetto è accessibile dall’interno della unit in cui la sua classe è
dichiarata e da qualsiasi classe discendente, indipendentemente dalla unit della
classe discendente.
• La sezione private dichiara campi e metodi che hanno limitazioni di accesso
rigorose. Un membro privato è accessibile solo dall’interno della unit in cui è
dichiarato. I membri privati sono utilizzati spesso in una classe per implementare
altro metodi e proprietà (pubblici o pubblicati).
• Per le classi che discendono da TPersistent, una sezione published dichiara le
proprietà e gli eventi che sono disponibili in progettazione. Un membro
pubblicato ha la stessa visibilità di un membro pubblico ma per i membri
pubblicati il compilatore genera informazioni di tipo in esecuzione . Le proprietà
pubblicate vengono visualizzate nell’Object Inspector in progettazione.
Quando si dichiara un campo, una proprietà o un metodo, il nuovo membro viene
aggiunto a una di queste quattro sezioni, il che definisce la sua visibilità: privato,
protetto, pubblico o pubblicato.
Per ulteriori informazioni sulla visibilità, vedere il manuale Guida al linguaggio Delphi.
var
Employee: TEmployee;
begin
Employee := TEmployee.Create;
end;
Il metodo Create è detto costruttore. Alloca memoria per un nuovo oggetto istanza e
restituisce un riferimento all’oggetto.
I componenti su una scheda vengono creati e distrutti automaticamente. Tuttavia, se
si scrive il codice per istanziare oggetti, si è anche responsabili della loro
cancellazione. Ogni oggetto eredita da Tobject un metodo Destroy (detto distruttore) .
Per distruggere un oggetto, tuttavia, si dovrebbe chiamare il metodo Free (anch’esso
ereditato da TObject), in quanto Free controlla che il riferimento sia nil prima di
chiamare Destroy. Ad esempio,
Employee.Free;
distrugge l’oggetto Employee e rilascia la memoria allocata.
Componenti e proprietà
I componenti di Delphi hanno un meccanismo interno per la gestione della memoria
che consente a un componente di assumersi la responsabilità di liberarne un altro. Si
dice che il componente precedente possied l’ultimo. La memoria di un componente
posseduto viene liberata automaticamente quando viene liberata la memoria del suo
proprietario. Il proprietario di un componente—il valore della sua proprietà Owner
—è determinato da un parametro passato al costruttore quando è stato creato il
componente. Per impostazione predefinita, una scheda possiede tutti i componenti
su di essa ed è posseduta a sua volta dall’applicazione. Quando si chiude
l’applicazione, viene pertanto liberata la memoria allocata per tutte le schede e per i
componenti su di esse.
Il concetto di proprietà vale solo per TComponent e per i suoi discendenti. Se si crea,
ad esempio, un oggetto TStringList o TCollection (anche se è associato a una scheda),
si è responsabili della liberazione dell’oggetto.
Type
TClassName = Class (TParentClass)
public
{public fields}
{public methods}
protected
{protected fields}
{protected methods}
private
{private fields}
{private methods}
end;
Se non si specifica alcun nome di classe genitore, la classe eredita direttamente da
TObject. TObject definisce solo pochissimi metodi, fra cui un costruttore e un
distruttore di base.
ToPer definire una classe:
1 Nell’IDE, iniziare con un progetto aperto e scegliere File|New|Unit per creare
una nuova unit in cui è possibile definire la nuova classe.
2 Aggiungere la clausola uses e la sezione type alla sezione interface.
3 InNella sezione type, scrivere la dichiarazione della classe. È necessario dichiarare
tutte le variabili membro, le proprietà, i metodi e gli eventi.
TMyClass = class; {This implicitly descends from TObject}
public
ƒ
private
ƒ
published {If descended from TPersistent or below}
ƒ
Se si desidera che la classe discenda da una classe specifica, è necessario indicare
nella definizione quella classe:
TMyClass = class(TParentClass); {This descends from TParentClass}
Ad esempio:
type TMyButton = class(TButton)
property Size: Integer;
procedure DoSomething;
end;
4 Alcune versioni dell’IDE includono una funzionalità detta completamento delle
classi che semplifica il lavoro di definizione e implementazione delle nuove classi
in quanto genera uno scheletro di codice per i membri di classe che vengono
dichiarati. Se si dispone della funzione per il completamento del codice,
richiamarlo per terminare la dichiarazione della classe: collocare il cursore
all’interno di una definizione di metodo nella sezione interface e premere
Ctrl+Shift+C (oppure fare clic destro e selezionare Complete Class a Cursor) . Tutte
le dichiarazioni di proprietà incompiute vengono completate, e per tutti i metodi
che richiedono un’implementazione, vengono aggiunti alla sezione
implementation i metodi vuoti.
For more details about the syntax, language definitions and rules for interfaces, see
the Delphi Language Guide
N Per questi esempi, si ipotizza che la classe di base immediata o una classe antenato
abbia implementato i metodi di IInterface, l’interfaccia di base da cui discendono tutte
le interfacce. Per ulteriori informazioni su IInterface, vedere “Implementazione di
IInterface” a pagina 4-14 e “Gestione della memoria di oggetti interfaccia” a
pagina 4-18.
Implementazione di IInterface
Così come tutti gli oggetti discendono, direttamente o indirettamente, da TObject,
tutte le interfacce derivano dall’interfaccia IInterface. IInterface consente
interrogazioni dinamiche e gestione durata dell’interfaccia. Questo è stabilito nei tre
metodi IInterface:
• QueryInterface interroga dinamicamente un oggetto dato per ottenere riferimenti di
interfaccia per le interfacce che l’oggetto supporta.
TInterfacedObject
Definendo una classe che supporta una o più interfacce, è conveniente utilizzare
TInterfacedObject come classe di base, poiché implementa i metodi di IInterface. La
classe TInterfacedObject è dichiarata nella unit System come segue:
type
TInterfacedObject = class(TObject, IInterface)
protected
FRefCount: Integer;
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
public
procedure AfterConstruction; override;
procedure BeforeDestruction; override;
class function NewInstance: TObject; override;
property RefCount: Integer read FRefCount;
end;
La derivazione diretta da TInterfacedObject è immediata. Nella seguente dichiarazione
di esempio, TDerived è un discendente diretto di TInterfacedObject e implementa
un’interfaccia ipotetica IPaint.
type
TDerived = class(TInterfacedObject, IPaint)
ƒ
end;
Poiché implementa i metodi di IInterface, TInterfacedObject gestisce automaticamente
il contatore dei riferimenti e la gestione della memoria degli oggetti interfacciati. Per
maggiori informazioni, vedere “Gestione della memoria di oggetti interfaccia” a
pagina 4-18, in cui si discute anche della scrittura delle classi che implementano
interfacce ma che non seguono il meccanismo di conteggio dei riferimenti inerente a
TInterfacedObject.
Aggregazione
L’aggregazione offre a un approccio modulare per il riutilizzo del codice mediante
sottoggetti che costituiscono le funzionalità di un oggetto contenente, ma che
nascondono i dettagli di implementazione a quell’oggetto. Nell’aggregazione, un
oggetto esterno implementa una o più interfacce. Quanto meno deve implementare
IInterface. L’oggetto o gli oggetti interni, implementano anche una o più interfacce.
Tuttavia, solo l’oggetto esterno espone le interfacce. Cioè, l’oggetto esterno espone sia
le interfacce che implementa sia quelle implementate dagli oggetti in esso contenuti.
I client non hanno alcuna informazione sugli oggetti interni. Mentre l’oggetto esterno
fornisce accesso alle interfacce dell’oggetto interno, la loro implementazione è
completamente trasparente. Quindi, la classe dell’oggetto esterno può scambiare il
tipo di classe dell’oggetto interno con qualsiasi classe che implementa la stessa
interfaccia. Analogamente, il codice per le classi dell’oggetto interno può essere
condiviso da altre classi che vogliono utilizzarlo.
Il modello di aggregazione definisce regole esplicite per implementare IInterface
utilizzando i meccanismi di delega. L’oggetto interno deve implementare due
versioni dei metodi IInterface.
• Deve implementare IInterface su se stesso, controllando il proprio conteggio dei
riferimenti. Questa implementazione di IInterface traccia la relazione fra l’oggetto
esterno e l’oggetto interno. Ad esempio, quando viene creato un oggetto del suo
tipo (l’oggetto interno), la creazione riesce solo se viene richiesta richiesta
un’intrefaccia di tipo IInterface.
• Implementa anche una seconda IInterface per tutte le interfacce implementate ed
esposte dall’oggetto esterno. Questa seconda IInterface delega le chiamate a
QueryInterface, _AddRef, e _Release all’oggetto esterno. La IInterface esterna viene
chiamata “controlling Unknown.”
Fare riferimento alla Guida in linea di MS per le regole sulla creazione di
un’aggregazione. Quando si scrivono proprie classi di aggregazione, è possibile
anche fare riferimento ai dettagli di implementazione di IInterface in TComObject.
TComObject è una classe COM che supporta l’aggregazione. Se si scrivono
applicazioni COM, è possibile anche utilizzare TComObject direttamente come una
classe di base.
N Negli esempi precedenti, la procedura beep , non appena viene dichiarata, incrementa
il contatore dei riferimenti (chiama _ AddRef) sul parametro, mentre le seguenti
dichiarazioni non lo fanno:
procedure beep(const x: ITest);
oppure
procedure beep(var x: ITest);
Queste dichiarazioni generano codice più piccolo e più veloce.
Nel caso in cui l’oggetto sia un componente o un controllo posseduto da un altro
componente impossibile utilizzare il contatore dei riferimenti, poiché non può essere
coerentemente applicato. In questo caso, è possibile ancora utilizzare le interfacce,
Utilizzo di BaseCLX
Capitolo5
5
Vi sono molte unit nella libreria dei componenti che forniscono il supporto di base
per la maggior parte delle librerie di componenti. Queste unit includono le routine
globali che costituiscono la libreria runtime, un numero di classi di utility come
quelle che rappresentano gli stream e gli elenchi, e le classi TObject, TPersistent, e
TComponent. Collettivamente, queste unit vengono chiamate BaseCLX. BaseCLX non
include nessuno dei componenti visualizzatisulla Component palette. Invece le classi
e le routine in BaseCLX vengono usate dai componenti visualizzati sulla Component
palette e sono utilizzabili nel codice delle proprie applicazioni o durante la scrittura
delle proprie classi.
Le sezioni seguenti trattano molte classi e routine che compongono BaseCLX e ne
illustrano i possibili utilizzi. Fra questi vi sono
• Uso di stream
• Operazioni con i file
• Operazioni con i file .ini
• Operazioni con le liste
• Operazioni con elenchi di stringhe
• Operazioni con stringhe
• Creazione di spazi di disegno
• Stampa
• Conversione di misure
• Definizione di variant custom
Uso di stream
Gli stream sono classi che permettono di leggere e scrivere dati. Essi forniscono
un’interfaccia comune per la lettura e la scrittura su svariati supporti come memoria,
stringhe, socket e campi BLOB nei database. Esistono numerose classi stream, che
discendono tutte da TStream. Ogni classe stream è specifica per un tipo di supporto.
Ad esempio, TMemoryStream legge o scrive su un’immagine in memoria; TFileStream
legge o scrive su un file.
Seek azzera la Position corrente dello stream, spostandola dello scostamento indicato.
Seek restituisce la nuova posizione corrente nello stream.
La proprietà Position indica l’offset corrente, in byte, nello stream (a partire dall’inizio
dello stream di dati). La dichiarazione per Position è:
property Position: Int64;
La proprietà Size indica le dimensioni in byte dello stream. Può essere utilizzata per
determinare il numero di byte disponibili per la lettura o per troncare i dati nello
stream. La dichiarazione per Size è:
property Size: Int64;
Size viene usata internamente dalle routine che leggono e scrivono nello stream.
L’impostazione della proprietà Size cambia le dimensioni dei dati nello stream. Ad
esempio,in un file stream, viene usata come marcatore di fine file per troncare il file.
Se le dimensioni Size del stream non possono essere cambiate, viene sollevata
un’eccezione. Ad esempio, il tentativo di cambiare Size di uno stream di file di sola
lettura solleva un’eccezione.
queste routine sono wrapper per funzioni API di Windows. Poiché le funzioni
BaseCLX possono usare la sintassi del linguaggio Delphi e occasionalmente
forniscono valori di parametri predefiniti, esse costituiscono una comoda
interfaccia per le API di Windows. Inoltre, esistono le versioni corrispondenti in
Linux, cosicché è possibile utilizzare queste routine in applicazioni
multipiattaforma. Per utilizzare un approccio basato su handle, per prima cosa si
deve aprire apre un file utilizzando la funzione FileOpen o creare un nuovo file
utilizzando la funzione FileCreate. Una volta ottenuto l’handle, utilizzare routine
basate su handle per operare con il contenuto (scrittura di una riga, lettura del
testo, e così via).
• La unit System definisce un numero di routine di file I/O che operano con
variabili di file, solitamente nel formato "F: Text:" oppure "F: File:". Il tipo delle
variabili di file può essere uno dei seguenti: con tipo, testo e senza tipo. Un certo
numero di routine per la gestione dei file, come AssignPrn e writeln, li utilizzano.
L’uso delle variabili di file è sconsigliato, e questi tipi di file sono supportati solo
per compatibilità con le versioni precedenti. Esse sono incompatibili con gli
handles dei file di Windows. Se è proprio necessario lavorare con queste variabili,
consultare il manuale Guida al linguaggio Delphi.
La modalità share può assumere uno dei seguenti valori con le limitazioni elencate di
seguito:
Si noti che la modalità share che è possibile utilizzare dipende dalla modalità open
che è stata utilizzata. La seguente tabella mostra le modalità share disponibili per
ogni modalità open.
Le costanti delle modalità open e share sono definite nella unit SysUtils.
W Benché il linguaggio Delphi non sia sensibile alle differenze fra maiuscole e
minuscole, lo è invece il sistema operativo Linux. Prestare molta attenzione all’uso di
maiuscole/minuscole quando si lavora con file in applicazioni multipiattaforma.
Cancellazione di un file
La cancellazione elimina il file dal disco e ne rimuove la voce dalla relativa directory.
Non esiste una operazione corrispondente che permetta di ripristinare un file
cancellato; generalmente, quindi, le applicazioni chiederanno agli utenti di
confermare la cancellazione dei file. Per cancellare un file, basta passare il suo nome
alla funzione DeleteFile:
DeleteFile(FileName);
DeleteFile restituisce True se il file viene cancellato, False in caso contrario (per
esempio, se il file non esiste o se è a sola lettura). DeleteFile elimina il file chiamato da
FileName dal disco.
Ricerca di un file
Per trovare un file si usano tre routine: FindFirst, FindNext, and FindClose. FindFirst
cerca la prima istanza del nome di un file con un certo set di attributi in una
determinata directory. FindNext restituisce il primo file corrispondente al nome e agli
attributi specificati in una precedente chiamata a FindFirst. FindClose rilascia la
memoria allocata da FindFirst. Si deve usare sempre FindClose per concludere una
sequenza FindFirst/FindNext. Per sapere se un file esiste, c’è una funzione FileExists
che restituisce True in caso affermativo, False in caso contrario.
Le tre routine di ricerca dei file accettano TSearchRec come parametro. TSearchRec
definisce le informazioni sul file cercate da FindFirst o FindNext. Se viene trovato un
file, i campi del parametro di tipo TSearchRec vengono modificati per descrivere il file
trovato:
type
TFileName = string;
TSearchRec = record
Time: Integer;//Time contains the time stamp of the file.
Size: Integer;//Size contains the size of the file in bytes.
Attr: Integer;//Attr represents the file attributes of the file.
Name: TFileName;//Name contains the filename and extension.
ExcludeAttr: Integer;
FindHandle: THandle;
FindData: TWin32FindData;//FindData contains additional information such as
//file creation time, last access time, long and short filenames.
end;
Per verificare un attributo, bisogna abbinare il valore del campo Attr alla costante
di attributo con l’operatore &. Se il file ha quell’attributo, il risultato sarà
maggiore di 0. Ad esempio, se il file trovato è un file nascosto, la seguente
espressione sarà valutata come true:
(SearchRec.Attr and faHidden > 0).
Gli attributi possono essere combinati eseguendo l’OR delle rispettive costanti o dei
valori. Ad esempio, per cercare i file nascosti e a sola lettura oltre ai normali file, si
può passare ciò che segue come parametro Attr.
(faReadOnly or faHidden).
L’esempio seguente illustra l’uso di tre routine che trovano file. Nell’esempio si usa
un’etichetta, un pulsante di nome Search e un pulsante di nome Again collocati su una
scheda. Quando l’utente fa clic sul pulsante Search, viene trovato il primo file nel
percorso specificato, e il nome e il numero di byte del file appaiono nel titolo
dell’etichetta. Ogni volta che l’utente fa clic sul pulsante Again, nell’etichetta vengono
visualizzati le dimensioni e il nome corrispondenti del file:
var
SearchRec: TSearchRec;
procedure TForm1.SearchClick(Sender: TObject);
begin
FindFirst('c:\Program Files\MyProgram\bin\*.*', faAnyFile, SearchRec);
Label1.Caption := SearchRec.Name + ' is ' + IntToStr(SearchRec.Size) + ' bytes in size';
end;
procedure TForm1.AgainClick(Sender: TObject);
begin
if FindNext(SearchRec) = 0 then
Label1.Caption := SearchRec.Name + ' is ' + IntToStr(SearchRec.Size) + ' bytes in size'
else
FindClose(SearchRec);
end;
N RenameFile nella libreria runtime è un wrapper per la funzione MoveFile delle API di
Windows, e pertanto nemmeno MoveFile funzionerà sulle varie unità.
Copia di un file
La libreria runtime non fornisce alcuna routine per copiare un file. Comunque, se si
stanno scrivendo applicazioni per l’ambiente Windows, per chiamare un file, è
possibile chiamare direttamente la funzione API CopyFile di Windows. Come la
maggior parte delle routine della libreria runtime, CopyFile accetta un nome di file
come parametro, e non un handle di file. Quando si copia un file, occorre fare
attenzione che nel nuovo file vengano copiati gli attributi del file esistente, ma non
quelli relativi alla sicurezza. CopyFile è utile anche nello spostamento dei file nelle
unità, perché né la funzione RenameFile né la funzione API MoveFile possono
rinominare oppure spostare i file nelle unità. Per ulteriori informazioni, consultare la
Guida in linea di Microsoft Windows.
Utilizzo di TRegistryIniFile
La maggior parte delle applicazioni a 32-bit memorizzano le proprie informazioni nel
file di registro invece che nel file ini poiché il file di registro è gerarchico e non è
soggetto ai limiti sulle dimensione dei file ini. Se si è abituati ad utilizzare i file ini e si
vogliono spostare invece le informazioni di configurazione nel file di registro, è
possibile utilizzare la classe TRegistryIniFile. Si potrebbe anche volere utilizzare
TRegistryIniFile in applicazioni multipiattaforma nel caso si voglia utilizzare il
Registro di sistema in Windows e un file ini in Linux. È possibile scrivere la maggior
parte dell’applicazione in modo che utilizzi il tipo TCustomIniFile. È necessario solo
condizionare il codice che crea un’istanza di TRegistryIniFile (in Windows) o
TMemIniFile (in Linux) e assegnarla al TCustomIniFile utilizzato dall’applicazione.
TRegistryIniFile è progettata per far sì che le voci del file di registro assomiglino alle
voci del file INI. Tutti i metodi di TIniFile e di TMemIniFile (lettura e scrittura)
esistono in TRegistryIniFile.
Quando si costruisce un oggetto TRegistryIniFile, il parametro che si passa (il nome
file per un oggetto IniFile oppure un oggetto TmemIniFile) diventa un valore di
chiave nelle chiavi utente nel file di registro e tutte le sezioni e i valori dipendono da
quella radice. Tutte le sezioni e i valori sono ramificazioni di quella radice.
TRegistryIniFile semplifica notevolmente l’interfaccia del file di registro, tanto che lo
si utilizzerà al posto del componente di TRegistry, anche se non si sta convertendo del
codice esistente o scrivendo un’applicazione multipiattaforma.
Uso di TRegistry
Se si sta scrivendo un’applicazione solamente per Windows e la struttura del
Registro di sistema è familiare, è possibile utilizzare TRegistry. A differenza di
TRegistryIniFile, che utilizza le stesse proprietà e metodi degli altri componenti per
file ini, le proprietà e i metodi di TRegistry corrispondono più direttamente alla
struttura del Registro di sistema. Ad esempio, TRegistry permette di specificare sia la
chiave radice che la sottochiave, mentre TRegistryIniFile assume
HKEY_CURRENT_USER come chiave radice. Oltre ai metodi per aprire, chiudere,
salvare, spostare, copiare e cancellare chiavi, TRegistry permette di specificare il
livello di accesso che si desidera utilizzare.
end;
associare a quell’elemento. Nel caso di collection, Add non accetta alcun parametro,
ma crea un nuovo elemento che aggiunge. Il metodo Add sulle collection restituisce
l’elemento che ha aggiunto, in modo che sia possibile assegnare valori alle proprietà
del nuovo elemento.
Oltre al metodo Add, alcune classi di elenco hanno un metodo Insert. Insert funziona
esattamente come il il metodo Add, ma ha un parametro aggiuntivo che consente di
specificare la posizione nell’elenco in cui si desidera che venga visualizzato il nuovo
elemento. Se una classe ha un metodo Add, ha anche un metodo Insert a meno che la
posizione degli elementi non sia predeterminata. Ad esempio, è impossibile
utilizzare Insert con elenchi ordinati poiché gli elementi devono essere messi secondo
la sequenza di ordinamento ed è impossibile utilizzare Insert con bucket lists poiché
l’algoritmo hash determina la posizione dell’elemento.
Le uniche classi che non hanno un metodo Add sono gli elenchi ordinati. Gli elenchi
ordinati sono code e stack. Per aggiungere elementi a un elenco ordinato, utilizzare
invece il metodo Push. Push, come Add, accetta un elemento come parametro e lo
inserisce nella posizione corretta.
Elenchi persistenti
Gli elenchi persistenti possono essere salvati in un file scheda. Per questo motivo,
sono speeso utilizzati come tipi di una proprietà pubblicata di un componente. È
possibile aggiungere elementi all’elenco in fase di progettazione e quegli elementi
vengono salvati con l’oggetto in modo che essi siano presenti quando il componente
che li utilizza viene caricato in memoria in fase esecuzione. Ci sono due tipi principali
di elenchi persistenti: elenchi di stringhe e collection.
Come esempi di elenchi di stringhe si possono citare TStringList e THashedStringList.
Gli elenchi di stringhe, come dice anche il nome, contengono stringhe. Essi
forniscono un supporto speciale per stringhe in formato Name=Value, in modo che
sia possibile reperire il valore associato a un nome. Inoltre, la maggior parte degli
elenchi di stringhe permettono di associare un oggetto a ogni stringa nell’elenco. Le
liste di stringhe sono descritte in modo più dettagliato in “Operazioni con elenchi di
stringhe” a pagina 5-16.
Le collection discendono dalla classe TCollection. Ogni discendente TCollection è
specializzato nella gestione di una specifica classe di elementi, dove quella classe
discende da TCollectionItem. Le collection supportano la maggior parte delle comuni
operazioni sugli elenchi. Tutte le collection sono progettate per essere del tipo di una
proprietà pubblicata, e molte non possono funzionare in modo indipendente
dall’oggetto che le utilizza per implementare una delle sue proprietà. In
progettazione, la proprietà il cui valore è una raccolta può utilizzare il Collection
editor l’editor per consentire l’aggiunt, la rimozione e il riordino di elementi. Il
Collection editor fornisce un’interfaccia utente comune per il trattamento delle
collection
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
private
{ Private declarations }
public
{ Public declarations }
ClickList: TStrings;{ declare the field }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
end.
Insert(2, 'Three');
Per aggiungere le stringhe di un elenco ad un altro, chiamare il metodo AddStrings:
StringList1.AddStrings(StringList2); { append the strings from StringList2 to StringList1 }
Quando è possibile, le tabelle forniscono anche le colonne per indicare se una routine
soddisfa i seguenti criteri.
• Sensibilità a maiuscole/minuscole: Se si utilizzano le impostazioni locali,
determina la definizione del formato delle lettere. Se la routine non usa le
impostazioni locali, l’analisi viene effettuata sui valori ordinali dei caratteri. Se la
routine tiene conto della differenza tra lettere maiuscole/ minuscole, c’è una
fusione logica dei caratteri maiuscoli e minuscoli che viene determinata da un
modello predefinito.
• Usa impostazioni locali: L’abilitazione della versione locale consente di
personalizzare l’ applicazione per specifiche nazioni, in particolare per gli
ambienti con lingue dell’Asia. La maggior parte delle versioni nazionalizzate
considera i caratteri minuscoli minori dei corrispondenti caratteri maiuscoli.
Questo è in contrasto con l’ordinamento ASCII, nel quale i caratteri minuscoli sono
maggiori dei caratteri maiuscoli. Le routine che usano le impostazioni locali di
sistema sono normalmente precedute dalla parola Ansi (cioè, AnsiXXX).
• Supporta il set di caratteri multibyte (MBCS): I MBCS vengono usati quando si
scrive codice per paesi dell’estremo oriente. I caratteri multi-byte vengono
rappresentati da uno o più codici di carattere, e pertanto la lunghezza in byte non
corrisponde necessariamente alla lunghezza della stringa. Le routine che
supportano i MBCS sono scritte per analizzare caratteri ad uno o più byte.
ByteType e StrByteType determinano se un particolare byte è quello iniziale di un
carattere multi-byte. Quando si usano i caratteri multi-byte bisogna prestare
attenzione a non troncare una stringa tagliando a metà un carattere. Non si
devono passare caratteri come parametro ad una funzione o procedura, poiché le
dimensioni di un carattere non possono essere predeterminate. Si può passare,
invece, un puntatore ad un carattere o ad una stringa. Per ulteriori informazioni su
MBCS, consultare il paragrafo “Abilitazione del codice dell’applicazione” a
pagina 17-2.
Tabella 5.12 Routine di conversione maiuscole/minuscole per stringhe terminate con null
Usa impostazioni
Routine locali Supporta MBCS
AnsiStrLower Sì Sì
AnsiStrUpper Sì Sì
StrLower no no
StrUpper no no
S = ‘’;
Una stringa vuota non contiene dati validi. Quindi, se si prova a indicizzare una
stringa vuota, è come se si stentasse di accedere a nil e il risultato sarà uno violazione
di accesso.
var
S: string;
begin
S[i]; // this will cause an access violation
// statements
end;
Analogamente, se si converte una stringa vuota a PChar, il risultato è un puntatore
nil. Quindi, se si esegue il passaggio di un siffatto PChar a una routine che deve
leggere o scrivere la stringa, bisogna accertarsi che la routine sia in grado di gestire
nil:
var
S: string; // empty string
begin
proc(PChar(S)); // be sure that proc can handle nil
// statements
end;
Se non è in grado di gestirlo, si può inizializzare la stringa:
S := ‘No longer nil’;
proc(PChar(S));// proc does not need to handle nil now
oppure impostarne la lunghezza, utilizzando la procedura SetLenght:
SetLength(S, 100);//sets the dynamic length of S to 100
proc(PChar(S));// proc does not need to handle nil now
Quando si utilizza SetLength, i caratteri esistenti nella stringa vengono slavaguardati,
ma i contenuti di qualsiasi spazio allocato di fresco sono indefiniti. Dopo una
chiamata a SetLenght, S fa senz’altro riferimento a una stringa univoca, che è una
stringa io cui contatore dei riferimenti è pari a uno. Per ottenere la lunghezza di una
stringa, utilizzare la funzione Length.
Quando si dichiara una stringa, ricordarsi che:
S: string[n];
dichiara implicitamente una short string e non una long string lunga n. Per dichiarare
una long string di una lunghezza specifica n, bisogna dichiarare una variabile di tipo
string e utilizzare la procedura SetLenght.
S: string;
SetLength(S, n);
variabile short string, bisogna tenere a mente che quel valore di stringa verrà troncato
nel caso esso sia più lungo della massima lunghezza dichiarata della variabile short
string.
Le long string risultano già allocate in modo dinamico. Se si utilizza uno dei tipi
puntatore nativi, come PAnsiString, PString, o PWideString, è bene ricordare che si sta
introducendo un altro livello di indirezione. Accertarsi che sia esattamente ciò che si
vuole fare.
Ulteriori funzioni (CopyQStringListToTstrings, Copy TStringsToQStringList,
QStringListToTStringList) vengono fornite per convertire i tipi di stringa Qt
sottostanti e per i tipi string di CLX. Queste funzioni sono incluse in Qtypes.pas.
Dipendenze di stringhe
Alcune volte è necessario convertire una long string in una stringa che termina con
null, ad esempio, se si sta utilizzando una funzione che accetta un PChar. Se si deve
convertire una stringa in un PChar, tenere a mente che si è responsabili della durata
del PChar risultante. Poiché le long string sono conteggiate per riferimento, una
conversione di tipo da string a PChar aumenta la dipendenza sulla stringa di uno
senza incrementare effettivamente il contatore dei riferimenti. Quando il contatore
dei riferimenti arriva a zero, la stringa viene distrutta, anche se vi è una dipendenza
extra. Anche il PChar convertito scompare, mentre la routine a cui lo si è passato lo
sta ancora utilizzando. Ad esempio:
procedure my_func(x: string);
begin
// do something with x
some_proc(PChar(x)); // cast the string to a PChar
// you now need to guarantee that the string remains
// as long as the some_proc procedure needs to use it
end;
termina, il PChar scompare poiché è un puntatore alla memoria, e non una copia
conteggiata per riferimento della stringa. Ad esempio:
function title(n: Integer): PChar;
var
s: string;
begin
s := Format(‘title - %d’, [n]);
Result := PChar(s); // DON’T DO THIS
end;
Questo esempio restituisce un puntatore a dati di stringa che viene liberato nel
momento in cui termina la funzione title.
SetLength(S, MAX_SIZE;// when casting to a PChar, be sure the string is not empty
SetLength(S, GetModuleFilename( 0, PChar(S), Length(S) ) );
// statements
end;
Stampa
Come TCanvas, la classe TPrinter non appartiene a BaseCLX in quanto vi sono due
versioni separate, una per le applicazioni VCL (nella unit Printers) e una per le
applicazioni CLX (nella unit QPrinters). L’oggetto TPrinter della VCL incapsula i
dettagli delle stampanti Windows. L’oggetto TPrinter è un dispositivo per il disegno
su stampante. Esso genera del codice postscript e lo invia ai dispositivi lpr, lp o a un
altro comando di stampa. Entrambe le versioni di TPrinter, tuttavia, sono
estremamente simili.
Per ottenere un elenco delle stampanti installate disponibili, utilizzare la proprietà
Printers. Entrambi gli oggetti printer utilizzano TCanvas (identico al TCanvas della
scheda), il che significa che tutto ciò che può essere tracciato su una scheda può anche
essere stampato. Per stampare un’immagine, chiamare il metodo BeginDoc seguito da
un qualsiasi canvas grafico che si desidera stampare (incluso del testo mediante il
metodo TextOut) e inviare il lavoro alla stampante chiamando il metodo EndDoc.
L’esempio seguente utilizza un pulsante e un campo memo su una scheda. Quando
l’utente fa clic sul pulsante, il contenuto del memo viene stampato a una distanza di
200-pixel dal bordo della pagina.
Per eseguire con successo questo esempio, includere Printers nella clausola uses.
Conversione di misure
La unit ConvUtils dichiara una funzione Convert di uso generale che è possibile
utilizzare per convertire una misura da un sistema di misura a uno altro. È possibile
eseguire conversioni tra unità di misura compatibili come piedi e pollici o giorni e
settimane. Le unità di misura che misurano lo stesso tipo di cose sono dette
appartenere alla stessa famiglia di conversione. Le unita che devono essere convertite
devono appartenere alla stessa famiglia di conversione. Per informazioni su come
effettuare una conversione, vedere la “Esecuzione di conversioni” a pagina 5-33 e
consultare l’argomento Convert nella Guida in linea.
La unit StdConvs definisce diverse famiglie di conversione e unità di misura
all’interno di ogni famiglia. Inoltre, è possibile creare famiglie di conversione
personalizzate e le relative unità di misura utilizzando le funzioni
RegisterConversionType e RegisterConversionFamily.Per informazioni sull’ampliamento
delle conversioni e sulle unita di conversione, consultare “Aggiunta di nuovi tipi di
misura” a pagina 5-34 e consultare l’argomento Convert nella Guida in linea.
Esecuzione di conversioni
È possibile utilizzare la funzione Convert per eseguire conversioni sia semplici che
complesse. La funzione ha una sintassi semplificata e una seconda sintassi per
l’esecuzione di conversioni tra tipi di misura complessi.
Per altri esempi, fare riferimento al codice sorgente per le unit di conversione
standard (stdconvs.pas). (Notare che il sorgente non è incluso in tutte le edizioni di
Delphi.
N Quando si definisce un record che viene mappato in questo modo sul record
TVarData, accertarsi di definirlo come un record packed.
Se al nuovo tipo variant custom servono più di 14 byte per memorizzare i propri dati,
è possibile definire un nuovo tipo record che includa un puntatore o un’istanza di
oggetto. Ad esempio, la unit VarCmplx utilizza un’istanza della classe TComplexData
per rappresentare i dati in un variant con valori complessi. Quindi definisce un tipo
record con le stesse dimensioni di TVarData che include un riferimento a un oggetto
TComplexData:
TComplexVarData = packed record
VType: TVarType;
Reserved1, Reserved2, Reserved3: Word;
VComplex: TComplexData;
Reserved4: LongInt;
end;
I riferimenti a oggetto sono in effetti dei puntatori (due Words ), pertanto questo tipo
ha le stessa dimensioni del record TVarData. Come visto in precedenza, un variant
custom complesso (o il suo record TVarData ), può essere convertito in
TComplexVarData e il tipo variant custom opererà con il record TVarData come se
fosse un tipo TComplexVarData.
N Il parametro Indirect nel metodo Copy segnala che la copia deve considerare il caso in
cui il variant conserva solo un riferimento indiretto ai propri dati.
T Se il tipo variant custom non alloca alcuna memoria per contenere i propri dati (nel
caso i dati siano contenuti completamente nel record TVarData), l’implementazione
del metodo Copy può limitarsi a chiamare il metodo SimplisticCopy.
Per indicare come cancellare il valore del variant, implementare il metodo Clear.
Come con il metodo Copy, l’unica cosa a cui prestare attenzione è quella di accertarsi
di liberare tutte le risorse allocate per memorizzare i dati del variant:
procedure TComplexVariantType.Clear(var V: TVarData);
begin
V.VType := varEmpty;
FreeAndNil(TComplexVarData(V).VComplex);
end;
Sarà necessario anche implementare il metodo IsClear. In questo modo, è possibile
rilevare qualsiasi valore non valido o valore speciale che rappresenta dati “vuoti”:
function TComplexVariantType.IsClear(const V: TVarData): Boolean;
begin
Result := (TComplexVarData(V).VComplex = nil) or
TComplexVarData(V).VComplex.IsZero;
end;
Utilizzo di TInvokeableVariantType
Per fornire il supporto per proprietà e metodi, la classe che si crea per attivare il
nuovo tipo variant custom dovrebbe discendere da TInvokeableVariantType invece che
direttamente da TCustomVariantType.
TInvokeableVariantType definisce quattro metodi:
• DoFunction
• DoProcedure
• GetProperty
• SetProperty
che è possibile implementare per supportare proprietà e metodi sul tipo variant
custom.
Ad esempio, la unit VarConv utilizza TInvokeableVariantType come classe di base per
TConvertVariantType in modo che i variant custom risultanti possano supportare le
proprietà. Il seguente esempio mostra il getter di proprietà per queste proprietà:
function TConvertVariantType.GetProperty(var Dest: TVarData;
const V: TVarData; const Name: String): Boolean;
var
LType: TConvType;
begin
// supports...
// 'Value'
// 'Type'
// 'TypeName'
// 'Family'
// 'FamilyName'
// 'As[Type]'
Result := True;
if Name = 'VALUE' then
Variant(Dest) := TConvertVarData(V).VValue
else if Name = 'TYPE' then
Variant(Dest) := TConvertVarData(V).VConvType
else if Name = 'TYPENAME' then
Variant(Dest) := ConvTypeToDescription(TConvertVarData(V).VConvType)
Utilizzo di TPublishableVariantType
Se il tipo variant custom memorizza i propri dati utilizzando un’istanza di un
oggetto, esiste un modo più semplice per implementare le proprietà, sempre che esse
siano anche proprietà dell’oggetto che rappresenta i dati del variant. Se si utilizza
TPublishableVariantType come classe di base per il tipo variant custom, è necessario
implementare solo il metodo GetInstance, e tutte le proprietà pubblicate dell’oggetto
che rappresenta i dati del variant saranno implementate automaticamente per i
variant custom.
Ad esempio, come si è visto in “Memorizzazione dei dati di un tipo variant custom”
a pagina 5-42, TComplexVariantType memorizza i dati di un variant con valori
complessi utilizzando un’istanza di TComplexData. TComplexData ha molte proprietà
pubblicate (Real, Imaginary, Radius, Theta e FixedTheta), che forniscono informazioni
sul valore complesso. TComplexVariantType discende da TPublishableVariantType e
implementa il metodo GetInstance per restituire l’oggetto TComplexData (in
TypInfo.pas) che è memorizzato nel record TVarData di un variant con valori
complessi:
function TComplexVariantType.GetInstance(const V: TVarData): TObject;
begin
Result := TComplexVarData(V).VComplex;
end;
N Per far sì che TPublishableVariantType funzioni, l’oggetto che contiene i dati del
variant custom deve essere compilato con RTTI. Ciò significa che deve essere
compilato utilizzando la direttiva al compilatore {$M+} oppure discendere da
TPersistent.
La maggior parte dei messaggi Windows (in applicazioni VCL) o degli eventi di
sistema (in applicazioni CLX) sono gestiti dai componenti di Delphi. Quando si vuole
rispondere ad un messaggio o ad un evento di sistema, occorre solo fornire un
gestore di eventi.
Il Capitolo 9, “Sviluppo dell’interfaccia utente dell’applicazione”, fornisce
informazioni dettagliate sull’uso delle schede, come la creazione di schede modali in
maniera dinamica, il passaggio dei parametri alle schede e il recupero dei dati dalle
schede.
Chiamate a metodi
I metodi vengono chiamati come qualsiasi altra comune procedura o funzione. Per
esempio, i controlli visuali hanno un metodo Repaint che aggiorna l’immagine del
controllo sullo schermo. Il metodo Repaint di un oggetto draw-grid potrebbe essere
chiamato nel seguente modo:
DrawGrid1.Repaint;
Come per le proprietà, il campo d’azione di un nome di metodo determina la
necessità o meno di qualificatori. Se, per esempio, si desidera ridisegnare una scheda
dall’interno di un gestore di evento di un controllo figlio della scheda, non è
necessario anteporre il nome della scheda alla chiamata al metodo:
procedure TForm1.Button1Click(Sender: TObject);
begin
Repaint;
end;
Per maggiori informazioni sul campo d’azione vedere “Ambito di visibilità e
qualificatori” a pagina 4-5
AboutBox.Caption := '';
AboutBox.ShowModal;
end;
Capitolo
Rilascio di elementi
Se un controllo indica che può accettare un elemento trascinato, è necessario gestire
l’elemento che viene rilasciato su di esso. Per gestire gli elementi rilasciati, si deve
collegare un gestore all’evento OnDragDrop del controllo che accetta l’elemento
rilasciato. Come l’evento drag-over, l’evento drag-and-drop indica la sorgente
dell’elemento trascinato e le coordinate del cursore del mouse sul controllo
accettante. L’ultimo parametro consente di monitorare il percorso compiuto da un
oggetto durante il trascinamento; ad esempio, si potrebbe utilizzare questa
informazione per modificare il colore dei componenti, se un oggetto viene rilasciato.
Nell’esempio che segue, una vista ad albero della directory, che accetta elementi
trascinati da una casella di riepilogo di file, risponde spostando i file nella directory
su cui i file vengono rilasciati.
procedure TFMForm.DirectoryOutline1DragDrop(Sender, Source: TObject; X,
Y: Integer);
begin
if Source is TFileListBox then
with DirectoryOutline1 do
ConfirmChange('Move', FileListBox1.FileName, Items[GetItem(X, Y)].FullPath);
end;
così via. I controlli pagina agganciano i figli in nuovi fogli di tabulazione (o fondono i
fogli di tabulazione se il figlio è un altro controllo pagina).
Tre eventi consentono alle posizioni di aggancio di limitare ulteriormente il modo in
cui vengono agganciati i controlli figlio:
property OnGetSiteInfo: TGetSiteInfoEvent;
TGetSiteInfoEvent = procedure(Sender: TObject; DockClient: TControl; var InfluenceRect:
TRect; var CanDock: Boolean) of object;
OnGetSiteInfo si verifica nella posizione di aggancio quando l’utente trascina un figlio
agganciabile sul controllo. Questo evento consente alla posizione di indicare se
accetterà o meno il controllo specificato dal parametro DockClient come figlio, e in
caso di risposta positiva, dove deve essere agganciato il figlio. Quando si verifica
OnGetSiteInfo, InfluenceRect viene inizializzato alle coordinate dello schermo della
posizione di aggancio, e CanDock viene inizializzato a True. Modificando
InfluenceRect, può essere creata una regione di aggancio più limitata, mentre il figlio
può essere rifiutato impostando CanDock a False.
property OnDockOver: TDockOverEvent;
TDockOverEvent = procedure(Sender: TObject; Source: TDragDockObject; X, Y: Integer; State:
TDragState; var Accept: Boolean) of object;
OnDockOver si verifica nella posizione di aggancio quando l’utente trascina sul
controllo un figlio agganciabile. Corrisponde all’evento OnDragOver in una normale
operazione drag-and-drop. Deve essere utilizzato per segnalare che il figlio può
essere rilasciato dalla posizione di aggancio, impostando il parametro Accept. Se il
controllo agganciabile è stato rifiutato dal gestore di evento OnGetSiteInfo (forse
perché il tipo di controllo era errato), l’evento OnDockOver non verrà attivato.
property OnDockDrop: TDockDropEvent;
TDockDropEvent = procedure(Sender: TObject; Source: TDragDockObject; X, Y: Integer) of
object;
OnDockDrop si verifica nella posizione di aggancio quando l’utente rilascia un figlio
agganciabile sul controllo. Corrisponde all’evento OnDragDrop in una normale
operazione drag-and-drop. Deve essere utilizzato per eseguire un adattamento
necessario per accettare il controllo come controllo figlio. L’accesso al controllo figlio
può essere ottenuto usando la proprietà Control del TDockObject specificato dal
parametro Source.
Il parametro Client indica il controllo figlio che sta tentando lo sganciamento, mentre
il parametro Allow consente alla posizione di aggancio (Sender) di rifiutare lo
sganciamento. Quando si implementa un gestore di evento OnUnDock, può risultare
utile conoscere quali altri figli (eventuali) sono al momento agganciati. Queste
informazioni sono disponibili nella proprietà a sola lettura DockClients, che è un array
indicizzato di TControl. Il numero di client agganciati viene indicato dalla proprietà a
sola lettura DockClientCount.
Right1.Checked := False;
Center1.Checked := False;
with Sender as TMenuItem do Checked := True; { check the item clicked }
with Editor do { then set Alignment to match }
if Left1.Checked then
Alignment := taLeftJustify
else if Right1.Checked then
Alignment := taRightJustify
else if Center1.Checked then
Alignment := taCenter;
end;
È anche possibile utilizzare la proprietà HMargin per aggiustare i margini destro e
sinistro in un controllo memo.
begin
for I := 0 to Memo1.Lines.Count do
begin
PosReturn := Pos(FindDialog1.FindText,Memo1.Lines[I]);
if PosReturn <> 0 then {found!}
begin
Skipchars := 0;
for J := 0 to I - 1 do
Skipchars := Skipchars + Length(Memo1.Lines[J]);
SkipChars := SkipChars + (I*2);
SkipChars := SkipChars + PosReturn - 1;
Memo1.SetFocus;
Memo1.SelStart := SkipChars;
Memo1.SelLength := Length(FindDialog1.FindText);
Break;
end;
end;
end;
Editor.CutToClipboard;
end;
procedure TEditForm.CopyToClipboard(Sender: TObject);
begin
Editor.CopyToClipboard;
end;
procedure TEditForm.PasteFromClipboard(Sender: TObject);
begin
Editor.PasteFromClipboard;
end;
Tabella 7.2 Confronto dello stile owner-draw fisso con quello variabile
Stile owner-draw Significato Esempi
Fixed Ogni elemento ha la stessa altezza, e lbOwnerDrawFixed,
precisamente quella determinata dalla csOwnerDrawFixed
proprietà ItemHeight.
Variable Ogni elemento può avere un’altezza diversa, lbOwnerDrawVariable,
determinata dai dati forniti al momento csOwnerDrawVariable
dell’esecuzione.
N Occorre convertire gli elementi dalla proprietà Objects nell’elenco di stringhe. Objects
è una proprietà di tipo TObject che pertanto può contenere qualsiasi tipo di oggetto.
Quando si recuperano gli oggetti dall’array, occorre riconvertirli nel tipo effettivo
degli elementi.
Creazione di applicazioni,
Capitolo 8
8
componenti e librerie
In questo capitolo viene fornita una panoramica su come creare applicazioni, librerie
e componenti.
Creazione di applicazioni
I tipi di applicazioni più comuni che si possono progettare e costruire sono:
• Applicazioni GUI
• Applicazioni per console
• Applicazioni di servizio (solo per applicazioni Windows)
• Package e DLL
Generalmente, le applicazioni GUI hanno un’interfaccia di facile impiego. Le
applicazioni per console vengono eseguite da una finestra della console. Le
applicazioni di servizio sono eseguite come servizi Windows. Questi tipi di
applicazioni vengono compilati come eseguibili con codice di avvio.
Si possono creare altri tipi di progetto, come package e DLL, che portano alla
realizzazione di package o di librerie collegabili dinamicamente. Queste applicazioni
producono un codice eseguibile senza codice di avvio. Fare riferimento al paragrafo
“Creazione di package e di DLL” a pagina 8-10.
Applicazioni GUI
Un’applicazione con interfaccia utente grafica (GUI) viene progettata utilizzando
funzionalità grafiche come finestre, menu, finestre di dialogo e altre funzionalità che
la rendono facile da usare. Quando si compila un’applicazione GUI, viene generato
un file eseguibile con codice di avvio. L’eseguibile generalmente fornisce la
funzionalità di base del programma, tanto che i programmi più semplici sono
costituiti esclusivamente da un file. È possibile estendere l’applicazione chiamando le
DLL, i package e gli altri file di supporto dall’eseguibile.
L’IDE offre due modelli di applicazione UI:
• Single document interface (SDI)
• Multiple document interface (MDI)
Oltre che con il modello di implementazione delle applicazioni, il comportamento
del progetto in fase di progettazione e di esecuzione dell’applicazione può essere
modificato tramite le opzioni di progetto dell’IDE.
Applicazioni SDI
Per creare una nuova applicazione SDI:
1 Selezionare File|New|Other per richiamare la finestra di dialogo New Items.
2 Fare clic sulla pagina Projects e fare doppio clic su SDI Application.
3 Fare clic su OK.
Per impostazione predefinita, la proprietà FormStyle dell’oggetto Form è fsNormal, in
questo modo l’IDE presuppone che tutte le nuove applicazioni siano di tipo SDI.
Applicazioni MDI
Per creare una nuova applicazione MDI:
1 Selezionare File|New|Other per richiamare la finestra di dialogo New Items.
2 Fare clic sulla pagina Projects e fare doppio clic su MDI Application.
3 Fare clic su OK.
Le applicazioni MDI richiedono una maggiore pianificazione e sono in un certo senso
più complesse da progettare di quelle SDI. Le applicazioni MDI generano finestre
figlio che risiedono all’interno della finestra client; la scheda principale contiene le
schede figlio. Per specificare se una scheda è figlio (fsMDIForm) o la scheda principale
(fsMDIChild), occorre impostare la proprietà FormStyle dell’oggetto TForm. È
consigliabile definire una classe base per le schede figlio e derivare ogni scheda figlio
da questa classe, per evitare di dover ridefinire le proprietà della scheda figlio.
Le applicazioni MDI spesso includono sul menu principale una finestra popup che
contiene elementi quali Cascade e Tile per la visualizzazione di più finestre in
modalità differenti. Quando una finestra figlio viene ridotta a icona, la sua icona è
situata nella scheda MDI genitore.
Per creare una nuova applicazione MDI senza utilizzare il wizard:
1 Creare la scheda della finestra principale o finestra MDI genitore. Impostare la sua
proprietà FormStyle a fsMDIForm.
2 Creare un menu per la finestra principale che include File|Open, File|Save e
Window che abbia gli elementi Cascade, Tile e Arrange All.
3 Creare le schede MDI figlio e impostare le loro proprietà FormStyle a fsMDIChild.
Modelli di programmazione
I modelli di programmazione sono scheletri di strutture comunemente utilizzate, che
è possibile aggiungere al codice sorgente e quindi completare. È anche possibile
utilizzare modelli di codice standard, come quelli per gli array, per le classi, per la
dichiarazioni di funzioni, nonché molte istruzioni.
È possibile anche scrivere dei modelli propri per codificare delle strutture di impiego
frequente. Ad esempio, se si desidera utilizzare nel codice un ciclo for, si può inserire
il seguente modello:
for := to do
begin
end;
Per inserire un modello di codice nel Code editor, premere Ctrl-j e selezionare il
modello di codice che si intende utilizzare. A questa raccolta è possibile aggiungere
anche dei propri modelli. Per aggiungere un modello:
1 Scegliere il comando Tools|Editor Options.
2 Fare clic sul separatore Code Insight.
3 Nei sezione Template, fare clic su Add.
4 Dopo Shortcut name scrivere un nome per il modello, immettere una breve
descrizione del nuovo modello e fare clic su OK.
5 Aggiungere il codice del modello nella casella di testo Code.
6 Fare clic su OK.
{$APPTYPE CONSOLE}
uses
SysUtils;
begin
try
raise exception.create('hi');
except
WriteLn('exception occurred');
end;
end.
Applicazioni di servizio
Le applicazioni di servizio accettano richieste dalle applicazioni client, elaborano tali
richieste e restituiscono informazioni all’applicazione client. Solitamente vengono
eseguite in background, con poca o nulla interazione con l’utente. Esempi di
applicazioni di servizio sono i server Web, i server FTP o di posta.
Per creare un’applicazione che implementi un servizio Win32:
1 Scegliere File|New|Other e fare doppio clic su Service Application nella finestra di
dialogo New Items. In questo modo si aggiunge una variabile di nome Application
al progetto, che è di tipo TServiceApplication.
private
{ Private declarations }
Stream: TMemoryStream; // Add this line here
public
function GetServiceController: PServiceController; override;
{ Public declarations }
end;
var
4 Selezionare ServerSocket 1, il componente aggiunto al passo 1. Fare doppio clic
sull’evento OnClientRead nell’Object Inspector ed aggiungere il seguente gestore di
evento:
procedure TService1.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
Buffer: PChar;
begin
Buffer := nil;
while Socket.ReceiveLength > 0 do begin
Buffer := AllocMem(Socket.ReceiveLength);
try
Socket.ReceiveBuf(Buffer^, Socket.ReceiveLength);
Stream.Write(Buffer^, StrLen(Buffer));
finally
FreeMem(Buffer);
end;
Stream.Seek(0, soFromBeginning);
Stream.SaveToFile('c:\Temp\Weblog' + IntToStr(ServiceThread.ThreadID) + '.log');
end;
end;
5 Infine, selezionare Service1 facendo clic nell’area del client della finestra (non sul
ServiceSocket). Fare doppio clic sull’evento OnExecute nell’Object Inspector ed
aggiungere il seguente gestore di evento:
procedure TService1.Service1Execute(Sender: TService);
begin
Stream := TMemoryStream.Create;
try
ServerSocket1.Port := 80; // WWW port
ServerSocket1.Active := True;
while not Terminated do begin
ServiceThread.ProcessRequests(True);
end;
ServerSocket1.Active := False;
finally
Stream.Free;
end;
Quando si scrivono le applicazioni di servizio, bisogna far attenzione a:
• Thread dei servizi
• Proprietà del nome del servizio
• Debug delle applicazioni di servizio
Proprietà di TDependency
DisplayName di TDependency è sia un nome di visualizzazione sia il nome vero e
proprio del servizio. Coincide quasi sempre con la proprietà Name di TDependency.
I package sono speciali DLL usate dalle applicazioni Delphi, dall’IDE o da entrambe.
Esistono due tipi di package: i package di esecuzione e quelli di progettazione. I
package di esecuzione forniscono funzionalità ad un programma durante il sua
funzionamento. I package di progettazione estendono la funzionalità dell’IDE
Per ulteriori informazioni sui package, consultare il Capitolo 16, “Uso di package e di
componenti”.
• Web Broker
• WebSnap
• IntraWeb
• Web Services
stand-alone oppure Apache Shared Module (DLL). Sono le stesse opzioni che
compaiono quando si creano applicazioni WebSnap e Web Service.
Per ulteriori informazioni sulla costruzione di applicazioni per server Web,
consultare il Capitolo 33, “Creazione di applicazioni server per Internet”.
dati che si aggiungono all’Object Repository per evitare conflitti di nome con altri
moduli dati presenti nel Repository, oppure con altre applicazioni che utilizzano i
moduli.
Per rinominare un modulo dati:
1 Selezionare il modulo.
2 Modificare la proprietà Name del modulo nell’Object Inspector.
Non appena la proprietà Name nell’Object Inspector non è più evidenziata, il nuovo
nome del modulo appare nella barra del titolo.
Modificando il nome di un modulo dati in progettazione se ne modifica il nome della
variabile nella sezione interface del codice. Vengono modificate anche tutte le
clausole uses che fanno riferimento al nome nelle dichiarazioni di procedura. È
necessario invece modificare manualmente qualsiasi riferimento al modulo dati nel
codice scritto in prima persona.
Per cambiare nome al file unit di un modulo dati:
1 Selezionare il file unit.
Copia di un elemento
Scegliere l’opzione Copy per fare una copia esatta dell’elemento scelto e aggiungere
la copia al progetto. Le successive modifiche apportate all’elemento nell’Object
Repository non influenzeranno la copia, come pure le modifiche apportate alla copia
non influenzeranno l’elemento originale nell’ Object Repository.
L’opzione Copy è l’unica disponibile per modelli di progetto.
Ereditare un elemento
Scegliere l’opzione Inherit per derivare una nuova classe dall’elemento scelto
nell’Object Repository e aggiungere la nuova classe al progetto. Quando si ricompila
il progetto, qualsiasi modifica apportata all’elemento nell’Object Repository si
ripercuoterà sulla classe derivata, in aggiunta alle modifiche apportate all’elemento
nel progetto. Le modifiche apportate alla classe derivata non si ripercuotono
sull’elemento condiviso dell’Object Repository.
L’opzione Inherit è disponibile per schede, finestre di dialogo e moduli dati ma non
per modelli di progetto. È l’unica opzione disponibile per riutilizzare elementi
all’interno dello stesso progetto.
Utilizzo di un elemento
Scegliere l’opzione Use quando si desidera che l’elemento scelto diventi parte del
progetto. Le modifiche apportate all’elemento nel progetto appariranno in tutti gli
altri progetti a cui è stato aggiunto l’elemento mediante le opzioni Inherit o Use.
Selezionare questa opzione con estrema attenzione.
L’opzione Use è disponibile per schede, finestre di dialogo e moduli dati.
Form), select the New Form check box. To specify the default main form for new
projects, select the Main Form check box.
4 Fare clic su OK.
Implementazione di ICustomHelpViewer
L’interfaccia ICustomHelpViewer contiene tre tipi di metodi: metodi utilizzati per
comunicare con l’Help Manager informazioni a livello di sistema (ad esempio,
informazioni non correlate a una particolare richiesta di Help); metodi relativi alla
visualizzazione dell’Help in base a una parola chiave fornita dall’Help Manager; e
metodi per la visualizzazione di un indice.
deve ovviamente essere di tipo statico, (cioè, non può cambiare durante
l’operazione dell’applicazione). I set di caratteri multibyte non sono supportati.
• ICustomHelpViewer.NotifyID(const ViewerID: Integer) viene chiamato
immediatamente dopo la registrazione in modo da fornire al visualizzatore un
cookie univoco che la identifichi. Queste informazioni devono essere memorizzate
per un successivo utilizzo; se il visualizzatore si chiude autonomamente (invece
che in risposta a una notifica da parte dell’Help Manager), deve fornire all’Help
Manager il cookie di identificazione, in modo che l’Help Manager possa rilasciare
tutti i riferimenti al visualizzatore. (Il non fornire il cookie o il fornirne uno errato,
fa sì che l’Help Manager potenzialmente rilasci i riferimenti al visualizzatore
errato.)
• ICustomHelpViewer.ShutDown viene chiamato dall’Help Manager per chiedere al
visualizzatore di Help di chiudere qualsiasi manifestazione esternamente visibile
del sistema di Help (ad esempio, delle finestre che visualizzano informazioni della
guida) senza però scaricare il visualizzatore.
• ICustomHelpViewer.SoftShutDownviene chiamato dall’Help Manager per informare
il visualizzatore di Help che il Manager sta per essere chiuso e che tutte le risorse
allocate dal visualizzatore di Help dovrebbero essere liberate. Si consiglia di
delegare a questo metodo tutte le risorse da liberare.
N I contesti numerici di aiuto sono la forma standard delle richieste di Help nelle
applicazioni eseguite in ambiente Windows che utilizzano il sistema WinHelp;
benché supportate dalla CLX, se ne sconsiglia l’utilizzo nelle applicazioni CLX
perché la maggior parte dei sistemi di Help di Linux non sono in grado di
comprenderle.
Alle implementazioni di ICustomHelpViewer viene richiesto di fornire il supporto per
richieste di aiuto in base a una parola chiave, mentre alle implementazioni
IExtendedHelpViewer viene richiesto il supporto per le richieste di aiuto in base al
contesto.
ICustomHelpViewer ha tre metodi per la gestione di aiuto in base a una parola chiave:
• UnderstandsKeyword
• GetHelpStrings
• ShowHelp
ICustomHelpViewer.UnderstandsKeyword(const HelpString: String): Integer
è il primo dei tre metodi chiamati dall’Help Manager, il quale chiamerà ogni
visualizzatore di Help registrato passandogli la stessa stringa per chiedergli se è in
grado di fornire un aiuto per quella stringa; il visualizzatore dovrebbe risponde con
un valore integer che indica quante differenti pagine della guida può visualizzare in
risposta a quella richiesta di Help. Per determinare tale valore, il visualizzatore può
utilizzare un qualsiasi metodo- all’interno dell’IDE il visualizzatore HyperHelp
gestisce il proprio indice e lo utilizza per la ricerca. Se il visualizzatore non è in grado
di fornire un aiuto per questa parola chiave dovrebbe restituire zero. I numeri
negativi vengono interpretati come se fossero zero, ma questo comportamento non è
garantito nelle versioni successive.
ICustomHelpViewer.GetHelpStrings(const HelpString: String): TStringList
viene chiamato dall’Help Manager nel caso vi sia più di un visualizzatore in grado di
fornire un aiuto su un argomento. Il visualizzatore dovrebbe restituire uno
TStringList liberato dall’Help Manager. Le stringhe nella lista restituita dovrebbero
corrispondere alle pagine disponibili per quella parola chiave, ma le caratteristiche di
quella mappatura possono essere determinate dal visualizzatore. Nel caso del
visualizzatore WinHelp in Windows e del visualizzatore HyperHelp in Linux,
l’elenco di stringhe contiene sempre esattamente una voce. HyperHelp fornisce una
propria indicizzazione e la sua duplicazione in un’altra posizione produrrebbe una
duplicazione senza puntatore. Nel caso del visualizzatore Man page (Linux), la lista
di stringhe è formata da stringhe multiple, una per ogni sezione del manuale che
contiene una pagina per quella parola chiave.
ICustomHelpViewer.ShowHelp(const HelpString: String)
viene chiamato dall’Help Manager nel caso abbia bisogno che il visualizzatore di
Help visualizzi un aiuto per una particolare parola chiave. Questa è l’ultima
chiamata a metodo dell’operazione; il sistema garantisce che non sarà mai chiamato a
meno che prima non venga chiamato il metodo UnderstandsKeyword.
Implementazione IExtendedHelpViewer
ICustomHelpViewer fornisce solo un supporto diretto per Help basati su parole
chiave. Alcuni sistemi di Help (specialmente WinHelp) funzionano associando
numeri (conosciuti come ID di contesto) a parole chiave in un modo interno al
sistema di Help e quindi non visibile all’applicazione. Tali sistemi richiedono che
l’applicazione supporti l’Help in base al contesto, vale a dire l’applicazione richiama
il sistema Help con quel contesto, invece che con una stringa, e il sistema di Help
traduca tale numero.
Le applicazioni possono dialogare con sistemi che richiedono un Help in base al
contesto estendendo l’oggetto che implementa ICustomHelpViewer in modo che
implementi anche IExtendedHelpViewer. IExtendedHelpViewer fornisce anche un
supporto per dialogare con sistemi di Help che permettono di passare direttamente
ad argomenti di livello più alto invece di utilizzare ricerche per parole chiave. Il
visualizzatore natico WinHelp compie l’operazione automaticamente.
IExtendedHelpViewer espone quattro funzioni. Due di esse - UnderstandsContext e
DisplayHelpByContext - sono utilizzate per supportare gli Help in base al contesto; le
altre due - UnderstandsTopic and DisplayTopic - sono utilizzate per supportare gli
argomenti.
Quando un utente dell’applicazione preme il tasto F1, l’Help Manager chiama
Implementazione IHelpSelector
IHelpSelector viene utilizzato in combinazione con ICustomHelpViewer. Quando
esistono più visualizzatori di Help che sostengono di essere in grado di fornire un
supporto per una certa parola chiave, per un contesto o per un determinato
argomento, o di essere in grado di fornire un indice, l’Help Manager deve effettuare
una scelta. Nel caso di contesti o di argomenti, l’Help Manager seleziona sempre il
primo visualizzatore di Help che sostiene di essere in grado di fornire il supporto.
Nel caso delle parole chiave o dell’indice, per impostazione predefinita l’Help
Manager selezionerà il primo visualizzatore Help. Questo comportamento può
essere ridefinito da un’applicazione.
Per ridefinire la decisione dell’Help Manager in questi casi, l’applicazione deve
registrare una classe che fornisca un’implementazione dell’interfaccia
IHelpSelector.IHelpSelector esporta due funzioni: SelectKeyword, e TableOfContents.
Entrambe accettano come argomento un TStrings contenente, ad uno ad uno, o le
possibili corrispondenze con la parola chiave o i nomi dei visualizzatori che
sostengono di essere in grado di fornire un indice. Chi implementa la funzione deve
restituire l’indice (in TStringList) che rappresenta la stringa selezionata, TStringList
viene quindi liberata dall’Help Manager.
Tutte e quattro le funzioni prendono i dati che vengono loro passati e li inoltrano
tramite un membro dati di TApplication che rappresenta il sistema di Help. Quel
membro dati è direttamente accessibile attraverso la proprietà HelpSystem a sola
lettura.
all’applicazione di dialogare con l’Help Manager, mentre l’altra viene utilizzata per
consentire ai visualizzatori di Help di dialogare con l’Help Manager.
Utilizzo di IHelpSystem
IHelpSystem permette ad un’applicazioni di fare tre cose:
• Fornisce all’Help Manager le informazioni sui percorsi.
• Fornisce un nuovo selettore di Help.
• Chiede all’Help Manager di visualizzare l’Help.
È importante fornire le informazioni di percorso, in quanto l’HelpManager è
indipendente dalla piattaforma e Help è indipendente dal sistema, e quindi non è in
grado di accertare la locazione dei file di Help. Se un’applicazione si aspetta che
l’Help venga fornito da un sistema di Help esterno che non è capace di accertare le
locazioni del file, essa deve fornire queste informazioni tramite il metodo
ProvideHelpPath di IHelpSystem, che permette alle informazioni di divenire disponibili
tramite il metodo GetHelpPath di IHelpManager. (Queste informazioni si propagano
all’esterno solo se il visualizzatore dell’Help lo richiede).
L’assegnazione di un selettore di Help consente all’Help Manager di delegare il
processo di decisione in quei casi in cui più sistemi di Help esterni possono fornire
un help per la stessa parola chiave. Per ulteriori informazioni, vedere la sezione
“Implementazione IHelpSelector” a pagina 8-29.
IHelpSystem esporta quattro procedure e una funzione per richiedere all’Help
Manager di visualizzare l’help:
• ShowHelp
• ShowContextHelp
• ShowTopicHelp
• ShowTableOfContents
• Hook
Hook è destinata esclusivamente alla compatibilità con WinHelp e non dovrebbe
essere utilizzata in un’applicazione CLX; permette l’elaborazione di messaggi
WM_HELP che non possono essere mappati direttamente su richieste di Help basate
su parola chiave, su contesto o su argomento. Ognuno degli altri metodi richiede due
argomenti: la parola chiave, l’ID di contesto o l’argomento per cui si chiede aiuto e il
file di Help in cui ci si aspetta di trovare l’aiuto.
Di solito, a meno che non si stia richiedendo aiuto in base a un argomento, è
ugualmente efficiente e molto più chiaro passare le richieste di aiuto all’Help
Manager tramite il metodo InvokeHelp del controllo.
Aggiunta di schede
Per aggiungere una scheda al progetto, occorre selezionare File|New|Form. È
possibile vedere tutte le schede del progetto e le loro unit associate elencate nel
Project Manager (View|Project Manager) e, scegliendo il comando View|Forms, è
possibile visualizzare un elenco delle schede non associate.
usarle. Per esempio, una finestra di dialogo ha bisogno di trovarsi in memoria solo
durante il periodo in cui un utente la utilizza.
Per creare una scheda in una fase diversa durante l’esecuzione usando l’IDE, occorre:
1 Selezionare File|New Form dal menu principale per visualizzare la nuova scheda.
2 Rimuovere la scheda dall’elenco Auto-create forms della pagina Project|Options|
Forms.
Questa operazione rimuove la chiamata al punto di ingresso alla scheda. In
alternativa, si può rimuovere manualmente la seguente riga dal punto d’ingresso
principale del programma:
Application.CreateForm(TResultsForm, ResultsForm);
3 Chiamare la scheda nel momento desiderato, usando il metodo Show della scheda,
se essa è non modale, o il metodo ShowModal, se è modale.
Un gestore di evento per la scheda principale deve creare un’istanza della scheda
risultato e distruggerla. Un modo per chiamare la scheda risultato consiste nell’usare
la variabile globale nel modo seguente. Si noti che ResultsForm è una scheda modale,
quindi il gestore usa il metodo ShowModal.
procedure TMainForm.Button1Click(Sender: TObject);
begin
ResultsForm := TResultForm.Create(self);
try
ResultsForm.ShowModal;
finally
ResultsForm.Free;
end;
end;
Nell’esempio precedente, si noti l’uso di try..finally. L’inserimento della riga
ResultsForm.Free; nella clausula finally assicura che la memoria per la scheda venga
liberata anche se la scheda solleva un eccezione.
Il gestore di evento dell’esempio cancella la scheda dopo averla chiusa, in modo che
non occorrerà ricrearla se occorrerà usare ResultsForm in qualche altro punto
dell’applicazione. Se la scheda fosse visualizzata usando Show, non potrebbe essere
cancellata all’interno del gestore di evento, perché Show termina mentre la scheda è
ancora aperta.
ResultsLabel: TLabel;
OKButton: TButton;
procedure OKButtonClick(Sender: TObject);
private
public
constructor CreateWithButton(whichButton: Integer; Owner: TComponent);
end;
Ecco il costruttore codificato manualmente che passa l’ulteriore argomento,
whichButton. Questo costruttore usa il parametro whichButton per impostare la
proprietà Caption di un controllo Label sulla scheda.
constructor CreateWithButton(whichButton: Integer; Owner: TComponent);
begin
inherited Create(Owner);
case whichButton of
1: ResultsLabel.Caption := 'You picked the first button.';
2: ResultsLabel.Caption := 'You picked the second button.';
3: ResultsLabel.Caption := 'You picked the third button.';
end;
end;
Quando si crea un’istanza di una scheda con più costruttori è possibile selezionare il
costruttore più adatto allo scopo. Per esempio, il seguente gestore OnClick per un
pulsante su una scheda crea un’istanza di TResultsForm, che usa il parametro
ulteriore:
procedure TMainForm.SecondButtonClick(Sender: TObject);
var
rf: TResultsForm;
begin
rf := TResultsForm.CreateWithButton(2, self);
rf.ShowModal;
rf.Free;
end;
in una proprietà di nome CurrentColor ogni volta che un utente seleziona un nuovo
colore. La dichiarazione di classe per la scheda è la seguente:
TColorForm = class(TForm)
ColorListBox:TListBox;
procedure ColorListBoxClick(Sender: TObject);
private
FColor:String;
public
property CurColor:String read FColor write FColor;
end;
Il gestore di evento OnClick per la casella di riepilogo, ColorListBoxClick, imposta il
valore della proprietà CurrentColor ogni volta che viene selezionato un nuovo
elemento nella casella di riepilogo. Il gestore di evento acquisisce la stringa dalla
casella di riepilogo contenente il nome del colore e la assegna a CurrentColor. La
proprietà CurrentColor usa la funzione setter, SetColor, per memorizzare il valore
effettivo per la proprietà nel membro dati private FColor:
procedure TColorForm.ColorListBoxClick(Sender: TObject);
var
Index: Integer;
begin
Index := ColorListBox.ItemIndex;
if Index >= 0 then
CurrentColor := ColorListBox.Items[Index]
else
CurrentColor := '';
end;
A questo punto, si supponga che un’altra scheda all’interno dell’applicazione,
chiamata ResultsForm, debba scoprire quale colore è al momento selezionato su
ColorForm ogni volta che si fa clic su un pulsante (chiamato UpdateButton) di
ResultsForm. Il gestore di evento OnClick per UpdateButton potrebbe avere il seguente
formato:
procedure TResultForm.UpdateButtonClick(Sender: TObject);
var
MainColor: String;
begin
if Assigned(ColorForm) then
begin
MainColor := ColorForm.CurrentColor;
{do something with the string MainColor}
end;
end;
Per prima cosa il gestore di evento verifica che ColorForm esista utilizzando la
funzione Assigned. Quindi, riceve il valore della proprietà CurrentColor di ColorForm.
In caso contrario, se ColorForm avesse una funzione pubblica chiamata GetColor,
un’altra scheda potrebbe acquisire il colore attivo senza usare la proprietà
CurrentColor (per esempio, MainColor := ColorForm.GetColor;). Infatti, non esiste un
modo per impedire che un’altra scheda riceva il colore di ColorForm al momento
selezionato contrassegnando direttamente le selezione della casella di riepilogo:
with ColorForm.ColorListBox do
MainColor := Items[ItemIndex];
Tuttavia, l’uso di una proprietà rende l’interfaccia per ColorForm molto chiara e
semplice. Tutto ciò che una scheda ha bisogno di sapere su ColorForm è come
controllare il valore di CurrentColor.
N Per usare il costruttore definito dall’utente sopra riportato, la scheda deve essere
creata esplicitamente. Essa non può essere creata automaticamente quando
l’applicazione è avviata. Per informazioni dettagliate, consultare il paragrafo
“Controllo delle schede in memoria” a pagina 9-6.
Nell’applicazione, l’utente seleziona un colore dalla casella di riepilogo e preme
SelectButton per salvare la scelta e chiudere la scheda. Il gestore di evento OnClick per
SelectButton potrebbe avere questa forma:
procedure TColorForm.SelectButtonClick(Sender: TObject);
begin
with ColorListBox do
if ItemIndex >= 0 then
String(FColor^) := ColorListBox.Items[ItemIndex];
end;
Close;
end;
Notare che il gestore di evento memorizza il nome del colore selezionato nella stringa
a cui fa riferimento il puntatore passato al costruttore.
Per usare efficacemente ColorForm, la scheda chiamante deve passare il costruttore a
un puntatore a una stringa esistente. Per esempio, si supponga che ColorForm è stata
istanziata da una scheda chiamata ResultsForm in risposta a un clic su un pulsante
chiamato UpdateButton di ResultsForm. Il gestore di evento dovrebbe essere simile al
seguente codice:
procedure TResultsForm.UpdateButtonClick(Sender: TObject);
var
MainColor: String;
begin
GetColor(Addr(MainColor));
if MainColor <> '' then
{do something with the MainColor string}
else
{do something else because no color was picked}
end;
necessità. Tenere ben presente che occorre sempre fornire un modo per consentire
alla scheda chiamante di sapere se la scheda modale è stata chiusa senza apportare
modifiche o effettuare selezioni (con MainColor impostato, per impostazione
predefinita, a una stringa vuota).
Creazione di frame
Per creare un frame vuoto, scegliere il comando File|New|Frame oppure scegliere
File|New|Other e fare doppio clic su Frame. A questo punto è possibile trascinare
sul nuovo frame altri componenti (inclusi altri frame.
Di solito è buona norma–anche se non strettamente necessario–salvare i frame come
parte di un progetto. Se si vuole creare un progetto che contenga solo frame e
N Quando si salvano i frame, è bene evitare l’uso dei nomi predefiniti, quali Unit1,
Project1 e così via, in quanto molto probabilmente provocheranno conflitti quando si
cercherà di utilizzare il frame in un secondo tempo.
In fase di progetto, è possibile visualizzare tutti i frame inclusi nel progetto corrente
scegliendo il comando View|Forms e selezionando un frame. Come con le schede e i
moduli dati, è possibile passare dalla visualizzazione grafica nel Form Designer al
file .form del frame, e viceversa, facendo clic destro e scegliendo il comando View as
Form oppure View as Text.
si cambiasse idea rispetto alla disposizione dei controlli, si dovrebbe tornare indietro
e modificare manualmente tutti i progetti in cui è stato collocato il modello.
Invece, se si collocassero i componenti database in un frame, le eventuali modifiche
dovrebbero essere apportate in un solo posto; le modifiche al frame originale si
propagano ai discendenti in esso contenuti al momento della ricompilazione del
progetto. Allo stesso tempo, si è liberi di modificare qualunque frame incluso senza
toccare il frame originale o altri suoi discendenti incorporati. L’unica limitazione
nella modifica di frame incorporati consiste nel non poter aggiungere ad essi altri
componenti.
Figura 9.1 Un frame con controlli data-aware e un componente datasource
Condivisione di frame
È possibile condividere un frame con altri sviluppatori in due modi:
• Aggiungendo il frame all’ Object Repository.
• Distribuendo i file unit (.pas) e i file scheda (.dfm o .xfm).
Per aggiungere un frame al Repository, aprire un qualsiasi progetto contenente il
frame, fare clic destro in Form Designer e scegliere il comando Add to Repository.
Per maggiori informazioni, consultare “Utilizzo dell’Object Repository” a
pagina 8-21.
Se si distribuiscono i file unit e scheda ad altri sviluppatori, essi potranno aprirli e
aggiungerli alla Component palette. Se il frame incorpora altri frame dovranno aprire
il frame come parte di un progetto.
N Per applicazioni CLX, è possibile utilizzare le finestre di dialogo fornite con CLX
nella unit QDialogs. Per i sistemi operativi che hanno tipi di finestra di dialogo native
per le comuni attività, come l’apertura o il salvataggio dei file oppure per la modifica
di font o colore, è possibile utilizzare la proprietà UseNativeDialog . Impostare
UseNativeDialog a True se l’applicazione sarà eseguirà in tale ambiente e se si desidera
che utilizzi le finestre di dialogo native invece delle finestre di dialogo Qt.
• Client: Uno o più client utilizzano l’azione. Il client rappresenta molto spesso una
voce di menu o un pulsante (ad esempio, TToolButton, TSpeedButton, TMenuItem,
TButton, TCheckBox, TRadioButton, e così via). Le azioni possono risiedere anche in
componenti ActionBand come TActionMainMenuBar e TActionToolBar. Quando il
client riceve un comando dell’utente (come il clic del mouse), avvia un’azione
associata. Di solito, l’evento OnClick di un client è associato all’evento OnExecute
della sua azione.
• Destinazione: L’azione agisce in base alla destinazione. Di solito la destinazione è
un controllo, come un campo memo o un controllo dati. Gli scrittori di componenti
possono creare azioni specifiche per le necessità dei controlli che essi progettano e
utilizzano e quindi assemblare quelle unit per creare applicazioni più modulari.
Non tutte le azioni utilizzano una destinazione. Ad esempio, le azioni Help
standard ignorano la destinazione e avviano semplicemente il sistema di aiuto.
Una destinazione può anche essere un componente. Ad esempio, i controlli per
dati cambiano la destinazione in un dataset associato.
Il client influisce sull’azione–l’azione risponde quando un client stimola l’azione.
L’azione influisce anche sul client–le proprietà dell’azione aggiornano
dinamicamente le proprietà del client. Ad esempio, se in fase di esecuzione un’azione
è disabilitata (impostando la sua proprietà Enabled a False), ogni client di quell’azione
è disabilitato e viene visualizzato come disabilitato.
È possibile aggiungere, cancellare e riordinare le azioni utilizzando l’Action Manager
o l’Action List editor (che vengono visualizzati facendo doppio clic su un oggetto
della lista di azioni, TActionList). Queste azioni saranno connesse successivamente a
controlli client.
• Fare clic sulla freccia verso il basso accanto al pulsante New Action (il pulsante
più a sinistra posto nell’angolo in alto a destra della pagina Actions, come
mostrato nella Figura 9.2) e selezionare “New Action” oppure “New Standard
Action”. Viene mostrata una vista ad albero. Aggiungere al pannello delle
azioni dell’Action Manager una o più azioni o categorie di azioni. L’Action
Manager aggiungerà le azioni alla proprie liste di azioni.
Figura 9.2 Action Manager editor
banner, l’immagine completa viene collocata alla sinistra (blLeftBanner) o alla destra
(blRightBanner) dell’elemento. È necessario accertarsi che le dimensioni siano
corrette in quanto non viene espando o ristretto in modo da adattarlo all’area.
Per modificare lo sfondo di una banda di azioni (cioè, di un menu principale o di una
barra strumenti), selezionare la banda di azioni e scegliere il TActionClientBar
utilizzando l’Action Band collection editor. È possibile impostare proprietà
Background e BackgroundLayout per specificare un colore, un motivo o una bitmap da
utilizzare nell’intera barra strumenti o nel menu.
in modo da dare all’applicazione un look and feel globale. Oltre allo stile standard,
l’applicazione può utilizzare lo stile di Windows XP, Encarta™ oppure uno stile
personalizzato utilizzando uno schema coordinato di colori. Per dare all’applicazione
un’aspetto coerente, l’IDE utilizza le mappe di colori.
Una mappa di colori può essere semplice, limitandosi ad aggiungere i colori
appropriati ai menu e alle barre strumenti esistenti. Oppure, una mappa di colori può
essere complessa, alterando tutti i numerosi piccoli dettagli che compongono
l’aspetto complessivo di un menu o di una barra strumenti, inclusi anche i bordi del
più piccolo pulsante o l’ombreggiatura dei menu. La mappa di colori di XP, ad
esempio, ha molti piccoli dettagli per le classi menu e barre strumenti. L’IDE gestisce
i dettagli in automatico, utilizzando le mappe di colori appropriate.
Per impostazione predefinita, la libreria di componenti utilizza lo stile XP. Per
selezionare in modo centralizzato uno stile alternativo per tutti i menu e le barre
strumenti dell’applicazione, utilizzare la proprietà Style del componente
ActionManager.
1 Dalla pagina Additional della Component palette, trascinare su una scheda un
componente ActionManager.
2 Nell’Object Inspector, selezionare la proprietà Style. È possibile scegliere tra vari
stili differenti.
3 Una volta selezionato uno stile, i menu e le barre strumenti dell’applicazione
assumeranno l’aspetto della nuova mappa di colori.
È possibile personalizzare l’aspetto di uno stile mediante i componenti colormap. Per
personalizzare l’aspetto di una mappa di colori:
1 Dalla pagina Additional della Component palette, trascinare su una scheda il
componente colormap appropriato (ad esempio, XPColorMap o
StandardColorMap). Nell’Object Inspector, si vedranno molte proprietà atte a
modificare l’aspetto, con numerosi elenchi a discesa da cui selezionare valori
differenti da quelli predefiniti.
2 Cambiare ogni proprietà ColorMap del menu o della bara strumenti in modo che
punti all’oggetto colormap che è stato collocato sulla scheda.
3 Nell’Object Inspector, modificare le proprietà del componente colormap in modo
da modificare a proprio piacimento l’aspetto delle barre strumenti e dei menu.
Tabella 9.2 Valori predefiniti della proprietà PrioritySchedule del gestore di azioni
Numero di sessioni in cui è
stato utilizzato un elemento Numero di sessioni per cui un elemento rimarrà visibile
di una banda di azioni dopo il suo ultimo utilizzo
0, 1 3
2 6
3 9
4, 5 12
6-8 17
9-13 23
14-24 29
25 o più 31
corrispondono alle proprietà e agli eventi dei suoi controlli client. Le proprietà
corrispondenti del client hanno di solito, ma non necessariamente, lo stesso nome
della proprietà client corrispondente. Ad esempio, la proprietà Enabled di
un’azione corrisponde alla proprietà Enabled di un TToolButton. Tuttavia, la
proprietà Checked di un’azione corrisponde alla proprietà Down di un TToolButton.
4 Se si utilizzano le azioni predefinite, l’azione include una risposta standard che si
verifica automaticamente. Se si sta creando un’azione personale, è necessario
scrivere un gestore di evento che definisca come risponde l’azione quando viene
scatenata. Per i dettagli, consultare “Cosa accade quando si scatena un’azione” a
pagina 9-28.
5 Collegare le azioni nella lista di azioni ai client che ne hanno bisogno:
• Fare clic sul controllo (come un pulsante o un voce di menu) sulla scheda o sul
modulo dati. NellObject Inspector, la proprietà Action elenca le azioni
disponibili.
• Selezionare quella che si desidera.
Le azioni standard, come TEditDelete o TDataSetPost, eseguono tutte l’azione che ci si
aspetta. Se occorre, è possibile consultare la Guida di riferimento in linea per i
dettagli sulle modalità di funzionamento di tutte le azioni standard. Se si dovranno
scrivere azioni personalizzate, sarà necessario approfondire ciò che avviene quando
l’azione viene scatenata.
azione predefinite e le azioni standard associate. Queste sono azioni già incluse in
Delphi e sono oggetti che eseguono automaticamente determinate azioni. Le azioni
predefinite sono organizzate nelle seguenti classi:
Questo capitolo spiega come usare il Menu Designer per progettare barre di menu e
menu (locali) a comparsa. Esso tratta i seguenti modi di lavorare con i menu in fase di
progettazione e in fase di esecuzione:
• Apertura di Menu Designer.
• Costruzione di menu.
• Editing delle voci di menu nell’Object Inspector.
• Uso del menu contestuale Menu Designer.
• Uso dei modelli di menu.
• Salvataggio di un menu come modello.
• Aggiunta di immagini alle voci di menu.
Figura 9.3 Terminologia dei menu
Voci di menu sulla barra dei menu
Acceleratore di
tastiera Voci di menu in un elenco di menu
Scorciatoia di tastiera
Separatore
Per informazioni su come agganciare parti del menu al codice che li esegue quando
sono selezionate, vedere “Associazione di eventi di menu a gestori di evento” a
pagina 6-6.
Componente MainMenu
Componente PopupMenu
Un componente MainMenu crea un menu che viene collegato alla barra del titolo
della scheda. Un componente PopupMenu crea un menu che appare quando l’utente
fa clic con il tasto destro nella scheda. I menu a comparsa non hanno una barra di
menu.
Per aprire il Menu Designer, selezionare un componente menu sulla scheda, e quindi
scegliere:
• Fare doppio clic sul componente menu.
oppure
• Dalla pagina Properties dell’Object Inspector, selezionare la proprietà Items, e
quindi fare doppio clic [Menu] nella colonna Value, oppure fare clic sul pulsante
ellissi (...).
Segnaposto per la
voce di menu
Costruzione di menu
Si aggiunga un componente menu alla scheda, o alle schede, per ogni menu da
includere nell’applicazione. È possibile costruire ciascuna struttura di menu
completamente ex-novo, o iniziare da uno dei modelli di menu predefiniti.
Questa sezione illustra i principi per la creazioni di un menu in fase di progettazione.
Per ulteriori informazioni sui modelli di menu, consultare “Uso dei modelli di menu”
a pagina 9-43.
N Se vengono immessi nella proprietà Caption caratteri non validi per gli
identificatori di Delphi, il programma modificherà conseguentemente la proprietà
Name. Per esempio, se si desidera che il caption inizi con un numero, Delphi fa
precedere il numero con un carattere per derivare la proprietà Name.
La seguente tabella mostra alcuni esempi di ciò, presupponendo che tutte le voci
di menu mostrate appaiano nella stessa barra di menu.
Come il componente menu, Delphi aggiunge qualsiasi nome di voce di menu alla
dichiarazione di tipo della scheda, e quei nomi quindi appaiono nella Component
list.
Usare i tasti cursore per spostarsi dalla barra dei menu nel menu, e quindi
spostarsi tra le voci dell’elenco; premere Invio per completare un’azione. Per
ritornare alla barra dei menu, premere Esc.
Per inserire una nuova voce di menu vuota:
1 Collocare il cursore su una voce di menu.
2 Premere Ins.
Le voci di menu vengono inserite a sinistra della voce selezionata sulla barra dei
menu, e sopra la voce selezionata nell’elenco del menu.
Per cancellare una voce di menu o comando:
1 Collocare il cursore sulla voce di menu da cancellare.
2 Premere Del.
N Non è possibile cancellare il placeholder predefinito che appare sotto l’ultima voce
immessa nell’elenco del menu, o vicino all’ultima voce sulla barra dei menu. Questo
placeholder non appare nel menu in fase di esecuzione.
Figura 9.6 Aggiunta di voci di menu a un menu principale
Le funzionalità WYSIWYG del Menu Designer mostrano le
voci di menu man mano che il menu viene creato. Barra del titolo (mostra la proprietà
Name per un componente Menu)
Barra del menu
Segnaposto per
la voce di menu
Creazione di sottomenu
Molti menu di applicazioni contengono elenchi a discesa che appaiono vicino a una
voce di menu per fornire ulteriori comandi collegati. Tali elenchi vengono indicati da
una freccia a destra della voce di menu. Delphi supporta tutti i livelli di sottomenu
desiderati.
Organizzando la struttura dei menu in questo modo, si può salvare lo spazio
verticale dello schermo. Tuttavia, per progettazioni ottimali forse è meglio non usare
più di due o tre livelli nella progettazione dell’interfaccia. (Per i menu popup,
potrebbe essere opportuno usare un solo sottomenu.)
Voci di menu in
una lista di menu
Voci di menu
annidate
2 Rilasciare il pulsante del mouse per abbandonare la voce di menu nella nuova
locazione.
Per spostare una voce in un elenco di menu:
1 Trascinare la voce lungo la barra dei menu finché la punta della freccia del cursore
di trascinamento punta al nuovo menu.
Questo obbliga il menu ad aprirsi, consentendo di trascinare la voce nella sua
nuova locazione.
2 Trascinare la voce di menu nell’elenco, rilasciando il pulsante del mouse per
abbandonare la voce di menu nella nuova locazione.
N Usare immagini 16 per 16 pixel per una visualizzazione corretta nel menu. Anche se è
possibile usare altre dimensioni, quando si usano immagini più grandi o più piccole
potrebbero nascere problemi di allineamento e di coerenza.
nella scheda in fase di progettazione, ma ciò non succede per gli stessi menu a
comparsa. Usare il Menu Designer per visualizzare un menu a comparsa in fase di
progettazione.)
Per visualizzare il menu:
1 Se la scheda è visibile, fare clic sulla scheda, o dal menu View, scegliere la scheda
di cui si vuole visualizzare il menu.
2 Se la scheda ha più di un menu, selezionare il menu desiderato dall’elenco a
discesa della proprietà Menu della scheda.
Il menu appare nella scheda esattamente come apparirà quando il programma
viene eseguito.
Questa finestra di dialogo elenca tutti i menu associati alla scheda il cui menu è
attualmente aperto nel Menu Designer.
2 Dall’elenco della finestra di dialogo Select Menu, scegliere il menu da visualizzare
o modificare.
3 Nella casella di modifica Template Description, scrivere una breve descrizione per
questo menu, e quindi scegliere OK.
La finestra di dialogo Save Template si chiude, salvando il progetto del menu e
ritornando alla finestra Menu Designer.
Convenzioni per l’assegnazione dei nomi delle voci di menu e dei gestori di
evento di un modello
Quando si salva un menu come modello, Delphi non salva la sua proprietà Name,
poiché ogni menu deve avere un nome caratteristico all’interno del campo d’azione
del suo proprietario (la scheda). Tuttavia, quando in una scheda viene inserito il
menu come modello usando il Menu Designer, allora Delphi genera nuovi nomi per
il menu stesso e per tutte le sue voci.
Per esempio, si supponga di salvare un menu File come modello. Nel menu originale,
questo menu è stato chiamato MyFile. Se tale menu viene inserito come modello in un
nuovo menu, Delphi gli assegna il nome File1. Se il menu viene inserito in un menu
con una voce di menu chiamata File1, Delphi gli assegna il nome File2.
Delphi non salva neanche tutti i gestori di evento OnClick associata a un menu
salvato come modello, poiché non c’è alcun modo per verificare se il codice è valido
nella nuova scheda. Quando viene generato un nuovo gestore di evento per la voce
di menu di un modello, Delphi genera ancora il nome del gestore di evento. È
possibile associare facilmente le voci del modello di menu ai gestori di evento
OnClick esistenti nella scheda.
Per maggiori informazioni, vedere “Associazione di eventi di menu a gestori di
evento” a pagina 6-6.
N Se il file risorsa contiene più di un menu, occorre prima salvare ciascun menu come
un file risorsa distinto prima di importarlo.
Per assegnare immagini alle singole bande, selezionare la coolbar e fare doppio clic
sulla proprietà Bands nell’Object Inspector. Quindi selezionare una banda e assegnare
un valore alla sua proprietà ImageIndex.
Risposta ai clic
Quando l’utente fa clic su un controllo, come un pulsante su una barra strumenti,
l’applicazione genera un evento OnClick a cui è possibile rispondere con un gestore
di evento. Poiché OnClick è l’evento predefinito dei pulsanti, è possibile generare uno
scheletro di gestore di evento facendo doppio clic sul pulsante in fase di
progettazione. Per informazioni di carattere generale sugli eventi ed i gestori di
evento, vedere “Operazioni con eventi e gestori di evento” a pagina 6-3 e
“Generazione di un gestore per l’evento predefinito di un componente” a pagina 6-4
Programmi dimostrativi
Per esempi di applicazioni Windows che utilizzano azioni, liste di azioni, menu e
barre strumenti, fare riferimento a Program Files\Borland\Delphi7\Demos\
RichEdit. Inoltre, Application wizard (pagina File|New|Other Projects), MDI
Application, SDI Application e Winx Logo Applications possono utilizzare gli oggetti
action e action list. Per esempi di applicazioni multipiattaforma, fare riferimento a
Demos\CLX.
10
Tipi di controlli
Capitolo 10
Controlli di testo
Molte applicazioni utilizzano controlli di testo per mostrare il testo all’utente. È
possibile utilizzare:
• Controlli di editing, che permettono all’utente di aggiungere testo.
Utilizzare questo
componente: Per consentire all’utente di:
TEdit Modificare una singola riga di testo.
TMemo Modificare più righe di testo.
TMaskEdit Immettere un testo in modo conforme a un particolare formato, come un
codice postale oppure un numero di telefono.
TRichEdit Modificare più righe di testo utilizzando il formato rich text (solo per la
VCL).
Controlli di editing
I controlli di editing mostrano del testo all’utente e gli consentono di immettere del
testo. Il tipo di controllo utilizzato a questo scopo dipende dalle dimensioni e dal
formato delle informazioni.
TEdit e TMaskEdit sono semplici controlli di testo che includono una casella di
modifica per una singola linea di testo in cui è possibile inserire informazioni.
Quando la casella di modifica riceve il fuoco, viene visualizzato un punto di
inserimento lampeggiante.
È possibile includere del testo nella casella di modifica assegnando un valore di
stringa alla proprietà Text. L’aspetto del testo nella casella di modifica viene
controllato assegnando dei valori alla proprietà Font. È possibile specificare il tipo di
carattere, le dimensioni, il colore e gli attributi del carattere. Gli attributi influiscono
su tutto il testo nella casella di modifica e non possono essere applicati a singoli
caratteri.
Una casella di modifica può essere progettata in modo che modifichi le proprie
dimensioni a seconda delle dimensioni del font utilizzato. L’operazione è possibile
impostando la proprietà AutoSize a True. È possibile limitare il numero di caratteri
che una casella di modifica può contenere assegnando un valore alla proprietà
MaxLength.
TMaskEdit è uno speciale controllo per l’editing che convalida il testo immesso a
fronte di una maschera che codifica i possibili formati validi che un testo può
assumere. La maschera può anche formattare il testo che viene mostrato all’utente.
TMemo e TRichEdit permettono all’utente di aggiungere diverse righe di testo.
Utilizzare questo
componente: Quando si vuole che l’utente:
TTextBrowser Visualizzi un file di testo o una semplice pagina HTML che gli utenti
possono scorrere.
TTextViewer Visualizzi un file di testo o una semplice pagina HTML. Gli utenti
possono scorrere la pagina o fare clic sui link per vedere altre pagine e
altre immagini.
TLCDNumber Visualizzi le informazioni numeriche in una scheda di visualizzazione
digitale.
TTextViewer agisce come un semplice visualizzatore in modo che gli utenti possano
leggere e scorrere documenti. Con TTextBrowser, gli utenti possono anche fare clic sui
collegamenti per navigare ad altri documenti e ad altre parti dello stesso documento.
I documenti visitati sono memorizzati in una cronistoria, che può essere percorsa
utilizzando i metodi Backward, Forward e Home. TTextViewer e TTextBrowser sono
utilizzati per visualizzare testo basato su HTML o per implementare un sistema di
Guida basato su HTML.
Oltre alle stesse proprietà di TtextViewer, TTextBrowser ha anche la proprietà Factory.
Factory determina l’oggetto factory MIME utilizzato per determinare i tipi di file per
le immagini incorporate. Ad esempio, è possibile associare le estensioni dei nome di
file—come .txt, .html e .xml—con i tipi MIME e fare in modo che factory carichi
questi dati nel controllo.
Utilizzare la proprietà FileName per aggiungere un file di testo, come .html, che sarà
visualizzato nel controllo in esecuzione.
Per vedere un applicazione che utilizza il controllo text browser, vedere ..\Delphi7\
Demos\Clx\TextBrowser.
Etichette
Le etichette visualizzano il testo e sono solitamente posizionate vicino ad altri
controlli.
Utilizzare questo
componente: Quando si vuole che l’utente:
TLabel Visualizzi un testo su di un controllo
senza finestra.
TStaticText Visualizzi il testo su di un controllo con
finestra.
Utilizzare questo
componente: Per consentire all’utente di:
TScrollBar Selezionare valori in un intervallo continuo
TTrackBar Selezionare valori in un intervallo continuo (impatto visivo più efficace
rispetto a una barra di scorrimento)
TUpDown Selezionare un valore da un controllo selettore associato a un compo-
nente di modifica (solo applicazioni VCL)
THotKey Immettere sequenze di tastiera con Ctrl/Shift/Alt (solo applicazioni VCL)
TSpinEdit Selezionare un valore da un widget con casella di selezione
(solo applicazioni CLX)
Barre di scorrimento
Il componente scrollbar crea una barra di scorrimento che è possibile utilizzare per
scorrere i contenuti di una finestra, di una scheda o di un altro controllo. Nel gestore
di evento di OnScroll viene scritto il codice che determina come si comporta il
controllo quando l’utente sposta il cursore della barra di scorrimento.
Il componente scrollbar non è utilizzato molto spesso, perché molti componenti
visuali includono proprie barre di scorrimento e non richiedono scrittura di codice
aggiuntivo. Per esempio, TForm ha le proprietà VertScrollBar e HorzScrollBar che
consentono di configurare automaticamente le barre di scorrimento sulla scheda. Per
creare una regione con scorrimento all’interno di una scheda utilizzare il componente
TScrollBox.
Barre di regolazione
Un componente trackbar consente di impostare un valore intero in un intervallo
continuo. Risulta utile per regolare proprietà quali colore, volume e luminosità.
L’utente sposta l’indicatore a scorrimento trascinandolo in una particolare posizione
oppure facendo clic all’interno della barra.
• Utilizzare le proprietà Max e Min per impostare i limiti superiore e inferiore della
barra di regolazione.
• Utilizzare SelEnd e SelStart per evidenziare un intervallo di selezione. Vedere la
Figura 10.1.
• La proprietà Orientation determina se la barra di regolazione è verticale oppure
orizzontale.
• Per impostazione predefinita, una barra di regolazione presenta una serie di
tacche nella sua parte inferiore. Utilizzare la proprietà TickMarks per modificarne
la posizione. Per controllare gli intervalli tra le tacche, utilizzare la proprietà
TickStyle e il metodo SetTick.
Controlli up-down
Nelle applicazioni solo VCL, un controllo up-down (TUpDown) è formato di una
coppia di pulsanti freccia che consentono agli utenti di modificare un valore intero
mediante incrementi fissi. Il valore corrente è dato dalla proprietà Position;
l’incremento assunto per impostazione predefinita è pari a 1, ed è specificato dalla
proprietà Increment. Utilizzare la proprietà Associate per associare al controllo di
selezione un altro componente (come un controllo di editing.
Controlli splitter
Uno splitter (TSplitter) collocato tra controlli allineati consente all’utente di
ridimensionare i controlli. Utilizzato con componenti quali pannelli e caselle di
gruppo, gli splitter consentono di suddividere una scheda in diversi pannelli con più
controlli su ciascun pannello.
Dopo avere collocato su una scheda un pannello o un altro controllo, aggiungere uno
splitter con lo stesso allineamento del controllo. L’ultimo controllo dovrebbe essere
allineato al client, in modo da occupare lo spazio rimante quando si ridimensionano
gli altri componenti. Per esempio, è possibile collocare un pannello al margine
sinistro di una scheda, impostare la sua proprietà Alignment a alLeft, quindi collocare
uno splitter (anch’esso con allineamento alLeft) alla destra del pannello, e infine
collocare un altro pannello (con allineamento alLeft oppure alClient) alla destra dello
splitter.
Impostare la proprietà MinSize per specificare la minima dimensione lasciata dallo
splitter quando si ridimensiona il suo controllo con esso confinante. Impostare la
proprietà Beveled a True per far assumere al bordo dello splitter un aspetto
tridimensionale.
Utilizzare questo
componente: Per fare ciò:
TButton Presentare scelte di comando su pulsanti con solo testo
TBitBtn Presentare scelte di comando su pulsanti con testo e simboli grafici
TSpeedButton Creare pulsanti raggruppati in una barra strumenti
TCheckBox Presentare opzioni di tipo on/off, sì/no
TRadioButton Presentare una serie di scelte reciprocamente esclusive
TToolBar Disporre pulsanti strumento ed altri controlli su più righe e regolarne
automaticamente dimensioni e posizioni
TCoolBar Visualizzare una raccolta di controlli per finestra, all’interno di bande
spostabili e dimensionabili (solo VCL)
Controlli pulsante
L’utente fa clic con il mouse sui controlli pulsante per avviare azioni. I pulsanti
hanno un’etichetta di testo che rappresenta l’azione. Il testo viene specificato
assegnando un valore stringa alla proprietà Caption. La maggior parte dei pulsanti
può essere selezionata anche premendo un tasto sulla tastiera, detto tasto di scelta
rapida. La scorciatoia viene visualizzata sul pulsante come una lettera sottolineata.
I controlli pulsante sono utilizzati per consentire agli utenti di iniziare un’azione
facendo clic su di essi. È possibile assegnare un’azione a un componente TButton
creando per esso un gestore di evento OnClick. Facendo doppio clic su un pulsante in
fase di progettazione, si passa nel gestore dell’evento OnClick del pulsante nell’editor
di Codice.
• Impostare la proprietà Cancel a True se si desidera che il pulsante scateni il suo
evento OnClick alla pressione del pulsante Esc.
• Impostare la proprietà Default a True se si desidera che il tasto Invio scateni l’evento
OnClick del pulsante.
Pulsanti bitmap
Un pulsante bitmap (TBitBtn) è un controllo pulsante che presenta sulla sua
superficie un’immagine bitmap.
• Per scegliere una bitmap da assegnare al pulsante, impostare la proprietà Glyph.
• Utilizzare la proprietà Kind per configurare automaticamente un pulsante con un
simbolo e un comportamento predefiniti.
• Per impostazione predefinita, il simbolo appare alla sinistra di qualsiasi testo. Per
spostarlo, utilizzare la proprietà Layout.
• Il simbolo e il testo vengono centrati automaticamente sul pulsante. Per spostarne
la posizione, utilizzare la proprietà Margin. Margin determina il numero di pixel
tra il bordo dell’immagine e il bordo del pulsante.
• Per impostazione predefinita, l’immagine e il testo sono separati da 4 pixel.
Utilizzare la proprietà Spacing per aumentare o diminuire la distanza.
• I pulsanti bitmap possono avere 3 stati: su, giù e premuto. Impostare la proprietà
NumGlyphs a 3 per mostrare una bitmap diversa per ciascuno stato.
• Per impostazione predefinita, i pulsanti di scelta rapida appaiono nello stato non
selezionato (non premuto). Per visualizzare inizialmente un pulsante di scelta
rapida come selezionato (premuto), impostare la proprietà Down a True.
• Se la proprietà AllowAllUp è True, tutti i pulsanti di scelta rapida in un gruppo
possono essere non selezionati. Impostare la proprietà AllowAllUp a False se si
desidera che un gruppo di pulsanti agisca come un gruppo di pulsanti di opzione.
Per ulteriori informazioni su pulsanti di accesso rapido, fare riferimento alle sezioni
“Aggiunta di una barra strumenti usando un componente panel” a pagina 9-48 e
“Organizzazione delle azioni per barre e menu” a pagina 9-18.
Caselle di controllo
Una casella di controllo è un commutatore che permette all’utente di selezionare uno
stato attivo/inattivo. Quando la scelta è attiva, la casella di controllo appare con un
segno di spunta. In caso contrario, la casella di controllo è vuota. Le caselle di
controllo vengono create utilizzando il componente TCheckBox.
• Impostare la proprietà Checked a True per far sì che la casella appaia selezionata
per impostazione predefinita.
• Impostare la proprietà AllowGrayed a True per assegnare alla casella di controllo
tre possibili stati: selezionato, deselezionato, e grigio.
• La proprietà State indica se la casella di controllo è selezionata (cbChecked),
deselezionata (cbUnchecked), oppure grigia (cbGrayed).
N I controlli casella di controllo visualizzano uno dei due possibili stati binari. Lo stato
indeterminato viene utilizzato quando altre impostazioni rendono impossibile
determinare il valore corrente della casella di controllo.
Pulsanti di opzione
I pulsanti di opzione presentano una serie di scelte reciprocamente esclusive. È
possibile creare singoli pulsanti di opzione utilizzando TRadioButton oppure
utilizzando il componente radio group (TRadioGroup) per organizzare
automaticamente in gruppi più pulsanti di opzione. È possibile raggruppare i
pulsanti di opzione in modo da consentire all’utente di effettuare una scelta da un
insieme limitato di opzioni. Per maggiori informazioni, consultare la sezione
“Controlli di raggruppamento” a pagina 10-15.
Un pulsante di opzione selezionato viene visualizzato come un cerchio con un
pallino di riempimento. Se non è selezionato, il pulsante di opzione visualizza un
cerchio vuoto. Per modificare lo stato visuale del pulsante di opzione, assegnare il
valore True o False alla proprietà Checked.
Barre strumenti
Le barre strumenti rappresentano un modo semplice per disporre e gestire i controlli
visuali. È possibile creare una barra strumenti a partire da un componente panel e da
pulsanti di scelta rapida, oppure è possibile utilizzare il componente TToolBar e
aggiungere alla barra strumenti una serie di pulsanti facendo clic destro e scegliendo
il comando New Button.
Il componente TToolBar presenta diversi vantaggi: i pulsanti su una barra strumenti
conservano automaticamente dimensioni e spaziatura uniformi; gli altri controlli
conservano la propria posizione e altezza relative; i controlli possono essere disposti
automaticamente su più righe quando lo spazio orizzontale non è sufficiente; inoltre,
TToolBar consente di utilizzare varie opzioni di visualizzazione quali la trasparenza, i
bordi popup oltre a spazi e divisori per raggruppare i controlli.
Grazie alle liste di azioni o alle bande di azioni è possibile utilizzare un set
centralizzato di azioni per le barre strumenti e per i menu. Per i dettagli su come
utilizzare liste di azioni con i pulsanti e le barre strumenti, consultare il paragrafo
“Uso delle liste di azioni” a pagina 9-27.
Le barre strumenti possono anche fungere da genitore (contenere) di altri controlli
come caselle di modifica, caselle combinate, e così via.
Controlli elenco
I componenti con elenchi presentano all’utente una serie di elementi fra cui effettuare
una selezione. Diversi componenti visualizzano elenchi:
Caselle combinate
Una casella combinata (TComboBox) combina una casella di testo con un elenco a
scorrimento. Quando l’utente immette dati nel controllo, scrivendo oppure
selezionando uno dei valori dell’elenco, viene modificato il valore della proprietà
Text. Se la proprietà AutoComplete è attiva, l’applicazione cerca nella lista e visualizza
la corrispondenza più simile al dato via via immesso dall’utente.
Esistono tre tipi di caselle combinate: standard, a discesa (impostazione predefinita),
e lista a discesa.
• Utilizzare la proprietà Style per selezionare il tipo di casella combinata necessaria.
• Utilizzare csDropDown per creare una casella di testo con un elenco a discesa.
Utilizzare csDropDownList per rendere la casella di testo a sola lettura
(costringendo così l’utente ad effettuare una scelta dall’elenco). Impostare la
proprietà DropDownCount per modificare il numero di elementi visualizzato
nell’elenco.
• Utilizzare csSimple per creare una casella combinata con un elenco fisso che non si
chiude. Accertarsi di ridimensionare la casella combinata in modo da visualizzare
gli elementi dell’elenco.
• Utilizzare csOwnerDrawFixed oppure csOwnerDrawVariable per creare caselle
combinate con tracciamento personalizzato in grado di visualizzare graficamente gli
elementi o con altezze differenti. Per informazioni sui controlli con tracciamento
personalizzato, consultare la sezione “Aggiunta di grafici ai controlli” a
pagina 7-13.
In esecuzione, le caselle combinate CLX funzionano in modo diverso rispetto alle
caselle combinate della VCL. Con le caselle combinate CLX, è possibile aggiungere
un elemento a una casella combinata a discesa immettendo del testo nel campo di
editing e premendo il tasto Invio. È possibile disattivare questa funzione impostando
InsertMode a ciNone. Alla lista della casella combinata è anche possibile aggiungere
elementi vuoti (nessuna stringa). Inoltre, se si mantiene premuto il tasto freccia, non
ci si ferma sull’ultimo elemento dell’elenco della casella combinata. Si torna
nuovamente all’inizio.
Viste ad albero
Un controllo tree view (TTreeView) visualizza gli elementi secondo una struttura con
rientranze. Il controllo dispone di pulsanti che consentono di espandere e contrarre i
nodi. Assieme alle etichette di testo degli elementi è possibile includere delle icone e
visualizzare icone differenti per indicare se un nodo è espanso o contratto. È possibile
anche includere elementi grafici, come, ad esempio, un segno di spunta, che è in
grado di fornire informazioni sullo stato degli elementi.
• Indent imposta il numero di pixels che separano in orizzontale gli elementi dai
rispettivi genitori.
• ShowButtons consente la visualizzazione di pulsanti ’+’ e ’–’ per indicare se un
elemento può essere espanso.
• ShowLines consente la visualizzazione di linee di connessione per evidenziare le
relazioni gerarchiche (solo VCL).
• ShowRoot determina se visualizzare o meno le linee che connettono gli elementi di
livello superiore (solo VCL).
Per aggiungere elementi a un controllo vista ad albero in fase di progettazione, fare
doppio clic sul controllo in modo da visualizzare l’editor TreeView Items. Gli
elementi aggiunti diventano il valore della proprietà Items. È possibile modificare gli
elementi in esecuzione utilizzando i metodi della proprietà Items , che è un oggetto di
tipo TTreeNodes. TTreeNodes ha metodi per aggiungere, cancellare ed esaminare gli
elementi nella vista albero.
Le viste ad albero possono visualizzare colonne e sottoelementi in modo analogo ai
componenti listview in modalità vsReport.
Viste ad elenco
I controlli list view, creati utilizzando TListView, visualizzano elenchi in diversi
formati. Utilizzare la proprietà ViewStyle per scegliere il tipo di elenco desiderato:
• vsIcon e vsSmallIcon visualizzano ciascun elemento come un’icona con un’etichetta.
L’utente può trascinare gli elementi all’interno della finestra del controllo vista ad
elenco (solo VCL).
• vsList visualizza gli elementi come icone con etichetta che non è possibile
trascinare.
• vsReport visualizza gli elementi su righe separate con informazioni disposte in
colonne. La colonna più a sinistra contiene una piccola icona e un’etichetta, mentre
le colonne successive contengono i sottoelementi specificati dall’applicazione.
Controlli di raggruppamento
Un’interfaccia grafica è più facile da utilizzare se controlli e informazioni correlate
sono presentate in gruppi. I componenti per raggruppare i componenti:
Utilizzare questo
componente: Quando si desidera:
TGroupBox Una casella di gruppo standard con un titolo
TRadioGroup Un semplice gruppo di pulsanti di opzione
TPanel Un gruppo di controlli più flessibile
TScrollBox Una regione a scorrimento contenente controlli
TTabControl Una serie di separatori di pagine reciprocamente esclusivi
TPageControl Un insieme di separatori in stile notebook reciprocamente esclusivi, con
pagine corrispondenti, ognune delle quali può contenere altri controlli
THeaderControl Intestazioni di colonna dimensionabili
Pannelli
Il componente TPanel fornisce un contenitore generico per altri controlli. Di solito i
pannelli sono utilizzati per raggruppare visivamente più componenti su una scheda.
I pannelli possono essere allineati con la scheda in modo da conservare la stessa
posizione relativa se la scheda fosse dimensionata. La proprietà BorderWidth
determina l’ampiezza in pixels del bordo attorno a un pannello.
Su un pannello è possibile anche collocare altri controlli e utilizzare la proprietà Align
per assicurare il corretto posizionamento sulla scheda di tutti i controlli nel gruppo. È
possibile impostare l’allineamento del pannello a alTop in modo che la sua posizione
rimanga fissa anche se la scheda viene ridimensionata.
L’aspetto del pannello può essere modificato facendogli assumere un aspetto rialzato
o incavato grazie alle proprietà BevelOuter e BevelInner. È possibile variare i valori di
queste proprietà per creare differenti effetti 3-D visuali. È bene notare che se si
desidera solamente uno smusso rialzato o incavato, è possibile utilizzare il controllo
TBevel che utilizza in minor numero di risorse.
È possibile anche utilizzare uno o più pannelli per costruire barre di stato o aree per
la visualizzazione di informazioni.
Caselle a scorrimento
Le caselle a scorrimento (TScrollBox) consentono di creare all’interno di una scheda
delle aree con funzioni di scorrimento. Spesso le applicazioni devono visualizzare
più informazioni di quante ce ne stiano in una determinata area. Alcuni controlli
come le caselle di riepilogo, i campi memo e le stesse schede, sono in grado di far
scorrere i propri contenuti.
Un altro utilizzo delle caselle a scorrimento consiste nel creare più aree a scorrimento
(viste) in un’unica finestra.Le viste sono molto comuni nei programmi commerciali
di elaborazione testi, nei fogli elettronici o nelle applicazioni per la gestione di
progetti. Le caselle a scorrimento offrono maggior flessibilità in quanto consentono di
definire in modo arbitrario aree di scorrimento all’interno di una scheda.
In modo analogo ai pannelli e alle caselle di gruppo, le caselle a scorrimento
contengono altri controlli, come gli oggetti TButton e TCheckBox. Una casella a
scorrimento di solito è invisibile. Se i controlli inseriti nella casella a scorrimento non
sono contenuti completamente nell’area visibile, la casella a scorrimento visualizza
automaticamente barre di scorrimento.
Un altro utilizzo di tali caselle è quello di restringere lo scorrimento in determinate
aree della finestra, come ad esempio in una barra strumenti o in una barra di stato
(componenti TPanel). Per evitare che si possa far scorrere una barra strumenti o una
barra di stato, nascondere le barre di scorrimento e posizionare una casella a
scorrimento nell’area del client della finestra, fra la barra strumenti e la barra di stato.
Le barre di scorrimento associate alla casella a scorrimento sembreranno appartenere
alla finestra, ma consentiranno solo di far scorrere l’area all’interno della casella.
Controlli separatore
Il componente tab (TTabControl) crea una serie di separatori che assomigliano ai
divisori di un’agenda. È possibile creare separatori modificando nell’Object Inspector
la proprietà Tab; ciascuna stringa in Tabs rappresenta un separatore. Il controllo tab è
un singolo pannello contenente una serie di componenti. Per modificare l’aspetto del
controllo si fa clic su di esso, è necessario scrivere un gestore dell’evento OnChange.
Per creare una finestra di dialogo multipagina, utilizzare un controllo Page.
Controlli pagina
Il componente controllo pagina (TPageControl) consiste di un set di pagine adatto alla
creazione di finestre di dialogo multipagina. Un controllo pagina visualizza più
pagine sovrapposte, ognuna delle quali è un oggetto TTabSheet. Nell’interfaccia
utente, una pagina viene selezionata facendo clic sul separatore di pagina nella parte
superiore del controllo.
Per creare una nuova pagina in un controllo pagina in fase di progettazione, fare clic
destro sul controllo e scegliere il comando New page. In esecuzione, è possibile
aggiungere nuove pagine creando l’oggetto per la pagina e impostandone la
proprietà PageControl:
NewTabSheet = TTabSheet.Create(PageControl1);
NewTabSheet.PageControl := PageControl1;
Per accedere alla pagina attiva utilizzare la proprietà ActivePage. Per modificare la
pagina attiva, è possibile impostare le proprietà ActivePage o ActivePageIndex.
Controlli intestazione
Un controllo header (THeaderControl) è una serie di intestazioni di colonna che
l’utente può selezionare o ridimensionare in fase di esecuzione. Modificare la
proprietà Sections del controllo per aggiungere o modificare le intestazioni. È
possibile collocare sezioni di intestazione su colonne o campi. Ad esempio, le sezioni
di intestazione potrebbero essere collocate sulle caselle di riepilogo (TListBox).
Controlli di visualizzazione
Esistono diversi modi per fornire agli utenti le informazioni sullo stato di
un’applicazione. Ad esempio, alcuni componenti, incluso TForm, hanno una
proprietà Caption che può essere impostata durante l’esecuzione. È anche possibile
Utilizzare il componente
o la proprietà: Se si vuole:
TStatusBar Visualizzare un’area di stato (di solito nella parte inferiore di una fine-
stra)
TProgressBar Mostrare lo stato di avanzamento di una determinata operazione
Hint e ShowHint Attivare il fumetto di aiuto o i suggerimenti
HelpContext e HelpFile Collegare la Guida in linea contestuale
Barre di stato
Sebbene sia possibile utilizzare un pannello per creare una barra di stato, è più
semplice utilizzare il componente TStatusBar. Per impostazione predefinita, la
proprietà Align della barra di stato è impostata ad alBottom, che ne determina
automaticamente posizione e dimensione.
Se è necessario visualizzare nella barra di stato solo una stringa di testo per volta,
impostare la proprietà SimplePanel a True e utilizzare la proprietà SimpleText per
controllare il testo visualizzato nella barra di stato.
È possibile che una barra di stato venga suddivisa in varie aree di testo, chiamate
pannelli. Per creare i pannelli, modificare nell’Object Inspector la proprietà Panels
impostando per ciascun pannello, mediante il Panel editor, le proprietà Width,
Alignment, e Text. La proprietà Text di ogni pannello contiene il testo visualizzato nel
pannello.
Barre di avanzamento
Se l’applicazione deve compiere un’operazione molto lunga, è possibile utilizzare
una barra di avanzamento (TProgressBar) per mostrare lo stato di avanzamento
dell’operazione. Una barra di avanzamento visualizza una riga punteggiata che
cresce da sinistra a destra.
Figura 10.2 Una barra di avanzamento
Griglie
Le griglie visualizzano informazioni disposte su righe e colonne. Se si sta scrivendo
un’applicazione database, utilizzare i componenti TDBGrid o TDBCtrlGrid descritti
nel Capitolo 20, “Utilizzo dei controlli dati”. Oppure, utilizzare una griglia draw
standard o una griglia stringa.
Griglie grafiche
Una griglia grafica (TDrawGrid) visualizza dati arbitrari in formato tabellare. Per
riempire le celle della griglia si deve scrivere un gestore per l’evento OnDrawCell.
• Il metodo CellRect restituisce le coordinate video di una cella specificata, mentre il
metodo MouseToCell restituisce la colonna e la riga della cella situata alle
coordinate video specificate. La proprietà Selection indica i bordi delle celle
attualmente selezionate.
• La proprietà TopRow determina quale riga è attualmente nella parte superiore
della griglia. La proprietà LeftCol determina la prima colonna visibile sulla sinistra.
VisibleColCount e VisibleRowCount rappresentano il numero di colonne e righe
visibili nella griglia.
• È possibile modificare l’ampiezza o altezza di una colonna o di una riga mediante
le proprietà ColWidths e RowHeights.Impostare lo spessore delle linee della griglia
mediante la proprietà GridLineWidth. Aggiungere alla griglia le barre di
scorrimento mediante la proprietà ScrollBars.
• Mediante le proprietà FixedCols e FixedRows è possibile decidere se avere colonne o
righe fisse non soggette a scorrimento. Alle colonne e alle righe fisse è possibile
assegnare un colore usando la proprietà FixedColor.
• Le proprietà Options, DefaultColWidth e DefaultRowHeight influenzano anche
l’aspetto e il comportamento della griglia.
Controlli grafici
I componenti seguenti semplificano l’incorporazione di elementi grafici in
un’applicazione.
Si noti che questi includono le comuni routine di disegno (Repaint, Invalidate e così
via) che non avranno mai bisogno di ricevere il fuoco.
Per creare un controllo grafico, vedere il Capitolo 10, “Creazione di un controllo
grafico”, del manuale Guida alla scrittura di componenti.
Immagini
Il componente TImage (immagine) visualizza un’immagine grafica, come una bitmap,
un’icona o un metafile. La proprietà Picture determina l’immagine grafica da
visualizzare. Utilizzare Center, AutoSize, Stretch e Transparent per impostare le
opzioni di visualizzazione. Per maggiori informazioni consultare “Panoramica sulla
programmazione dei grafici” a pagina 12-1.
Forme
Il componente shape (forma) visualizza una forma geometrica.È un controllo che non
è basato su finestra (un controllo basato su widget nelle le applicazioni CLX) e
pertanto non può ricevere l’input dell’utente. La proprietà Shape determina la forma
assunta dal controllo.Per modificare il colore della forma o aggiungere un motivo di
riempimento, utilizzare la proprietà Brush che contiene un oggetto TBrush. Il modo in
cui la forma viene tracciata dipende dalle proprietà Color e Style di TBrush.
Linee smussate
Il componente bevel (TBevel) è una linea che può apparire incavata oppure a sbalzo.
Alcuni componenti, come TPanel, hanno proprietà intrinseche per creare bordi
smussati. Quando tali proprietà non sono disponibili, l’uso di TBevel consente di
creare contorni smussati, riquadri o cornici.
Caselle di disegno
Il componente paint box (TPaintBox) consente all’applicazione di tracciare un disegno
su una scheda. Per riprodurre direttamente un’immagine sul Canvas della casella di
disegno occorre scrivere un gestore per l’evento OnPaint. Non è consentito disegnare
al di fuori dei bordi della casella di disegno. Per maggiori informazioni consultare
“Panoramica sulla programmazione dei grafici” a pagina 12-1.
Modelli di ModelMaker
Nonostante ModelMaker produca codice sorgente, nella maggior parte delle
operazioni non modifica direttamente il codice sorgente. ModelMaker lavora sui
propri set di file, noti come modelli. Quando si lavora a un progetto in ModelMaker,
si sta manipolando la struttura del modello. ModelMaker converte periodicamente i
propri modelli in codice sorgente, sia automaticamente sia in risposta ad un
comando utilizzato dall’utente. È possibile utilizzare il codice sorgente generato per
costruire applicazioni e package.
I modelli non sono solo una mera rappresentazione compressa di codice sorgente.
Essi possono anche contenere informazioni esterne (come i dati di un diagramma
UML) che non sono memorizzate nei file di unità generati. Inoltre i modelli possono
gestire un numero arbitrario di unit di codice sorgente. Spesso un modello non
contiene un intero progetto o package, ma solo un subset delle sue unit.
N Dal momento che i modelli contengono informazioni uniche, non presenti nelle unit
del codice, è importante inlcudere i set di file del modello nei propri archivi e il
controllo di versione li elaborerà insieme ai file unit.
Per maggiori informazioni sui modelli e sui file di modello, vedere il manuale
ModelMaker User’s Guide.
Quando si utilizza ModelMaker con l’IDE, bisogna ricordarsi che l’IDE non può
cambiare i file del modello di ModelMaker. Ogni modifica al codice sorgente
effettuato con gli editor dell’IDE non verrà estesa automaticamente al modello. Le
modifiche verranno azzerate non appena ModelMaker aggiornerà le unit di codice
generate. Se è necessario compiere delle modifiche su un modello esistente, utilizzare
ModelMaker al posto dell’IDE per essere sicuri della sincronizzazione modello-
codice sorgente. Se ciò non è possibile, assicurarsi di reimportarte la unità nel
modello, appena si è finito di modificarla.
Creazione di modelli
Vi sono molti modi per creare modelli con ModelMaker. Se si sta creando del codice
completamente nuovo, è possibile iniziare con un nuovo modello e progettare il
codice (oltre alle schede) utilizzando ModelMaker. Per creare un nuovo modello,
selezionare File|New o fare clic sul pulsante New model sulla barra strumenti di
ModelMaker. (il pulsante New model è il pulsante posto più a sinistra sulla barra
strumenti).
Figura 11.1 Parte della barra strumenti ModelMaker
New model Import source
Collections
pane
Editors
pane
Methods
pane
Pannello Collections
Il pannello Collections visualizza raccolte di elementi utilizzati nei modelli di
ModelMaker. I modelli contengono spesso diverse classi, unit e diagrammi. Il
pannello delle raccolte mostra gruppi logici di questi elementi.
Vista Classes
La vista Classes mostra un elenco gerarchico di tutte le classi e interfacce nel modello.
Visualizza anche la geneaogia delle classi e delle interfacce nel modello. Gli antenati
contenuti nel modello corrente hanno icone circondati per linee solide. Quelli non
contenuti nel modello hanno icone delimitati con linee tratteggiate.
Figura 11.3 La vista Classes
N Se un oggetto e il suo antenato non sono inclusi in un modello, allora la gerarchia tra
loro potrebbe non essere completa.
È possibile compattare le gerarchie per nascondere rami a cui non si è interessati.
Attraverso la vista Classes, è possibile anche aggiungere nuove classi e interfacce al
modello.
Vista Units
La vista Units visualizza un albero o un elenco di tutto le unit contenute nel progetto.
La vista mostra anche tutti gli oggetti, le interfacce e gli eventi contenuti in ogni unit.
Figura 11.4 La vista Units
È possibile utilizzare pulsanti nella vista Units (sopra l'albero) per modificare il
contenuto della vista, aggiungere o editare le unit o modificare il comportamento di
generazione del codice.
Vista Diagrams
La vista Diagrams mostra che un elenco di tutti i diagrammi in stile UML contenuti
nel modello. È possibile modificare questi diagrammi utilizzando la vista Diagram
Editor del pannello editor.
Figura 11.5 La vista Diagrams
I diagrammi sono utilizzati spesso come uno strumento per la progettazione delle
classi. È possibile aggiungere proprietà, metodi ed eventi a un diagramma, il che
modificherà il modello, ed, eventualmente, il codice sorgente. Dopo la fase di
progettazione del diagramma, è possibile utilizzare gli strumenti nel pannello editors
(come la vista Implementation) per completare le implementazioni della nuova
classe. È possibile anche creare diagrammi per classi progettate senza UML o
ModelMaker.
È possibile utilizzare pulsanti nella vista Diagrams per creare vari tipi di diagrammi
in stile UML, fra cui:
• Diagrammi di classi
• Diagrammi di sequenze
• Diagrammi di collaborazione
• Diagrammi di utilizzo di case
• Diagrammi di robustezza
• Diagrammi Statechart (o di stato)
• Diagrammi di attività
• Diagrammi di implementazione
• Diagrammi di mappa
• Diagrammi di dipendenza di unit
Altri pulsanti permettono clonare o cancellare un diagramma esistente.
Pannello Members
Il pannello Members contiene la vista Members. Esso visualizza i membri (campi,
proprietà, metodi o eventi) della classe o dell'interfaccia attualmente selezionata nella
vista Class. La selezione di elementi nella vista Members può visualizzarne il
contenuto nel pannello editor se esiste un editor appropriato.
Figura 11.6 La vista Members
È possibile utilizzare la vista Members per modificare i nomi dei membri o per
visualizzare i membri nella vista Implementation e modificarli. È possibile utilizzare
alcuni dei pulsanti nella vista Members per aggiungere campi, proprietà, metodi ed
eventi. Altri pulsanti permettono di selezionare quali membri vengono visualizzati
nella vista in base al tipo di visibilità o al tipo di membro.
Pannello Editors
Il pannello Editors contiene viste che è possibile utilizzare per fare modifiche alle
implementazioni dei metodi, al codice sorgente delle unit, ai diagrammi ULM, alle
macro e agli schemi di progettazione. È possibile anche utilizzare il pannello Editors
per visualizzare le differenze fra uno dei file unit del modello prima e dopo aver
apportato modifiche al modello.
Implementation Editor
Implementation Editor permette di editare il codice sorgente dei metodi nel modello
senza utilizzare l'IDE. Dopo avere aggiunto metodi alle classi e alle interfacce
utilizzando la vista Members o i diagrammi ULM, è possibile scrivere le
implementazioni nel modello utilizzando l'editor Implementation. Queste
implementazioni verranno visualizzate nel codice sorgente generato.
Molte funzioni di un file unit, come le implementazioni delle classi, sono gestite
utilizzando editor specifici. Tali contenuti sono indicati nel modello da linee di
demarcazione che iniziano con MMWIN. Queste linee di demarcazione devono
essere lasciate isolate in Unit Code Editor (benché possano essere spostate all'interno
del file a patto che siano lasciate intatte). Con Unit Code Editor è possibile modificare
le linee non contrassegnate, come le clausole uses della unit e i metodi non
appartenenti alla classe.
Diagram Editor
Diagram Editor viene utilizzato per modificare i diagrammi UML creati dalla vista
Diagrams del pannello Collections. Esso contiene una vasta raccolta di strumenti per
apportare modifiche visuali nei diagrammi ULM. È possibile anche espandere il
modello di ModelMaker aggiungendo funzioni (come proprietà e metodi) ai
diagrammi ULM. Le modifiche apportate al modello attraverso i diagrammi si
propagheranno nel codice sorgente.
Figura 11.9 Diagram Editor
Altri Editor
ModelMaker include numerose altre viste di editor, fra cui:
• la vista Macros, che aiuta gestire e trattare le macro ModelMaker
• la vista Patterns, che permette di definire elementi di codice utilizzando gli
strumenti di schemi di progettazione di ModelMaker
• la vista Unit Difference, che permette di tracciare le differenze tra i file unit in
sorgenti differenti (tra cui modelli di ModelMaker e file unit salvati)
• la vista Documentation, che è possibile utilizzare per scrivere documentazione nel
modello per unit, classi e membri di classe
• la vista Events, che è possibile utilizzare per gestire gli eventi nel progetto
Il manuale ModelMaker User's Guide contiene informazioni approfondite su queste
altre viste di editor.
Capitolo
Windows tutto ciò che viene disegnato sullo schermo è permanente. Quando una
scheda o un controllo viene oscurato temporaneamente, per esempio durante il
disegno di una finestra, la scheda o il controllo devono dipingere di nuovo l’area
oscurata quando vengono riesposti. Per ulteriori informazioni sul messaggio
WM_PAINT, consultare la Guida in linea di Windows.
Se si usa il controllo TImageper visualizzare sulla scheda un’immagine grafica, le
operazioni relative alla pittura e all’aggiornamento del grafico contenuto in
TImagevengono gestite automaticamente. La proprietà Picture specifica la bitmap
attuale, il disegno o un altro oggetto grafico visualizzato da TImage. È possibile anche
impostare la proprietà Proportional per garantire che l’immagine possa essere
visualizzata completamente nel controllo immagine senza alcuna distorsione.
Disegnando su un controllo TImage, si crea un’immagine persistente.
Conseguentemente, non occorre fare nulla per ridisegnare l’immagine contenuta. Al
contrario, il canvas di TPaintBox mappa direttamente sul dispositivo di schermo
(applicazioni VCL) o sul painter (applicazioni CLX), e pertanto qualsiasi cosa
disegnata sul canvas di PaintBox è transitoria. Ciò è vero per quasi tutti i controlli,
compresa la scheda stessa. Perciò, se si disegna o si dipinge su un TPaintBox nel suo
costruttore, occorrerà aggiungere quel codice al gestore dell’evento OnPaint affinché
l’immagine venga ridipinta ogni volta che l’area client viene invalidata.
Queste proprietà sono descritte in modo più approfondito nella sezione “Uso delle
proprietà dell’oggetto Canvas” a pagina 12-5.
La Tabella 12.3 riporta un elenco dei vari metodi che è possibile usare:
Questi metodi sono descritti in modo più approfondito nel paragrafo “Uso dei
metodi Canvas per disegnare oggetti grafici” a pagina 12-10.
Si supponga di avere una barra di scorrimento sulla barra strumenti della penna per
impostare i valori dello spessore della penna. Si supponga inoltre di voler aggiornare
l’etichetta accanto alla barra di scorrimento per fornire informazioni di controllo
all’utente. Usando la posizione della barra di scorrimento per determinare la
larghezza della penna, questa viene aggiornata ogni volta che la posizione cambia.
Il codice che segue indica come gestire l’evento OnChange della barra di scorrimento:
procedure TForm1.PenWidthChange(Sender: TObject);
begin
Canvas.Pen.Width := PenWidth.Position;{ set the pen width directly }
PenSize.Caption := IntToStr(PenWidth.Position);{ convert to string for caption }
end;
N Per le applicazioni CLX distribuite in ambiente Windows, Windows non supporta gli
stili tratteggiato e punteggiato per penne più spesse di un pixel e disegna come
continue le penne più spesse, indipendentemente dallo stile specificato.
L’impostazione delle proprietà di una penna è ideale per avere controlli differenti
che condividono lo stesso gestore per gestire gli eventi. Per determinare quale
controllo ha di fatto ricevuto l’evento, si deve contrassegnare il parametro Sender.
Per creare un gestore per gli eventi OnClick relativi ad un gruppo di sei pulsanti di
stile su una barra strumenti della penna, occorre:
1 Selezionare tutti e sei i pulsanti e quindi Object Inspector|Events|OnClick e nella
colonna Handler scrivere SetPenStyle.
Il Code editor genera un gestore di evento vuoto di nome SetPenStyle e lo collega
agli eventi OnClick di tutti e sei pulsanti.
2 Riempire il gestore di evento generato impostando lo stile della penna in funzione
del valore di Sender, ossia del controllo che ha inviato l’evento OnClick
procedure TForm1.SetPenStyle(Sender: TObject);
begin
with Canvas.Pen do
begin
if Sender = SolidPen then Style := psSolid
else if Sender = DashPen then Style := psDash
else if Sender = DotPen then Style := psDot
else if Sender = DashDotPen then Style := psDashDot
else if Sender = DashDotDotPen then Style := psDashDotDot
else if Sender = ClearPen then Style := psClear;
end;
end;
nera, essere l’inverso del colore dello sfondo del canvas, l’inverso del colore della
penna, e così via. Per informazioni dettagliate, consultare TPen nella Guida in linea.
N Disegnando una linea con il metodo LineTo, si sposta anche la posizione attuale al
punto finale della linea.
N L’impostazione e la rilevazione dei singoli pixel sono migliaia di volte più lente
dell’esecuzione di operazioni grafiche sulle regioni. Non usare la proprietà Pixel
dell’array per accedere ai pixel dell’immagine di un generico array. Per l’accesso ad
elevate prestazioni ai pixel dell’immagine, consultare la proprietà TBitmap.ScanLine.
Disegno di linee
Per disegnare una linea retta su un canvas, si deve usare il metodo LineTo del canvas.
LineTo disegna una linea dalla posizione attuale della penna al punto specificato e
rende il punto finale della linea la posizione attiva. Il canvas disegna la linea usando
la sua penna.
Per esempio, il metodo seguente disegna diagonalmente linee incrociate in una
scheda ogni volta che la scheda viene dipinta:
procedure TForm1.FormPaint(Sender: TObject);
begin
with Canvas do
begin
MoveTo(0, 0);
LineTo(ClientWidth, ClientHeight);
MoveTo(0, ClientHeight);
LineTo(ClientWidth, 0);
end;
end;
Disegno di spezzate
Oltre alle singole linee, il canvas può disegnare anche spezzate, cioè gruppi di un
numero qualunque di segmenti consecutivi.
Per disegnare una spezzata su un canvas, si deve chiamare il metodo Polyline del
canvas.
Il parametro passato al metodo Polyline è un array di punti. Si può pensare ad una a
spezzata come all’esecuzione di un MoveTo sul primo punto e di un LineTo su ciascun
punto successivo. Per disegnare più linee, Polyline è più rapido dell’uso dei metodi
MoveTo e LineTo, in quanto vengono eliminate molte chiamate.
Il metodo seguente, per esempio, disegna un rombo in una scheda:
procedure TForm1.FormPaint(Sender: TObject);
begin
with Canvas do
Polyline([Point(0, 0), Point(50, 0), Point(75, 50), Point(25, 50), Point(0, 0)]);
end;
Questo esempio sfrutta i vantaggi della capacità di Delphi di creare istantaneamente
un parametro open-array. Si può passare un qualsiasi array di punti, ma un modo
semplice per costruire rapidamente un array consiste nel racchiudere i suoi elementi
tra parentesi quadre e nel passare l’intera espressione come parametro. Per ulteriori
informazioni, consultare la Guida in linea.
Disegno di figure
I canvas hanno metodi per disegnare tipi differenti di figure. Il canvas disegna il
contorno di una figura con la sua penna, quindi ne riempie l’interno con il suo
pennello. La linea che rappresenta il bordo della figura è controllata dall’oggetto Pen
attivo.
In queste sezione vengono trattati i seguenti argomenti:
• Disegno di rettangoli ed ellissi
• Disegno di rettangoli arrotondati
• Disegno di poligoni
Disegno di poligoni
Per disegnare un poligono con un numero qualsiasi di lati su un canvas, si deve
chiamare il suo metodo Polygon.
Polygon accetta come unico parametro un array di punti.
Questi vengono collegati con la penna, e l’ultimo punto viene collegato al primo per
chiudere il poligono. Dopo aver disegnato le linee, Polygon usa il pennello per
riempire l’area all’interno del poligono.
Per esempio, il codice seguente disegna un triangolo rettangolo nella metà inferiore
sinistra di una scheda:
procedure TForm1.FormPaint(Sender: TObject);
begin
Canvas.Polygon([Point(0, 0), Point(0, ClientHeight),
Point(ClientWidth, ClientHeight)]);
end;
Disegno di figure
Disegnare figure è facile quanto disegnare linee. Basta un singola istruzione; sono
necessarie solo le coordinate.
Il codice seguente è una riscrittura del gestore di evento OnMouseUp che disegna
figure per tutti e quattro gli strumenti:
procedure TForm1.FormMouseUp(Sender: TObject; Button TMouseButton; Shift: TShiftState;
X,Y: Integer);
begin
case DrawingTool of
dtLine:
begin
Canvas.MoveTo(Origin.X, Origin.Y);
Canvas.LineTo(X, Y)
end;
dtRectangle: Canvas.Rectangle(Origin.X, Origin.Y, X, Y);
dtEllipse: Canvas.Ellipse(Origin.X, Origin.Y, X, Y);
dtRoundRect: Canvas.RoundRect(Origin.X, Origin.Y, X, Y,
(Origin.X - X) div 2, (Origin.Y - Y) div 2);
end;
Drawing := False;
end;
Naturalmente, occorre anche aggiornare il gestore OnMouseMove per disegnare
figure:
procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
if Drawing then
begin
Canvas.Pen.Mode := pmNotXor;
case DrawingTool of
dtLine: begin
Canvas.MoveTo(Origin.X, Origin.Y);
Canvas.LineTo(MovePt.X, MovePt.Y);
Canvas.MoveTo(Origin.X, Origin.Y);
Canvas.LineTo(X, Y);
end;
dtRectangle: begin
Canvas.Rectangle(Origin.X, Origin.Y, MovePt.X, MovePt.Y);
Canvas.Rectangle(Origin.X, Origin.Y, X, Y);
end;
dtEllipse: begin
Canvas.Ellipse(Origin.X, Origin.Y, X, Y);
Canvas.Ellipse(Origin.X, Origin.Y, X, Y);
end;
dtRoundRect: begin
Canvas.RoundRect(Origin.X, Origin.Y, X, Y,
(Origin.X - X) div 2, (Origin.Y - Y) div 2);
Canvas.RoundRect(Origin.X, Origin.Y, X, Y,
(Origin.X - X) div 2, (Origin.Y - Y) div 2);
end;
end;
MovePt := Point(X, Y);
end;
Canvas.Pen.Mode := pmCopy;
end;
Normalmente, tutto il codice ripetitivo dell’esempio sopra riportato dovrebbe essere
inserito in una routine separata. La sezione successiva mostra tutto il codice per il
disegno delle figure in una singola routine che i gestori di evento del mouse possono
chiamare.
Disegno su un grafico
Non sono necessari componenti per manipolare gli oggetti grafici dell’applicazione.
È possibile costruire, prelevare, salvare e distruggere oggetti grafici senza dover
necessariamente disegnare qualcosa sullo schermo. Infatti, raramente le applicazioni
disegnano direttamente su una scheda. Più spesso un’applicazione opera sui grafici e
poi utilizza un componente controllo immagine per visualizzare il grafico su una
scheda.
Una volta spostato il disegno dell’applicazione nel grafico del controllo immagine, è
facile aggiungere le funzioni di stampa, di clipboard, di caricamento e salvataggio
per tutti gli oggetti grafici. Gli oggetti grafici possono essere file bitmap, metafile,
icone o qualsiasi altra classe di grafici installati, come, ad esempio, i grafici jpeg.
Sostituzione dell’immagine
In qualsiasi momento è possibile sostituire la figura di un controllo immagine. Se si
assegna un nuovo grafico ad un’immagine che ne ha già uno, il nuovo grafico
sostituisce quello esistente.
Per sostituire la figura di un controllo immagine, si deve assegnare un nuovo grafico
all’oggetto Picture del controllo immagine.
Il processo adottato per la creazione del nuovo grafico è identico a quello utilizzato
per creare il grafico iniziale (consultare “Impostazione delle dimensioni iniziali della
bitmap” a pagina 12-18), ma in questo caso si deve fornire anche un modo affinché
l’utente possa scegliere una dimensione diversa da quella standard usata per il
grafico iniziale. Un semplice modo per fornire questa opzione consiste nel presentare
una finestra di dialogo, come quella della Figura 12.1.
Figura 12.1 Finestra di dialogo Bitmap Dimension dalla unit BMPDlg..
WidthEdit
HeightEdit
Questa particolare finestra di dialogo viene creata nella unit BMPDlg che fa parte del
progetto GraphEx (nella directory demos\doc\graphex).
Avendo questa finestra di dialogo nel progetto, aggiungerla alla clausola uses nella
unit della scheda principale. Quindi, si può collegare un gestore all’evento onClick
della voce di menu File|New. Ecco un esempio:
procedure TForm1.New1Click(Sender: TObject);
var
Bitmap: TBitmap;{ temporary variable for the new bitmap }
begin
with NewBMPForm do
begin
ActiveControl := WidthEdit;{ make sure focus is on width field }
WidthEdit.Text := IntToStr(Image.Picture.Graphic.Width);{ use current dimensions... }
HeightEdit.Text := IntToStr(Image.Picture.Graphic.Height);{ ...as default }
if ShowModal <> idCancel then{ continue if user doesn't cancel dialog box }
begin
Bitmap := TBitmap.Create;{ create fresh bitmap object }
Bitmap.Width := StrToInt(WidthEdit.Text);{ use specified width }
Bitmap.Height := StrToInt(HeightEdit.Text);{ use specified height }
Image.Picture.Graphic := Bitmap;{ replace graphic with new bitmap }
CurrentFile := '';{ indicate unnamed file }
Bitmap.Free;
end;
end;
end;
Clipboard.Assign(Image.Picture)
end.
N Il codice VCL seguente mostra come incollare una figura dalla clipboard in un
controllo immagine in risposta ad un clic su una voce di menu Edit|Paste:
procedure TForm1.PasteButtonClick(Sender: TObject);
var
Bitmap: TBitmap;
begin
if Clipboard.HasFormat(CF_BITMAP) then { is there a bitmap on the Windows clipboard? )
begin
Image1.Picture.Bitmap.Assign(Clipboard);
end;
end;
Risposta al mouse
L’applicazione può rispondere alle azioni del mouse: mouse-down, spostamento
mouse e mouse-up. Essa può rispondere anche ad un clic (un’operazione completa di
pressione e rilascio nello stesso punto), che può essere generato da una combinazione
di tasti (come le pressione di Invio in una finestra di dialogo modale).
In queste sezione vengono trattati i seguenti argomenti:
• Che cosa c’è in un evento mouse?
• Risposta ad un’azione mouse-down
• Risposta ad un’azione mouse-up
• Risposta ad uno spostamento del mouse
Quando un’applicazione rileva un’azione del mouse, chiama il gestore di evento che
è stato definito per l’evento corrispondente, passando cinque parametri. Le
informazioni di questi parametri devono essere utilizzate per personalizzare le
risposte agli eventi. I cinque parametri sono i seguenti:
N Delphi usa gli stessi criteri di Microsoft Windows nel determinare quale pulsante del
mouse è stato premuto. Pertanto, se sono stati invertiti i pulsanti del mouse
predefiniti “principale” e “secondario” (in modo che il pulsante destro sia quello
principale), un clic sul pulsante principale (destro) registrerà mbLeft come valore del
parametro Button.
Per rispondere ai movimenti del mouse, occorre definire un gestore per l’evento
OnMouseMove. Questo esempio usa gli eventi mouse-move per disegnare figure
intermedie su una scheda mentre l’utente tiene premuto il pulsante del mouse,
fornendo pertanto all’utente un certo controllo. Il gestore di evento OnMouseMove
disegna una linea su una scheda nella posizione dell’evento OnMouseMove
procedure TForm1.FormMouseMove(Sender: TObject;Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
Canvas.LineTo(X, Y);{ draw line to current position }
end;
Con questo codice, lo spostamento del mouse sulla scheda fa sì che il disegno segua il
mouse, anche prima che il pulsante del mouse venga premuto.
Gli eventi mouse-move si verificano quando non sono stati premuti i pulsanti del
mouse.
Se si vuole registrare se è stato premuto un pulsante del mouse, occorre aggiungere
un campo oggetto all’oggetto scheda.
end;
procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
Canvas.MoveTo(Origin.X, Origin.Y);{ move pen to starting point }
Canvas.LineTo(X, Y);
Drawing := False;
end;
Queste modifiche servono all’applicazione per disegnare di nuovo la linea finale, e
non per disegnare delle azioni intermedie—l’applicazione non supporta ancora
l’effetto “elastico”.”
mediale specificato dalla proprietà FileName). Per ulteriori informazioni sui tipi di
dispositivo e sulle loro funzioni, consultare la Tabella 12.7.
4 Se il dispositivo memorizza il suo supporto in un file, specificarne il nome usando
la proprietà FileName. Selezionare la proprietà FileName, fare clic sul pulsante coi
puntini di sospensione (…) e scegliere un file mediale da una directory locale o di
rete disponibile e fare clic su Open nella finestra di dialogo omonima. In
alternativa, inserire in fase di esecuzione l’hardware (disco, cassetta o altro) in cui
è memorizzato il supporto per il dispositivo mediale selezionato.
5 Impostare la proprietà AutoOpen a True. In questo modo il riproduttore mediale
apre automaticamente il dispositivo specificato quando viene creata in fase di
esecuzione la scheda che contiene il controllo MediaPlayer. Se AutoOpen è False, il
dispositivo deve essere aperto con una chiamata al metodo Open.
6 Impostare la proprietà AutoEnable a True per attivare o disattivare
automaticamente i pulsanti MediaPlayer, come richiesto in fase di esecuzione;
oppure, fare doppio clic sulla proprietà EnabledButtons per impostare ciascun
pulsante a True o False, a seconda di quali si desidera attivare o disattivare.
Il dispositivo multimediale viene riprodotto, messo in pausa, fermato, e così via,
quando l’utente fa clic sul pulsante corrispondente sul componente mediaplayer.
Il dispositivo può essere controllato anche tramite i metodi che corrispondono ai
pulsanti (Play, Pause, Stop, Next, Previous, e così via).
7 Posizionare la barra del controllo MediaPlayer sulla scheda facendo clic e
trascinandola nel posto desiderato sulla scheda o selezionando la proprietà Align e
scegliendo la posizione di allineamento corretta dall’elenco a discesa.
Se si vuole che il MediaPlayer sia invisibile in fase di esecuzione, impostare la
proprietà Visible a False e controllare il dispositivo chiamando i metodi appropriati
(Play, Pause, Stop, Next, Previous, Step, Back, Start Recording, Eject).
8 Apportare tutte le altre modifiche alle impostazioni del controllo MediaPlayer. Per
esempio, se il supporto richiede una finestra di visualizzazione, impostare la
proprietà Display al controllo che visualizza il supporto. Se il dispositivo usa più
tracce, impostare la proprietà Tracks alla traccia desiderata.
Capitolo
N A differenza della maggior parte delle finestre di dialogo nell’IDE che richiedono un
nome di classe, la finestra di dialogo New Thread Object non mette automaticamente
una ‘T’ come prefisso del nome di classe fornito.
Il file unit generato automaticamente contiene lo scheletro di codice per la nuova
classe thread. Un thread al quale è stato attribuito come nome TMyThread apparirà
più o meno in questo modo:
unit Unit2;
interface
uses
Classes;
type
TMyThread = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
end;
implementation
{ TMyThread }
procedure TMyThread.Execute;
begin
{ Place thread code here }
end;
end.
Occorre completare il codice per il metodo Execute. Le fasi relative a tale operazione
vengono descritte nelle sezioni successive.
W L’aumento della priorità del thread di un’operazione che richiede un uso intensivo
della CPU può lasciare “a bocca asciutta” gli altri thread dell’applicazione. Ciò vale
solo per i thread che trascorrono la maggior parte del tempo in attesa di eventi
esterni.
Il codice seguente mostra il costruttore di un thread a bassa priorità che esegue
operazioni secondarie che non interferiranno con le altre prestazioni
dell’applicazione:
constructor TMyThread.Create(CreateSuspended: Boolean);
begin
inherited Create(CreateSuspended);
Priority := tpIdle;
end;
Synchronize aspetta il thread principale per avviare il ciclo di messaggi, dopo di che
esegue il metodo passato.
N Dal momento che Synchronize usa il ciclo di messaggi, non funziona nelle
applicazioni console. Per proteggere l’accesso agli oggetti VCL e CLX nelle
applicazioni per console, si devono, pertanto, usare altri meccanismi, come le sezioni
critiche.
Non occorre usare sempre il thread principale. Alcuni oggetti sono associati ai
thread. Omettendo l’uso del metodo Synchronize quando si è certi che i metodi di un
oggetto sono thread-safe si miglioreranno le prestazioni, poiché non occorrerà
aspettare che il thread VCL o CLX avvii il proprio ciclo di messaggi. Non è necessario
usare il metodo Synchronize per i seguenti oggetti:
• I componenti di accesso ai dati sono thread-safe in questo senso: Per i dataset che
supportano BDE, ciascun thread deve avere il proprio componente database
session. L’unica eccezione è quando si usano i driver di Microsoft Access, che sono
costruiti usando la libreria Microsoft, che non è thread-safe. Per dbExpress, finché
la libreria client del produttore è thread-safe, i componenti dbExpress saranno
thread-safe. I componenti ADO e InterbaseExpress sono thread-safe.
Quando si usano componenti di accesso ai dati, occorre sempre passare al metodo
Synchronize tutte le chiamate che interessano i controlli associati ai dati. Quindi,
per esempio, occorre sincronizzare le chiamate che collegano un controllo dati ad
un dataset impostando la proprietà DataSet dell’oggetto data source, ma non
occorre alcuna sincronizzazione per accedere ai dati di un campo del dataset.
Per maggiori informazioni sull’uso delle sessioni database con i thread in
applicazioni che utilizzano BDE, consultare “Gestione di sessioni multiple” a
pagina 26-30.
• I controlli non sono thread-safe.
• Gli oggetti grafici sono thread-safe. Non occorre usare il thread VCL principale
per accedere a TFont, TPen, TBrush, TBitmap, TMetafile (solo VCL), TDrawing(solo
CLX), o TIcon. Gli oggetti canvas possono essere usati all’esterno del metodo
Synchronize bloccandoli(consultare “Blocco di oggetti” a pagina 13-8).
• Benché gli oggetti list non siano thread-safe, si può usare una versione thread-safe,
TThreadList, al posto di TList.
Chiamare periodicamente la routine CheckSynchronize dall’interno del thread
principale dell’applicazione in modo che i thread in background possano
sincronizzare la propria esecuzione con il thread principale. Il momento ideale per
chiamare CheckSynchronize è quando l’applicazione è inattiva (ad esempio, da un
gestore di evento OnIdle ). Ciò garantisce che è sicuro effettuare chiamate ai metodi
nel thread di background.
Qualche volta, tuttavia, può risultare preferibile usare variabili che sono globali per
tutte le routine che vengono eseguite nel thread, ma non sono condivise con altre
istanze della stessa classe thread. Per ottenere questo risultato, occorre dichiarare le
variabili locali al thread. Una variabile locale al thread viene predisposta
dichiarandola nella sezione threadvar. Per esempio,
threadvar
x : integer;
dichiara una variabile di tipo integer che è privata per ciascun thread
dell’applicazione, ma globale all’interno di ciascun thread.
La sezione threadvar può essere utilizzata solamente per variabili globali. Pointer e
Function non possono essere variabili thread. Non funzionano come variabili
neppure i tipi che usano la semantica a sola scrittura, così come pure le variabili di
tipo long string.
except
{ do something with exceptions }
end;
end;
Blocco di oggetti
Alcuni oggetti hanno un blocco integrato che impedisce l’esecuzione di altri thread
per l’uso dell’istanza di quell’oggetto.
Per esempio, gli oggetti canvas (TCanvas e discendenti) hanno un metodo Lock che
impedisce agli altri thread di accedere al canvas finché non viene chiamato il metodo
Unlock.
Anche le applicazioni VCL e CLX includono un oggetto list thread-safe, TThreadList.
Chiamando TThreadList.LockList viene restituito l’oggetto list e viene anche impedito
ad altri thread in esecuzione di usare la lista finché non viene chiamato il metodo
UnlockList. Le chiamate a TCanvas::Lock o a TThreadList::LockList possono essere
annidate tranquillamente. Il blocco non viene rilasciato finché non si verifica una
corrispondenza tra l’ultima chiamata di blocco ed una chiamata di sblocco nello
stesso thread.
W Le sezioni critiche funzionano solo se ogni thread le usa per accedere alla memoria
globale associata. I thread che ignorano la sezione critica e accedono alla memoria
globale senza chiamare Acquire possono provocare problemi di accesso simultaneo.
Per esempio, si consideri un’applicazione che abbia una variabile globale della
sezione critica, LockXY, che blocca l’accesso alle variabili globali X e Y. Tutti i thread
che utilizzano X o Y devono circondare tale utilizzo con chiamate alla sezione critica,
come nell’ esempio seguente:
LockXY.Acquire; { lock out other threads }
try
Y := sin(X);
finally
LockXY.Release;
end;
ƒ
CounterGuard.Acquire; { obtain a lock on the counter }
Dec(Counter); { decrement the global counter variable }
if Counter = 0 then
Event1.SetEvent; { signal if this is the last thread }
CounterGuard.Release; { release the lock on the counter }
ƒ
end;
Il thread principale inizializza la variabile Counter, avvia l’esecuzione dei thread e
aspetta il segnale che indica che tutti hanno terminato chiamando il metodo WaitFor.
WaitFor attende per un tempo specificato il segnale da impostare, e restituisce uno
dei valori elencati nella Tabella 13.2.
Il codice seguente mostra come il thread principale avvia l’esecuzione dei thread,
quindi ricomincia quando tutti hanno terminato l’operazione:
Event1.ResetEvent; { clear the event before launching the threads }
for i := 1 to Counter do
TaskThread.Create(False); { create and launch task threads }
if Event1.WaitFor(20000) <> wrSignaled then
raise Exception;
{ now continue with the main thread. All task threads have finished }
2 Aggiungere il metodo SetName alla classe del thread nella sezione interface:
//---------------------------------------------------------------------------
type
TMyThread = class(TThread)
private
procedure SetName;
protected
procedure Execute; override;
end;
//---------------------------------------------------------------------------
3 Aggiungere il record TThreadNameInfo e il metodo SetName nella sezione
implementation:
//---------------------------------------------------------------------------
{$IFDEF MSWINDOWS}
type
TThreadNameInfo = record
FType: LongWord; // must be 0x1000
FName: PChar; // pointer to name (in user address space)
FThreadID: LongWord; // thread ID (-1 indicates caller thread)
FFlags: LongWord; // reserved for future use, must be zero
end;
{$ENDIF}
{ TMyThread }
procedure TMyThread.SetName;
{$IFDEF MSWINDOWS}
var
ThreadNameInfo: TThreadNameInfo;
{$ENDIF}
begin
{$IFDEF MSWINDOWS}
ThreadNameInfo.FType := $1000;
ThreadNameInfo.FName := 'MyThreadName';
ThreadNameInfo.FThreadID := $FFFFFFFF;
ThreadNameInfo.FFlags := 0;
try
RaiseException( $406D1388, 0, sizeof(ThreadNameInfo) div sizeof(LongWord),
@ThreadNameInfo );
except
end;
{$ENDIF}
end;
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
procedure TMyThread.Execute;
begin
SetName;
{ Place thread code here }
end;
//---------------------------------------------------------------------------
Sollevare un’eccezione
Per indicare una condizione di errore distruttivo, è possibile sollevare un'eccezione
costruendo un'istanza di un oggetto exception che descriva la condizione di errore e
chiamando la parola riservata raise.
Per sollevare un'eccezione, chiamare la parola riservata raise, seguita da un'istanza di
un oggetto di exception. Questo stabilisce da quale particolare indirizzo viene
l’eccezione. Quando un gestore di eccezioni gestisce l'eccezione, finisce distruggendo
l'istanza di eccezione, in modo che non sia mai necessario doverlo fare.
Ad esempio, data la seguente dichiarazione,
type
EPasswordInvalid = class(Exception);
è possibile sollevare un'eccezione “password invalid” in qualsiasi momento
chiamando raise con un'istanza di EPasswordInvalid, come:
if Password <> CorrectPassword then
raise EPasswordInvalid.Create('Incorrect password entered');
W Non assegnare mai un valore a ErrorAddr, che deve essere considerato a sola lettura.
Per specificare un indirizzo di errore per un'eccezione, aggiunge la parola riservata at
dopo l'istanza di eccezione, seguita da un'espressione di indirizzo come
identificatore.
Risollevare le eccezioni
Talvolta quando si gestisce un'eccezione localmente, si desidera potenziare la
gestione nel blocco che la include, piuttosto che sostituirla. Naturalmente, quando il
gestore locale finisce la sua gestione, distrugge l'istanza di eccezione, cosicché il
gestore del blocco che include non riesce mai ad agire. È possibile impedire, tuttavia,
al gestore di distruggere l'eccezione, dando al gestore del blocco che include una
possibilità di rispondere. Si fa questo utilizzando il comando raise senza argomenti.
Questo è chiamato risollevare o rigettare l'eccezione. Il seguente esempio illustra
questa tecnica:
try
{ statements }
try
{ special statements }
except
on ESomething do
begin
{ handling for only the special statements }
raise;{ reraise the exception }
end;
end;
except
on ESomething do ...;{ handling you want in all cases }
end;
Per assicurare che la memoria venga liberata, è possibile utilizzare un blocco try con
un blocco finally.
I meccanismi di gestione delle eccezioni dei componenti non sono diversi dalla
gestione di qualsiasi altro tipo di eccezione.
Se non si gestisce l'eccezione, VCL la gestisce in un modo predefinito. Di solito, viene
visualizzato un messaggio descrivendo il tipo di errore che si è verificato. Mentre si fa
il debug dell'applicazione, è possibile cercare la classe di eccezione nella Guida in
linea. Le informazioni fornite aiuteranno spesso a determinare dove si è verificato
l'errore e la sua causa
Una sorgente comune di errori nei componenti sono gli errori di intervallo nelle
proprietà indicizzate. Ad esempio, se una casella di riepilogo ha tre elementi nel suo
elenco (0..2) e l'applicazione tenta di accedere all’elemento numero 3, la casella di
riepilogo solleva un’eccezione “List index out of bounds”.
Il seguente gestore di evento contiene un gestore di eccezioni per informare l'utente
in caso di tentativo di accesso a un indice non valido in una casella di riepilogo:
procedure TForm1.Button1Click(Sender: TObject);
begin
ListBox1.Items.Add('a string');{ add a string to list box }
ListBox1.Items.Add('another string');{ add another string... }
ListBox1.Items.Add('still another string');{ ...and a third string }
try
Caption := ListBox1.Items[3];{ set form caption to fourth string }
except
on EStringListError do
ShowMessage('List box contains fewer than four strings');
end;
end;
Se si fa clic sul pulsante una volta, la casella di riepilogo ha solo tre stringhe, cosicché
accedere alla quarta stringa solleva un'eccezione. Facendo clic un’altra volta si
aggiungono altre stringhe all'elenco, in questo modo non si causa più l'eccezione.
Ci sono volte in cui è necessario creare specifiche classi di eccezione per gestire
situazioni uniche. È possibile dichiarare una nuova classe di eccezione creando un
discendente del tipo Exception e tanti costruttori quanti sono necessari (o copiare i
costruttori da una classe esistente nella unit SysUtils).
Ci sono alcune circostanze dove HandleException non viene chiamato. Eccezioni che si
verificano prima o dopo l'esecuzione del metodo Run dell'applicazione non vengono
intercettate e gestite da HandleException. Quando si scrive una funzione di callback o
una libreria (.dll o oggetto condiviso) con funzioni che possono essere chiamate da
un'applicazione esterna, le eccezioni possono sfuggire all'oggetto Application. Per
impedire alle eccezioni di sfuggire in questo modo, è possibile inserire un’apposita
chiamata al metodo HandleException:
try
{ special statements }
except
on Exception do
begin
Application.HandleException(Self);{ call HandleException }
end;
end;
Eccezioni silenziose
Le applicazioni VCL gestiscono la maggior parte delle eccezioni che il codice non
gestisce specificatamente, visualizzando un riquadro di messaggio che mostra la
stringa di messaggio dell'oggetto exception. È possibile anche definire eccezioni
"silenziose" che, per impostazione predefinita, fanno in modo che l'applicazione non
visualizzi il messaggio di errore.
Le eccezioni silenziose sono utili quando non si vuole segnalare un'eccezione
all'utente, ma si desidera terminare un'operazione. Terminare in modo anomalo
un'operazione è simile all'utilizzo delle procedure Break o Exit per uscire da un
blocco, ma può uscire da più livelli annidati di blocchi.
Le eccezioni silenziose discendono tutte dal tipo di eccezione standard EAbort. Il
gestore di eccezioni predefinito per applicazioni VCL visualizza la finestra di dialogo
error-message per tutte le eccezioni che lo raggiungono tranne per quelle derivate da
EAbort.
N Per applicazioni per console, viene visualizzata una finestra di dialogo di messaggio
di errore su qualsiasi eccezione EAbort non gestita.
C'è una scorciatoia per sollevare eccezioni silenziose. Invece di costruire
manualmente l'oggetto, è possibile chiamare la procedura Abort. Abort solleva
automaticamente un'eccezione EAbort, che si libera dall'operazione corrente senza
visualizzare un messaggio di errore.
Capitolo
Tecniche di porting
Di seguito sono elencate le varie strade che è possibile intraprendere per trasportare
un’applicazione da una piattaforma a una altra:
Ad esempio, nei file sorgente è possibile delimitare con direttive condizionali del
compilatore il codice specifico per la piattaforma:
[$IFDEF MSWINDOWS]
{$IFDEF MSWINDOWS}
IniFile.LoadfromFile(‘c:\x.txt’);
[$ENDIF]
[$IFDEF LINUX]
{$ENDIF}
{$IFDEF LINUX}
IniFile.LoadfromFile(‘/home/name/x.txt’);
[$ENDIF]
{$ENDIF}
7 Cercare in tutti i file di progetto i riferimenti ai nomi di percorso.
• Nei percorsi di Linux si utilizza come delimitatore una barra diritta / (ad
esempio, /usr/lib) e i file possono essere situati in varie directory sul sistema
Linux. Utilizzare la costante PathDelim (in SysUtils) per specificare il
delimitatore di percorso appropriato per il sistema. Determinare l’ubicazione
corretta per tutti i file in Linux.
• Modificare i riferimenti alle lettere di unità (ad esempio, C: \) e il codice che
ricava le lettere associate alle unità ricercando il carattere due punti alla
posizione 2 nella stringa. Utilizzare la costante DriveDelim (in SysUtils) per
specificare l’ubicazione in modo appropriato per il sistema.
• Nei segmenti di codice in cui si specificano percorsi multipli, modificare il
separatore di percorso da punto e virgola (;) a due punti (:). Utilizzare la
costante PathSep (in SysUtils) per specificare il separatore di percorso
appropriato per il sistema.
• Poiché in Linux i nomi dei file sono sensibili all’uso di maiuscole e minuscole,
assicurarsi che l’applicazione non modifichi i caratteri maiuscoli/ minuscoli dei
nomi dei file o non faccia affidamento su di essi.
Consultare “Differenze di programmazione in Linux” a pagina 15-17.
WinCLX e VisualCLX
Le applicazioni CLX utilizzano la Borland Component Library for Cross-Platform
(CLX) al posto della Visual Component Library (VCL). Sia la VCL che la CLX
includono le stesse quattro sottolibrerie delle cinque che sono incluse, come descritto
in “La libreria di componenti” a pagina 3-1. Le classi e le proprietà in queste
sottolibrerie hanno gli stessi nomi. Le uniche differenze fra la VCL e la CLX sono le
classi nelle sottolibrerie WinCLX e VisualCLX. Le applicazioni VCL utilizzano
WinCLX mentre le applicazioni CLX utilizzano VisualCLX.
All’interno di WinCLX, molti controlli accedono a controlli Windows facendo
chiamate alle librerie delle API di Windows. Allo stesso modo, nella VisualCLX i
controlli forniscono accesso ai widget Qt effettuando delle chiamate alle librerie Qt
condivise.
Alcune unit presenti nella applicazioni VCL sono presenti anche nelle applicazioni
CLX, come le unit Classes, DateUtils, DB, System, SysUtils e molte altre unit, come
quelle nella libreria di esecuzione (RTL). Tuttavia, le unit CLX nella sottolibreria
VisualCLX sono diverse da quelle nella sottolibreria WinCLX. Se si esegue il porting
di applicazioni VCL da Windows a Linux, sarà necessario modificare i nomi di
queste unit nella clausola uses dell’applicazione. La modifica di nome più comune
viene fatta aggiungendo una Q all’inizio del nome della unit o del file header.
Questa sezione presenta tre tabelle che elencano le unit solo per WinCLX e le unit
VisualCLX equivalenti; le unit solo per VisualCLX e le unit solo per WinCLX.
La Tabella 15.3 elenca i nomi delle unit della WinCLX che il cui nome è diverso
rispetto a quello delle unit della VisualCLX. Le unit che hanno lo stesso nome sia
nelle applicazioni VCL che nelle applicazioni CLX, o le unit fornite da terze parti, non
sono elencate.
Le seguenti unit specifiche per Windows non sono incluse nelle applicazioni CLX
principalmente perché sono relative a funzioni specifiche di Windows che non sono
disponibili in Linux. Ad esempio, le applicazioni CLX non utilizzano le unit ADO,
BDE o COM, né unit per Windows come CtlPanel, Messages, Registry e Windows.
I riferimenti a queste unit e alle classi all’interno di queste unit devono essere
eliminati dalle applicazioni che si desidera eseguire in Linux. Se si prova a compilare
un programma contenete unit che non esistono in un’applicazione multipiattaforma,
si riceverà il seguente messaggio di errore:
• Provare a non utilizzare $IFDEF a meno che non sia assolutamente necessario. Le
direttive $IFDEF in un file sorgente vengono valutate solo al momento della
compilazione del codice sorgente. Delphi non necessita dei sorgenti della unit per
compilare un progetto. La rigenerazione completa di tutto il codice sorgente è un
evento insolito per la maggior parte dei progetti Delphi.
• Non utilizzare $IFDEF in file package (.dpk). Limitare il loro utilizzo ai file
sorgente. Gli scrittori di componenti devono creare due package distinti di
progettazione quando sviluppano per più piattaforme, e non un solo package
utilizzando $IFDEF.
• Di solito, utilizzare $IFDEF MSWINDOWS per verificare tutte le piattaforme
Windows, inclusa WIN32. Riservare l’utilizzo di $IFDEF WIN32 per effettuare
una distinzione fra piattaforme Windows specifiche, ad esempio tra Windows 32
bit e 64 bit. Non limitare il codice alla piattaforma WIN32 a meno che non si sappia
per certo che non verrà utilizzato in WIN64.
• Evitare test di negazione come $IFNDEF a meno che non sia assolutamente
necessario. La direttiva $IFNDEF LINUX non è equivalente a
$IFDEFMSWINDOWS.
• Evitare combinazioni $IFNDEF/$ELSE. Utilizzare invece un test positivo
($IFDEF) per migliorare la leggibilità.
• Evitare clausole $ELSE con direttive $IFDEF sensibili alla piattaforma. Utilizzare
blocchi separati $IFDEF per codice specifico per Linux e Windows invece di
$IFDEF LINUX/$ELSE oppure di $IFDEF MSWINDOWS/$ELSE.
Ad esempio, del vecchio codice potrebbe contenere
{$IFDEF WIN32}
(32-bit Windows code)
{$ELSE}
(16-bit Windows code) //!! By mistake, Linux could fall into this code.
{$ENDIF}
Per qualsiasi codice non portabile in $IFDEF, è preferibile che il codice sorgente
non venga compilato piuttosto che la piattaforma utilizzi erroneamente una
clausola $ELSE e generi misteriosamente un errore in esecuzione. Gli errori di
compilazione sono più facili da individuare dei malfunzionamenti in esecuzione.
• Utilizzare la sintassi $IF per test complicati. Sostituire $IFDEF annidati con
un’espressione booleana in una direttiva $IF. Si dovrebbe terminare la direttiva
$IF utilizzando $IFEND, non $ENDIF. Ciò consente di collocare espressioni $IF
all’interno di direttive $IFDEF in modo da nascondere la nuova sintassi $IF ai
compilatori precedenti.
Tutte le direttive condizionali sono documentate nella Guida in linea. Per ulteriori
informazioni, consultare anche l’argomento “conditional directives” nella Guida in
linea.
alle DLL) richiedono che tutto il codice sia rilocabile in memoria senza modifiche. Ciò
influisce principalmente sulle routine assembler in linea che utilizzano variabili
globali o altri indirizzi assoluti oppure che chiamano funzioni esterne.
Per le unit che contengono solo codice Delphi, se necessario, il compilatore genera
automaticamente codice PIC. È buona norma compilare ogni unit in entrambi i
formati PIC e non-PIC; utilizzare l’opzione -p del compilatore per generare codice
PIC.
Le unit precompilate sono disponibili in entrambi i formati PIC e non-PIC. Le unit
PIC hanno estensione .dpu (invece di .dcu).
Si potrebbe voler scrivere le routine assembler in modo diverso a seconda che si stia
compilando un eseguibile o una libreria condivisa; utilizzare la direttiva { $IFDEF
PIC} per dividere in due sezioni distinte le due diverse versioni del codice assembler.
Oppure, per evitare il problema, si potrebbe riscrivere la routine in linguaggio
Delphi.
Di seguito sono riportate le regole PIC per il codice assembler in linea:
• PIC richiede che tutti i riferimenti di memoria siano fatti rispetto al registro EBX,
che contiene il puntatore all’indirizzo di base del modulo corrente (in Linux viene
chiamato Global Offset Table o GOT). Pertanto, invece di
MOV EAX,GlobalVar
uso
MOV EAX,[EBX].GlobalVar
• PIC richiede che il registro EBX venga protetto durante le varie chiamate delle
istruzioni in linguaggio macchina (come in Win32), e inoltre che il registro EBX
venga ripristinato prima di effettuare chiamate a funzioni esterne (diversamente da
Win32).
• Benché il codice PIC funzioni negli eseguibili di base, potrebbe però diminuire le
prestazioni e generare molto codice. Negli oggetti condivisi non vi sono
alternative, ma negli eseguibili si vorranno probabilmente ottenere le migliori
prestazioni possibili.
per caratteri multibyte come il giapponese, il cinese, l’ebraico e l’arabo potrebbe non
essere compatibile con la codifica Windows per lo stesso ambiente. Unicode è
portatile, mentre multibyte non lo è. Consultare “Abilitazione del codice
dell’applicazione” a pagina 17-2 per i dettagli relativi alla gestione delle stringhe per
le diverse impostazioni locali nelle applicazioni internazionali.
In Linux, è impossibile utilizzare variabili su indirizzi assoluti. La sintassi:
var X: Integer absolute $1234;
non è supportata in PIC e non è ammessa in un’applicazione CLX.
Tabella 15.6 Differenze fra gli ambienti dei sistemi operativi Linux e Windows
Differenza Descrizione
ensibilità alle maiuscole/ In Linux, i nomi dei file risentono delle differenze fra maiuscole/
minuscole nei nomi di minuscole. Il file Test.txt è un file differente rispetto al file test.txt. In
file Linux è necessario prestare grande attenzione all’uso delle
maiuscole/minuscole nei nomi dei file.
Caratteri di fine riga In Windows, le righe di testo terminano con CR/LF (cioè, ASCII 13 +
ASCII 10), mentre in Linux viene usato solo LF. Benché l’editor di codice
sia in grado di gestire la differenza, è bene ricordarsene quando si importa
del codice in Windows.
Carattere di fine file In MS-DOS e in Windows, il carattere con valore #26 (Ctrl-Z) viene
trattato come la fine del file di testo, anche se, dopo quel carattere, nel
file vi sono dati. Linux utilizza il carattere Ctrl+D come carattere di fine
file.
File batch/procedure di L’equivalente Linux dei file .bat sono gli script della shell. Uno script è
shell un file di testo contenente istruzioni, salvate e rese eseguibile con il
comando, chmod +x <scriptfile>. Il linguaggio di script dipende dalla
shell utilizzata su Linux. Bash è quello comunemente utilizzato.
Tabella 15.6 Differenze fra gli ambienti dei sistemi operativi Linux e Windows (continua)
Differenza Descrizione
Conferma dei comandi In MS-DDOS o in Windows, se si prova a cancellare un file o una
cartella, apparirà una richiesta di conferma (un messaggi del tipo “Si
conferma l’operazione?”). Di solito, Linux non fa alcuna domanda;
eseguirà l’ordine o il comando. In questo modo è molto facile
distruggere casualmente un file o l’intero file system. In Linux non c’è
alcun modo per annullare una cancellazione a meno che non sia stata
fatta una copia di riserva del file su altro supporto.
Risultato dei comandi In Linux, se un comando va a buon fine, viene rivisualizzato il prompt
dei comandi senza alcun messaggio di stato.
Parametri dei comandi Linux utilizza un trattino (-) per indicare un parametro di comando o
un trattino doppio (--) per più caratteri di opzioni mentre il DOS
utilizza una barra (/) o un trattino (-).
File di configurazione In Windows, la configurazione viene fatta nel file di registro o in file
come autoexec.bat.
In Linux, i file di configurazione vengono creati come file nascosti che
iniziano con un punto (.). Molti file sono collocati nella directory /etc
e nella home directory dell’utente.
Linux utilizza inoltre variabili di ambiente come
LD_LIBRARY_PATH (percorso di ricerca per le librerie). Altre
variabili di ambiente importanti sono:
• HOME La directory iniziale dell’utente (/home/sam)
• TERM Il tipo di terminale (xterm, vt100, console)
• SHELL Percorso per la shell (/bin/bash)
• USER Il nome di login dell’utente (sfuller)
• PATH Elenco di ricerca per i programmi
Queste variabili sono specificate nella shell o nei file rc, ad esempio
.bashrc.
DLL/File oggetto Su Linux, si utilizzano file oggetto condivisi (.so). I corrispondenti
condivisi Windows sono le librerie a collegamento dinamico (DLL).
Lettere di unità Linux non ha lettere di unità. Un esempio di percorso Linux è
/lib/security. Fare riferimento a DriveDelim nella libreria di runtime.
Eccezioni Le eccezioni di sistema operativo in Linux vengono chiamate segnali.
File eseguibili In Linux, i file eseguibili non richiedono alcuna estensione. In
Windows, i file eseguibili hanno l’estensione exe..
Estensioni dei nomi di Linux non utilizza estensioni dei nomi di file per identificare i tipi di
file file o per associare i file alle applicazioni.
Permessi sui file In Linux, ai file (e alle directory) vengono assegnati i diritti di lettura,
scrittura ed esecuzione al proprietario di file, al gruppo e ad altri. Ad
esempio,
- è il tipo di file (- = file comune, d = directory, l = collegamento); rwx
sono i permessi concessi al proprietario del file (lettura, scrittura,
esecuzione); r-x sono i permessi concessi al gruppo del proprietario
del file (lettura, esecuzione); e r-x sono i permessi concessi a tutti gli
altri utenti (lettura, esecuzione). L’utente root (superuser) può
ridefinire questi permessi.
È necessario accertarsi che l’applicazione venga eseguita dall’utente
corretto e abbia i corretti accessi per i file necessari.
Tabella 15.6 Differenze fra gli ambienti dei sistemi operativi Linux e Windows (continua)
Differenza Descrizione
Programma di utilità Il programma di utilità Make di Borland non è disponibile sulla
Make piattaforma Linux. Al suo posto è possibile utilizzare il programma di
utilità Make GNU proprio di Linux.
Multitasking Linux supporta completamente il multitasking. È possibile eseguire
contemporaneamente svariati programmi (in Linux, vengono
chiamati processi). È possibile avviare processi in background
(utilizzando il simbolo & dopo il comando) e continuare a operare
tranquillamente. Linux consente anche di avere diverse sessioni.
Nomi dei percorsi Linux utilizza una barra (/) mentre il DOS utilizza una barra
retroversa (\). Per specificare il carattere appropriato per la
piattaforma è possibile utilizzare la costante PathDelim. Fare
riferimento a PathDelim nella libreria di runtime. Vedere “Struttura
delle directory in Linux” a pagina 15-22.
Percorsi di ricerca Per l’esecuzione dei programmi, Windows controlla sempre, come
prima cosa, la directory corrente, quindi guarda nei percorsi
specificati nella variabile di ambiente PATH. Linux non guarda mai
nella directory corrente ma cerca soltanto nelle directory elencate in
PATH. Per eseguire un programma nella directory corrente, di solito è
necessario immettere il carattere ./ prima del nome del programma.
È possibile anche modificare la variabile PATH in modo da includere
./ come primo percorso di ricerca.
Separatore del percorso Windows utilizza il punto e virgola come separatore dei percorsi di
di ricerca ricerca. Linux utilizza il carattere due punti. Fare riferimento a
PathDelim nella libreria di runtime.
Collegamenti simbolici Su Linux, un collegamento simbolico è un file speciale che punta a un
altro file su disco. Se si collocano i collegamenti simbolici nella
directory globale bin che punta ai file principali dell’applicazione non
sarà necessario modificare il percorso di ricerca di sistema. Un
collegamento simbolico viene creato con il comando ln (link).
Windows ha i collegamenti del desktop. Di solito, per rendere un
programma disponibile dalla riga comandi, i programmi di
installazione Windows modificano il percorso di ricerca di sistema.
Registry
Linux non utilizza un file di registro per memorizzare le informazioni di
configurazione. Invece, al posto del file di registro, si utilizzano file di configurazione
di testo e variabili di ambiente. I file di configurazione di sistema su Linux sono
situati spesso in /etc, ad esempio, in /etc/host. Altri profili utente sono situati in file
nascosti (preceduti da un punto), come .bashrc, che contiene impostazioni della shell
bash, oppure .XDefaults, utilizzato per memorizzare le impostazioni predefinite dei
programmi X.
Il codice dipendente dal file di registro può essere modificato in modo da utilizzare
un file di testo di configurazione locale. Le impostazioni modificabili dagli utenti
devono essere salvate nella directory home di ciascun utente, in modo che siano
garantiti i permessi di scrittura. Le opzioni di configurazione che devono eessere
impostate dall’utente root vanno salvate nella directory /etc. Un modo per gestire
una precedente dipendenza dal file di registro è quello di scrivere una unit che
includa tutte le funzioni relative al file di registro, dirigendo però tutto l’output su un
file di configurazione locale.
Per collocare le informazioni in una posizione globale in Linux, si potrebbe
memorizzare un file di configurazione globale nella directory /etc o nella directory
home dell’utente come file nascosto. In questo modo tutte le applicazioni potranno
accedere allo stesso file di configurazione. Tuttavia, è necessario accertarsi che le
autorizzazioni sui file e i diritti di accesso siano configurati correttamente.
Nelle applicazioni multipiattaforma è possibile utilizzare anche i file .ini . Tuttavia,
nella CLX, è necessario utilizzare TMemIniFile invece di TRegIniFile.
Differenze in dbExpress
In Linux, dbExpress gestisce la comunicazione con i server di database. dbExpress è
formato da un gruppo di driver leggeri che implementano un insieme di interfacce
comuni. Ogni driver è un oggetto condiviso (file .so) di cui si deve eseguire il link
nell’applicazione. Poiché dbExpress è progettato per essere multipiattaforma, è
disponibile anche in ambiente Windows come un insieme di librerie a collegamento
dinamico (.dll).
Come qualsiasi altro strato per l’accesso ai dati, anche dbExpress richiede un
software sul lato client fornito dal produttore di database. Inoltre, utilizza un driver
specifico per il database, più due file di configurazione, dbxconnections e dbxdrivers.
Questo è notevolmente meno di quanto sia necessario, ad esempio, per BDE, che
richiede la libreria principale di Borland Database Engine (Idapi32.dll) oltre a un
driver specifico per il database e a molte altre librerie di supporto.
Vi sono altre differenze fra dbExpress e gli altri strati per l’accesso ai dati da cui è
necessario fare il porting. Ad esempio, dbExpress
• Consente un percorso più semplice e più rapido per accedere ai database remoti.
Di conseguenza è lecito aspettarsi un incremento di prestazioni notevole nel caso
di un accesso semplice e diretto ai dati.
• È in grado di elaborare le query e le procedure registrate, ma non supporta il
concetto dell’apertura di tabelle.
• Restituisce solo cursor unidirezionali.
• Non dispone di un supporto interno per l’aggiornamento, se si esclude la capacità
di eseguire una query INSERT, DELETE o UPDATE.
• Non è in grado di collocare in cache i metadati; l’interfaccia per l’accesso ai
metadati in fase di progettazione è implementata utilizzando l’interfaccia di base
per l’accesso ai dati.
• Esegue solo le query richieste dall’utente, ottimizzando pertanto l’accesso al
database dal momento che non vengono introdotte ulteriori query.
• Gestisce internamente un buffer per i record o un blocco di buffer per i record.
Questo comportamento è diverso rispetto a BDE, in cui sono i client a dover
allocare la memoria utilizzata per memorizzare record.
• Supporta solo tabelle locali basate su SQL (come InterBase e Oracle).
• Utilizza i driver per DB2, Informix, InterBase, MSSQL, MySQL, e Oracle. Se si
utilizza un server di database diverso, è necessario convertire i dati in uno di
questi formati di database, oppure scrivere un driver dbExpress appositamente
per il server di database utilizzato oppure, ancora, ottenere un driver dbExpress di
terze parti per il server di database.
confermato. Per fare ciò, fornire al dataset client un gestore di evento AfterPost in
grado di applicare gli aggiornamenti al server di database:
procedure TForm1.ClientDataSet1AfterPost(DataSet: TDataSet);
begin
with DataSet as TClientDataSet do
ApplyUpdates(1);
end;
• È possibile adattare l’interfaccia utente in modo che si occupi degli aggiornamenti
in cache. Questo approccio presenta alcuni vantaggi, come la riduzione delle
quantità di traffico di rete e la riduzione dei tempi di transazione. Tuttavia, se si
passa all’utilizzo di aggiornamenti in cache, occorre decidere quando applicare
quegli aggiornamenti al server di database e probabilmente apportare delle
modifiche all’interfaccia utente per consentire agli utenti di iniziare l’applicazione
degli aggiornamenti o per informarli se le modifiche apportate sono stato
registrate nel database. Inoltre, poiché quando l’utente invia un record gli errori di
aggiornamento non vengono rilevati, sarà necessario modificare il modo in cui
vengono segnalati tali errori all’utente, affinché possano vedere non solo quale
aggiornamento ha causato un problema ma anche che tipo di problema si è
verificato.
Se l’applicazione originale utilizzava il supporto fornito da BDE o da ADO per
aggiornamenti in cache, sarà necessario apportare alcune modifiche nel codice per
passare all’utilizzo di un dataset client. La tabella seguente elenca proprietà, eventi e
metodi che supportano gli aggiornamenti in cache con i dataset BDE e ADO e
proprietà, metodi ed eventi corrispondenti nei TClientDataSet:
Tabella 15.9 Proprietà, metodi ed eventi per gli aggiornamenti in cache (continua)
Sui datasetBDE
(o TDatabase) Sui dataset ADO Su TClientDataSet Scopo
ApplyUpdates UpdateBatch ApplyUpdates Applica al database i record nella
(su dataset o cache locale.
database)
CancelUpdates CancelUpdates o CancelUpdates Rimuove dalla cache locale gli
CancelBatch aggiornamenti in sospeso senza
applicarli.
CommitUpdates Gestito Reconcile Cancella la cache di
automaticamente aggiornamento dopo che
l’applicazione degli
aggiornamenti è andata a buon
fine.
FetchAll Non supportato GetNextPacket Copia i record del database nella
(e PacketRecords) cache locale per l’editing e
l’aggiornamento.
RevertRecord CancelBatch RevertRecord Annulla gli aggiornamenti al
record corrente nel caso gli
aggiornamenti non siano ancora
stati applicati.
Web Broker e non utilizza chiamate API native, non sarà molto difficile eseguire il
porting in Linux.
Se l’applicazione scrive su ISAPI, NSAPI, Windows CGI o altre API per Web, sarà
molto più difficile fare il porting. Sarà necessario ricercare queste chiamate nei file
sorgente e tradurle in chiamate Apache (per i prototipi delle funzione delle API
Apache, consultare il file ..\Source\Internet\httpd.pas) o CGI. È necessario anche
apportare tutte le altre modifiche suggerite descritte nel paragrafo “Porting di
applicazioni VCL” a pagina 15-2.
Capitolo
N In un’applicazione i package condividono i loro dati globali con gli altri moduli.
Per ulteriori informazioni sulle DLL e i package, consultare il manuale Guida al
linguaggio Delphi.
Package di esecuzione
Package di esecuzione
I package di esecuzione vengono distribuiti con le applicazioni. Essi forniscono
funzionalità quando un utente esegue l’applicazione.
Per eseguire un’applicazione che usa i package, un computer deve contenere sia il file
.EXE dell’applicazione sia tutti i package (i file .bpl) che essa utilizza. Affinché
un’applicazione sia in grado di usare i file .bpl, tali file devono essere nel percorso di
ricerca del sistema. Quando si distribuisce un’applicazione, occorre accertarsi che gli
utenti abbiano le versioni corrette di tutte i file .bpl necessari.
Package di esecuzione
N Quando si crea un’applicazione che utilizza i package, si deve sempre includere nella
clausola uses del file sorgente i nomi delle unit originali di Delphi. Per esempio, il file
sorgente della scheda principale potrebbe assomigliare al seguente:
unit MainForm;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs; //Some units in CLX applications differ.
Tutte le unit citate nell’esempio sono contenute nei package vcl e rtl. Ciònonostante, è
necessario mantenere questi riferimenti nella clausola uses, anche se l’applicazione
utilizza i package vcl e rtl, per evitare di ottenere errori di compilazione. Nei file
sorgente generati, queste unit vengono aggiunte automaticamente alla clausola uses
dal Form Designer.
Package di progettazione
netclx per applicazioni server Web, così come è necessario baseclx e probabilmente
visualclx.
vcl;rtl;vcldb;vclx;
N Non è necessario includere vcl ed rtl, in quanto tali package sono referenziati nella
clausola Requires di vcldb. (Vedere “La clausola Requires” a pagina 16-9.)
L’applicazione sarà compilata esattamente allo stesso modo, indipendentemente dal
fatto che i package vcl e rtl siano inclusi o meno nella casella di testo Runtime
Packages.
Un altro modo per determinare quali package vengono chiamati da un applicazione
è quello di eseguirla, quindi revisionare il registro degli eventi (scegliere View|
Debug Windows|Event Log). Il registro degli eventi visualizza ogni modulo che è
stato caricato, inclusi tutti i package. Vengono elencati i nomi completi del package.
Così, ad esempio, per vcl70.bpl si vedrà una riga simile alla seguente:
Module Load: vcl70.bpl Has Debug Info. Base Address $400B0000. Process Project1.exe ($22C)
Package custom
Un package custom è un file bpl scritto e compilato dall’utente oppure un package
esistente fornito da un produttore terzo. Per usare in un’applicazione un package
custom di esecuzione, scegliere Project|Options ed aggiungere alla casella di testo
Runtime Packages nella pagina Packages il nome del package.
Per esempio, si supponga di avere un package di statistica denominato stats.bpl. Per
usarlo in un’applicazione, la riga da immettere nella casella di testo Runtime
Packages sarebbe la seguente:
vcl;rtl;vcldb;stats
Se sono stati creati dei package custom, aggiungerli all’elenco quando è necessario.
Package di progettazione
I package di progettazione vengono usati per installare i componenti nella
Component palette dell’IDE e per creare speciali editor di proprietà per i componenti
custom. I package installati dipendono dall’edizione di Delphi utilizzata e dal fatto
che l’IDE sia stato personalizzato o meno. È possibile vedere una lista dei package
installati nel sistema scegliendo il comando Component|Install Packages.
I package di progettazione funzionano chiamando i package di esecuzione che
vengono referenziati nella propria clausola Requires. (Vedere “La clausola Requires”
a pagina 16-9.) Per esempio, dclstd contiene riferimenti a vcl. Lo stesso dclstd
contiene un’ulteriore funzionalità che rende disponibile nella Component palette
molti dei componenti standard.
Oltre ai package preinstallati, è possibile installare nell’IDE propri package di
componenti, o package di componenti di sviluppatori terzi. Il package di
progettazione dclusr viene fornito come contenitore predefinito per nuovi
componenti.
Package di progettazione
fare clic sul separatore Palette. Il separatore Palette options elenca ciascun
componente installato insieme al nome della pagina della Component Palette in cui
esso appare. Selezionando un componente e facendo clic su Hide, il componente
viene rimosso dalla tavolozza.
Creazione di un package
Per creare un package, seguire la procedura riportata di seguito. Per maggiori
informazioni sui punti qui descritti, consultare “Struttura dei package” a pagina 16-8.
1 Scegliere File|New|Other, selezionare l’icona Package e fare clic su OK. Il
package generato appare nel Package editor. Il Package editor visualizza un nodo
Requires e un nodo Contains per il nuovo package.
2 Per aggiungere una unit alla clausola contains, fare clic sul pulsante Add del
Package editor. Nella pagina Add Unit, scrivere nella casella Unit file name il
nome di un file .pas, oppure fare clic su Browse per ricercare il file, quindi fare clic
su OK. La unit selezionata apparirà sotto il nodo Contains nel Package editor. È
possibile aggiungere altre unit ripetendo la procedura.
3 Per aggiungere una unit alla clausola requires, fare clic sul pulsante Add. Nella
pagina Requires, scrivere nella casella Package name il nome di un file .dcp,
oppure fare clic su Browse per ricercare il file, quindi fare clic su OK. Il package
selezionato appare sotto il nodo Requires nell’editor di Package. È possibile
aggiungere altri package ripetendo questo operazione.
4 Fare clic sul pulsante Options e decidere il tipo di package che si vuol generare.
• Per creare un package utilizzabile solo in fase di progettazione (un package che
non può essere usato in fase di esecuzione), selezionare il pulsante di opzione
Designtime only. (Oppure aggiungere la direttiva al compilatore
{$DESIGNONLY} al file dpk.)
• Per creare un package utilizzabile solo in fase di esecuzione (un package che
non può essere installato), selezionare il pulsante di opzione Runtime only.
(Oppure aggiungere la direttiva al compilatore {$RUNONLY} al file dpk.)
• Per creare un package disponibile in fase di progettazione e di esecuzione,
selezionare il pulsante di opzione Designtime and runtime.
5 Per compilare il package, fare clic nel Package editor sul pulsante Compile.
N È anche possibile fare clic sul pulsante Install per forzare l’esecuzione di make.
Non utilizzare direttive IFDEF in file package (.dpk) quando si scrivono applicazioni
multipiattaforma. Tuttavia è possibile utilizzare gli IFDEF nel codice sorgente.
La clausola Requires
La clausola requires specifica gli altri package esterni usati dal package attivo. Un
package esterno incluso nella clausola requires viene collegato automaticamente in
fase di compilazione a qualsiasi applicazione che usi il package attivo e una delle unit
contenute nel package esterno.
Se i file unit contenuti nel package fanno riferimento ad altre unit presenti in altri
package, questi package dovrebbero apparire nella clausola requires oppure, nel
caso non fossero presenti, li si dovrebbe aggiungere. Se gli altri package vengono
omessi dalla clausola requires, il compilatore li importerà nel package come “unit
contenute implicitamente”.
N La maggior parte dei package che vengono creati richiedono rtl. Se si utilizzano
componenti VCL, sarà necessario includere anche il package vcl. Se si utilizzano
componenti CLX per programmazione multipiattaforma, è necessario includere
VisualCLX.
La clausola Contains
La clausola contains identifica i file unit che devono essere inclusi nel package. Se si
sta scrivendo un package personale, mettere il codice sorgente in file pas e includerli
nella clausola contains.
Compilazione di package
È possibile compilare un package dall’IDE o dalla riga comandi. Per ricompilare
automaticamente un package dall’IDE:
1 Scegliere File|Open e selezionare un package (.dpk).
2 Fare clic su Open
3 Quando si apre il Package editor:
• Fare clic sul pulsante Compile del Package editor
• Nell’IDE, scegliere Porject|Build.
N È anche possibile scegliere File|New|Other e fare doppio clic sull’icona Package. Per
progettare il progetto del package fare clic sul pulsante Install. Fare clic destro nel
nodo package project per le opzioni da installare, compilare o costruire.
Nel codice sorgente del package possono essere inserite delle direttive al
compilatore. Per maggiori informazioni, vedere la sezione “Direttive al compilatore
specifiche per il packaging”.
Quando si compila dalla riga comandi, è possibile utilizzare diverse opzioni del
linker specifiche per i package. Per maggiori informazioni, consultare “Compilazione
e link dalla riga comandi” a pagina 16-13.
Packaging debole
La direttiva $WEAKPACKAGEUNIT influisce sul modo in cui un file .dcu viene
incorporato nei file .dcp e .bpl del package. (Per informazioni sui file generati dal
compilatore, vedere “File package creati durante la compilazione” a pagina 16-13.) Se
in un file di unit appare la direttiva {$WEAKPACKAGEUNIT ON}, il compilatore,
se possibile, omette la unit dai file bpl, e crea una copia locale della unit non
incorporata nel package nel caso sia necessaria per un’altra applicazione o per un
altro package. Le unit compilate in questo modo vengono dette “weakly packaged.”
Si supponga, ad esempio, di aver creato un package chiamato pack1 contenente una
sola unit, unit1. Si supponga che unit1 non faccia uso di altre unit, ma che faccia delle
chiamate a rare.dll. Se quando si compila il package, si inserisce in unit1.pas la
direttiva {$WEAKPACKAGEUNIT ON}, unit1 non verrà inclusa in pack1.bpl. Non
si dovranno distribuire copie di rare.dll insieme a pack1. Tuttavia, unit1 continuerà a
essere inclusa in pack1.dcp. Se unit1 è referenziata da un altro package o da un’altra
applicazione che utilizza pack1, unit1 verrà copiata da pack1.dcp e compilata
direttamente nel progetto.
Ora, si supponga di aggiungere a pack1 una seconda unit, unit2. Si supponga anche
che unit2 utilizzi unit1. Questa volta, anche se si compila pack1 con
{$WEAKPACKAGEUNIT ON}in unit1.pas, il compilatore includerà unit1 in
PACK.bpl. Invece, gli altri package e le altre applicazioni che fanno riferimento a
unit1 utilizzeranno la copia (non inserita nel package) presa da pack1.dcp.
Tabella 16.3 Opzioni del compilatore da riga comandi specifiche per i package
Opzione Scopo
-$G- Disabilita la creazione di riferimenti a dati importati. Questa opzione migliora
l’efficienza di accesso alla memoria, ma impedisce alle unit così compilate di fare
riferimento a variabili contenute in altri package.
-LEpath Specifica la directory in cui verrà collocato il file del package (.bpl).
-LNpath Specifica la directory in cui verrà collocato il file del package (.dcp).
-LUpackage Usa i package.
-Z Impedisce una successiva ricompilazione implicita del package. Viene utilizzato
quando si compilano package con funzionalità a basso livello, modificati
raramente tra un build e il successivo, o il cui codice sorgente non deve essere
distribuito.
Capitolo
Creazione di applicazioni
Capitolo17
17
internazionali
In questo capitolo vengono descritte le linee guida per la scrittura di applicazioni che
si intende immettere sul mercato internazionale. Pianificando per tempo l’obiettivo, è
possibile ridurre la quantità di tempo e di codice necessari per rendere l’applicazione
valida anche sui mercati esteri e non solo su quello interno.
Internazionalizzazione e localizzazione
Per creare un’applicazione che possa essere distribuita nei mercati stranieri, devono
essere effettuate due operazioni fondamentali:
• L’internazionalizzazionen
• La localizzazione
Se l’edizione acquistata include il modulo Translation Tools, è possibile utilizzarlo
per gestire la localizzazione. Per maggiori informazioni, consultare la Guida in linea
relativa a Translation Tools (ETM.hlp).
L’internazionalizzazione
L’internazionalizzazione è il processo che permette al programma di funzionare in
località diverse. Una località è costituita dall’ambiente utente, che comprende le
convenzioni culturali del paese di destinazione e la lingua. Windows supporta molte
località, ciascuna delle quali viene descritta tramite una lingua e una nazione.
Localizzazione
La localizzazione è la procedura di traduzione di un’applicazione in modo che sia in
funzione in una determinata località. Oltre alla traduzione delle stringhe che
appaiono nell’interfaccia utente, la localizzazione comprende l’adattamento delle
funzionalità alle caratteristiche specifiche della nazione. Per esempio, una
applicazione finanziaria può essere modificata a causa delle forme di tassazione
previste nei diversi stati.
Set di caratteri
Le edizioni di Windows per l’occidente (inclusa l’edizione inglese, quella francese e
quella tedesca) utilizzano il set di caratteri ANSI Latin-1 (1252). Altre edizioni di
Windows usano invece set di caratteri differenti. Per esempio, la versione giapponese
di Windows utilizza il set di caratteri Shift-JIS (code page 932), che rappresenta i
caratteri giapponesi come codici di caratteri multibyte.
In generale esistono tre tipi di set di caratteri:
• Singolo byte
• Multibyte
• Caratteri estesi
Windows e Linux supportano entrambi set di caratteri a singolo byte e multibyte
oltre a Unicode. In un set di caratteri a singolo byte, ogni byte in una stringa
rappresenta un carattere. Il set di caratteri ANSI utilizzato da molti sistemi operativi
occidentali è un set di caratteri a singolo byte.
In un set di caratteri multibyte, alcuni caratteri sono rappresentati da un byte e altri
da più di un byte. Il primo byte di un carattere multibyte è chiamato il byte iniziale.
Di solito, i primi 128 caratteri di un set di caratteri multibyte corrispondono ai
caratteri ASCII a 7 bit e tutti i byte il cui valore ordinale è maggiore di 127 è il byte
iniziale di un carattere multibyte. Solo i caratteri a singolo byte possono contenere il
valore null (# 0). I set di caratteri multibyte – in particolare i set a doppio byte (DBCS)
– sono ampiamente utilizzato per le lingue asiatiche.
Occorre tenere presente che la lunghezza delle stringhe in byte non corrisponde
necessariamente alla lunghezza delle stringhe in caratteri. Si deve fare attenzione a
non troncare le stringhe tagliando a metà un carattere multibyte. Non si devono,
Caratteri estesi
Un altro approccio per lavorare con i set di caratteri ideografici è quello di convertire
tutti i caratteri in uno schema di codifica del carattere esteso come Unicode. I caratteri
e le stringhe Unicode sono anche chiamati wide characters e wide character string.
Nel set di caratteri Unicode, ogni carattere è rappresentato da due byte. Pertanto una
stringa Unicode è una sequenza non di singoli byte ma di word composte da due
byte.
I primi 256 caratteri Unicode mappano il set di caratteri ANSI. Il sistema operativo
Windows supporta Unicode (UCS-2). Il sistema operativo Linux supporta UCS-4, un
superset di UCS-2. Delphi supporta UCS-2 su entrambe le piattaforme. Poiché i wide
character sono lunghi due byte anziché uno, il set di caratteri può rappresentare un
numero maggiore di caratteri differenti.
Usando uno schema di codifica dei caratteri esteso, si ha il vantaggio di poter
effettuare molte delle solite assunzioni sulle stringhe che non funzionano per i
sistemi MBCS. C’è una relazione diretta tra il numero di byte e il numero di caratteri
di una stringa. Non occorre preoccuparsi di tagliare i caratteri a metà né di
confondere la seconda metà di un carattere con l’inizio di un altro carattere.
Il maggiore inconveniente quando si lavora con i wide character sta nel fatto che
Windows supporta solo poche chiamate alle funzioni API per i wide character. Per
questo motivo, i componenti VCL rappresentano tutti i valori delle stringhe come
stringhe a un solo byte o MBCS. La traduzione dal sistema wide character al sistema
MBCS tutte le volte che si imposta una proprietà stringa o se ne legge il valore
richiede del codice aggiuntivo che rallenta l’applicazione. Tuttavia, può essere
opportuna la traduzione in caratteri estesi per alcuni algoritmi di elaborazione di
particolari stringhe che hanno bisogno di sfruttare i vantaggi del mappatura 1:1 tra
caratteri e WideChars.
Proprietà BiDiMode
La proprietà BiDiMode controlla l’ordine di lettura per il testo, il posizionamento
della barra di scorrimento verticale, e se è cambiato l’allineamento. I controlli che
hanon una proprietà text, come Name, visualizzano la proprietà BiDiMode nell’Object
Inspector.
La proprietà BiDiMode è un nuovo tipo enumerativo, TBiDiMode, con quattro stati:
bdLeftToRight, bdRightToLeft, bdRightToLeftNoAlign e bdRightToLeftReadingOnly.
bdLeftToRight
bdLeftToRight traccia il testo da sinistra a destra. L’allineamento e le barre di
scorrimento non vengono modificate. Per esempio, quando si immette del testo da
destra a sinistra, come nella lingua araba o ebraica, il cursore entra in modalità
“spinta” e il testo viene introdotto da destra a sinistra. Il testo nelle lingue neolatine,
come l’inglese o il francese, viene immesso da sinistra a destra. bdLeftToRight è il
valore predefinito.
bdRightToLeft
bdRightToLeft traccia il testo da destra a sinistra e non modifica l’allineamento né le
barre di scorrimento. Il testo viene immesso nel solito modo per le lingue, come
l’arabo o l’ebraico, che richiedono l’immissione da destra a sinistra. Quando si
imposta la tastiera per le lingue neolatine, il cursore entra in modalità “spinta” e il
testo viene introdotto da sinistra a destra.
bdRightToLeftNoAlign
bdRightToLeftNoAlign traccia il testo da destra a sinistra, non modifica l’allineamento
e non sposta le barre di scorrimento.
bdRightToLeftReadingOnly
bdRightToLeftReadingOnly riporta il testo da destra a sinistra e non modifica né
l’allineamento né le barre di scorrimento.
Proprietà ParentBiDiMode
ParentBiDiMode è una proprietà booleana. Quando è True (impostazione predefinita),
il controllo cerca il suo genitore per stabilire quale BiDiMode usare. Se il controllo è
un oggetto TForm, la scheda usa l’impostazione di BiDiMode di Application. Se tutte le
proprietà ParentBiDiMode sono True, quando si cambia la proprietà BiDiMode di
Application, tutte le schede e i controlli del progetto vengono aggiornati con la nuova
impostazione.
Metodo FlipChildren
Il metodo FlipChildren consente di invertire la posizione di un figlio del controllo
contenitore. I controlli contenitori sono controlli che accettano altri controlli, come
TForm, TPanel e TGroupBox. FlipChildren ha un unico parametro booleano, AllLevels.
Quando è False, solo i figli diretti del controllo contenitore vengono invertiti. Quando
è True, vengono invertiti tutti i livelli di figli del controllo contenitore.
Delphi inverte i controlli cambiando la proprietà Left e il loro allineamento. Se la
parte sinistra di un controllo di testo è a cinque pixel dal margine sinistro del suo
controllo genitore, una volta invertito la parte destra del controllo di testo è a cinque
pixel dal margine destro del controllo genitore. Se il controllo di testo è allineato a
sinistra, la chiamata di FlipChildren farà sì che lo stesso venga allineato a destra.
Per invertire un controllo in fase di progettazione, occorre selezionare Edit|Flip
Children, quindi All o Selected, a seconda del fatto che si intendano invertire tutti i
controlli o solo i figli del controllo selezionato. È anche possibile invertire un
controllo selezionandolo sulla scheda, facendo clic con il pulsante destro e
selezionando Flip Children dal menu contestuale.
Ulteriori metodi
Ci sono diversi altri metodi che possono essere utilizzati per lo sviluppo di
applicazioni per utenti di lingue bidirezionali.
Testo
Tutto il testo che appare nell’interfaccia utente deve essere tradotto. Il testo in Inglese
è quasi sempre più breve di quello tradotto. Gli elementi dell’interfaccia utente
devono essere progettati in modo da poter accogliere anche testi più lunghi. Le
finestre di dialogo, i menu, le barre di stato e gli altri elementi dell’interfaccia utente
che mostrano del testo devono essere creati in modo da poter visualizzare con facilità
stringhe più lunghe. Occorre evitare le abbreviazioni-che non esistono nelle lingue
che utilizzano caratteri ideografici.
Le stringhe brevi tendono a crescere in fase di traduzione più delle frasi lunghe. La
Tabella 17.2 fornisce una stima approssimativa dell’espansione che si deve prevedere
della lunghezza di una stringa in Inglese:
Immagini
Teoricamente si possono usare immagini che non richiedono traduzione.
Ovviamente, ciò presuppone che esse non contengano testo, il quale richiede sempre
una traduzione. Se si deve inserire del testo nelle immagini, è consigliabile utilizzare
un oggetto etichetta con uno sfondo trasparente sopra un’immagine anziché
includere il testo come parte dell’immagine..
Ci sono altre considerazioni da fare quando si creano immagini. Bisogna evitare, se
possibile, di usare immagini specifiche di una particolare cultura. Per esempio, le
caselle di posta assumono un aspetto diverso a seconda dei paesi. I simboli religiosi
devono essere evitati se l’applicazione è destinata a paesi che hanno religioni
predominanti diverse. Anche i colori possono avere connotazioni simboliche
differenti in culture diverse.
Formati e ordinamento
Il formato della data, dell’ora, dei numeri e della valuta nell’applicazione deve essere
quello del paese a cui l’applicazione è destinata. Se si utilizzano formati specifici di
Windows, non occorre modificarli, in quanto la relativa trasformazione viene
effettuata dal registro di Windows dell’utente. Se, invece, si specificano delle stringhe
di formato proprie, bisogna ricordarsi di dichiararle come costanti di risorsa in modo
che possano essere localizzate.
Anche l’ordine in cui le stringhe vengono ordinate varia da paese a paese. Molte
lingue europee includono dei segni diacritici che sono ordinati in modo diverso a
seconda del paese. Inoltre, in alcun paesi, le combinazioni di due caratteri sono
considerate un singolo carattere in fase di ordinamento. Per esempio, in spagnolo la
combinazione ch viene ordinata come un’unica lettera intermedia tra la c e la d. A
volte un singolo carattere viene ordinato come se fosse costituito da due caratteri
separati, come il tedesco eszett.
Form1: TForm1;
implementation
{$R *.DFM}
function GetLocaleData(ID: LCID; Flag: DWORD): string;
var
BufSize: Integer;
begin
BufSize := GetLocaleInfo(ID, Flag, nil, 0);
SetLength(Result, BufSize);
GetLocaleinfo(ID, Flag, PChar(Result), BufSize);
SetLength(Result, BufSize - 1);
end;
{ Called for each supported locale. }
function LocalesCallback(Name: PChar): Bool; stdcall;
var
LCID: Integer;
begin
LCID := StrToInt('$' + Copy(Name, 5, 4));
Form1.LocaleList.Items.Add(GetLocaleData(LCID, LOCALE_SLANGUAGE));
Result := Bool(1);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
I: Integer;
begin
with Languages do
begin
for I := 0 to Count - 1 do
begin
ListBox1.Items.Add(Name[I]);
end;
end;
end;
Se si vuole che la propria applicazione utilizzi una DLL di risorse diversa da quelle
della località del sistema, si può impostare una voce di ridefinizione della località nel
registro di Windows. Sotto HKEY_CURRENT_USER\Software\Borland\Locales
key, bisogna aggiungere il percorso e il nome di file della propria applicazione come
un valore stringa e impostare il valore dati all’estensione delle proprie DLL di risorse.
All’avvio, l’applicazione cercherà le risorse DLL con questa estensione prima di
verificare qual è il sistema locale. L’impostazione di questa voce nel registro permette
di collaudare le versioni localizzate delle proprie applicazioni senza dover
modificare la località del sistema.
Per esempio, la procedura seguente può essere utilizzata in un programma di
impostazione o di installazione per definire il valore della chiave del registro che
indica la località da utilizzare durante il caricamento delle applicazioni:
procedure SetLocalOverrides(FileName: string, LocaleOverride: string);
var
Reg: TRegistry;
begin
Reg := TRegistry.Create;
try
if Reg.OpenKey(‘Software\Borland\Locales’, True) then
Reg.WriteString(LocalOverride, FileName);
finally
Reg.Free;
end;
All’interno dell’applicazione, per ottenere la gestione della DLL di risorse attiva si
deve usare la funzione globale FindResourceHInstance. Ad esempio:
LoadStr(FindResourceHInstance(HInstance), IDS_AmountDueName, szQuery, SizeOf(szQuery));
È possibile inviare una sola applicazione che si adatti automaticamente alla località
del sistema sul quale verrà eseguita, fornendo semplicemente le DLL di risorse
appropriate.
N Tutte le modifiche apportate alle proprietà della scheda andranno perdute in fase di
esecuzione. Una volta caricata la nuova DLL, non vengono ripristinati i valori
predefiniti. Bisogna evitare di scrivere codice che presuma che gli oggetti della
scheda vengano reinizializzati al loro stato di avvio, al di là delle differenze dovute
alla localizzazione.
Capitolo
Distribuzione di applicazioni
Capitolo 18
18
Una volta che l’applicazione è pienamente funzionante, la si può distribuire. Cioè, è
possibile renderla disponibile ad altri utenti affinché la utilizzino. Per distribuire
un’applicazione da utilizzare su altri computer, occorre effettuare una serie di
operazioni, in modo che essa risulti completamente funzionale. Il numero di passi
necessari varia da un’applicazione all’altra, a seconda del tipo. Le seguenti sezioni
trattano alcune di questi passi da prendere in esame quando si distribuiscono le
seguenti applicazioni:
• Distribuzione di applicazioni generiche
• Distribuzione di applicazioni CLX
• Distribuzione di applicazioni database
• Distribuzione di applicazioni Web
• Programmazione per ambienti di destinazione diversi
• Requisiti per la licenza d’uso del software
• Applicazioni d’ausilio
• Localizzazione di DLL
Applicazioni database e applicazioni Web richiedono ulteriori operazioni. Per
ulteriori informazioni sull’installazione di applicazioni database, consultare
“Distribuzione di applicazioni database” a pagina 18-6. Per maggiori informazioni
sull’installazione di applicazioni Web, consultare “Distribuzione di applicazioni
Web” a pagina 18-9. Per maggiori informazioni sull’installazione di controlli
ActiveX, consultare “Distribuzione di un controllo ActiveX su Web” a pagina 45-16.
File di applicazione
Con un’applicazione potrebbe essere necessario distribuire i seguenti tipi di file.
File package
Se l’applicazione usa dei package di runtime, è necessario che essi vengano
distribuiti insieme all’applicazione. InstallShield Express gestisce l’installazione dei
file package nello stesso modo delle DLL, copiando i file ed apportando le necessarie
modifiche nel registro di Windows. Per la distribuzione di package di esecuzione con
strumenti di installazione basati su MSI, tra cui InstallShield Express, è possibile
anche utilizzare moduli di fusione. Per i dettagli, vedere la sezione successiva.
Borland consiglia di installare i file package di runtime forniti da Borland nella
directory Windows\System. Questa directory serve come dislocazione comune, in
modo che più applicazioni possano accedere a un’unica istanza dei file. Si consiglia
di installare nella stessa directory dell’applicazione anche i package creati. Devono
essere distribuiti solo i file .bpl.
Moduli di fusione
InstallShield Express 3.0 si basa sulla tecnologia di Windows Installer (MSI). Con gli
strumenti di installazione basati su MSI come InstallShield Express, è possibile usare
i moduli di fusione per la distribuzione di package di esecuzione. Ecco perché
include i moduli di fusione. I moduli di fusione forniscono un metodo standard che è
possibile utilizzare per distribuire con le applicazioni codice condiviso, file, risorse,
voci del file di Registro e logica di installazione come un singolo file composto.
Le librerie di esecuzione contengono alcune interdependenze a causa del modo in cui
vengono assemblate. Il risultato è che quando un package viene aggiunto a un
progetto di installazione, lo strumento di installazione aggiunge automaticamente o
segnala una dipendenza da uno o più packages. Per esempio, se si aggiunge il
modulo di fusione VCLInternet a un progetto di installazione, lo strumento di
installazione dovrebbe anche aggiungere automaticamente o segnalare una
dipendenza dai moduli VCLDatabase e StandardVCL.
Le dipendenze per ciascun modulo di fusione sono elencate nella tabella seguente. I
diversi strumenti di installazione possono reagire a queste dipendenze in modo
Controlli ActiveX
Determinati componenti abbinati a sono i controlli ActiveX. Il wrapper del
componente viene collegato al file eseguibile dell’applicazione (o a un package di
runtime), insieme alla quale deve essere distribuito anche il file .ocx per il
componente. Questi componenti comprendono:
• Chart FX, copyright SoftwareFX Inc.
• VisualSpeller Control, copyright Visual Components, Inc.
• Formula One (spreadsheet), copyright Visual Components, Inc.
• First Impression (VtChart), copyright Visual Components, Inc.
• Graph Custom Control, copyright Bits Per Second Ltd.
I controlli ActiveX creati dal programmatore devono essere registrati sul computer di
distribuzione prima di poter essere usati. Programmi di installazione come
InstallShield Express automatizzano questo processo di registrazione. Per registrare
manualmente un controllo ActiveX, scegliere il comando Run|ActiveX Server
nell’IDE, usare l’applicazione demo TRegSvr oppure il programma di utilità
REGSRV32.EXE di Microsoft (non incluso nelle versioni di Windows 9x).
Con un’applicazione devono essere distribuite anche le DLL che supportano i
controlli ActiveX.
Applicazioni di ausilio
Le applicazioni di ausilio sono programmi distinti senza i quali l’applicazione è
parzialmente o completamente impossibilitata a funzionare. Queste applicazioni
possono essere quelle fornite col sistema operativo, da Borland oppure prodotti di
terze parti. Un esempio di applicazione di ausilio è il programma di utilità Server
Manager di InterBase, che amministra i database, gli utenti e la sicurezza di
InterBase.
Se un’applicazione dipende da un programma di ausilio, bisogna accertarsi di
distribuirlo con l’applicazione, se possibile. La distribuzione di programmi di ausilio
N Nel caso di applicazioni database che utilizzano Informix o MSSQL non è possibile
distribuire un eseguibile indipendente. Si deve invece distribuire un file eseguibile
con la DLL del driver (elencata nella tabella seguente).
Se non si sta distribuendo un eseguibile indipendente, è possibile distribuire assieme
all’eseguibile i driver dbExpress associati e le DLL di DataSnap. La seguente tabella
elenca le DLL necessarie e quando includerle:
SetHandler project1-handler
</Location>
Questa modifica consente di passare al modulo di Apache tutte le richieste per
l’indirizzo http://www.somedomain.com/project1.
La direttiva SetHandler specifica l’applicazione Web server che gestisce la richiesta.
L’argomento SetHandler dovrebbe essere impostato al valore della variabile globale
ContentType.
Applicazioni CGI
Se si creano applicazioni CGI, la directory fisica (specificata nella direttiva Directory
del file httpd.conf) deve avere l’opzione ExecCGI e la clausola SetHandler impostate
in modo da consentire l’esecuzione di programmi e poter pertanto eseguire la
procedura CGI. Per essere certi che le autorizzazioni siano configurate correttamente,
utilizzare la direttiva Alias con entrambe le opzioni ExecCGI e SetHandler abilitate.
N Apache viene eseguito in locale sul server, all’interno dell’account specificato nella
direttiva User nel file httpd.conf. Accertarsi che l’utente abbia gli opportuni diritti
per accedere alle risorse necessarie all’applicazione.
Per ulteriori informazioni sulla distribuzione, consultare il file LICENSE di Apache,
incluso nella distribuzione del software. Per ulteriori configurazioni di Apache,
consultare il sito Web Apache all’indirizzo www.apache.org.
del tutto visibile all’interno del desktop su un computer configurato per una
risoluzione di 640x480.
Font
Windows viene distribuito con un set standard di font TrueType e vettoriali. Linux
viene distribuito con un set standard di font, che variano a seconda della
distribuzione. Quando si progetta un’applicazione che deve essere distribuita su altri
computer, bisogna tener conto del fatto che non tutti i computer potrebbero avere
altri font oltre a quelli del set standard.
Tutti i componenti di testo usati nell’applicazione devono usare i font che sono
probabilmente disponibili su tutti i computer di distribuzione.
Quando in un’applicazione è assolutamente necessario usare un font non standard,
occorre distribuire tale font con l’applicazione. Oppure, si deve fare in modo che il
programma di installazione o l’applicazione stessa installino il font sul computer di
distribuzione. La distribuzione dei font di produttori terzi può essere soggetta a
limitazioni imposte da chi ha creato il font.
Windows prevede una misura di sicurezza che consente di usare un font che sul
computer non esiste. Lo sostituisce con un altro font esistente che ritiene essere
quello più simile. Anche se è vero che ciò può impedire l’insorgere di errori relativi
alla mancanza di font, il risultato finale può essere un degrado dell’aspetto visuale
dell’applicazione. È meglio prepararsi a questa eventualità in fase di progettazione.
Per rendere disponibile in un’applicazione Windows un font non standard, usare le
funzioni API di Windows AddFontResource e DeleteFontResource. Distribuire il file .fot
del font non standard con l’applicazione.
DEPLOY
Il documento DEPLOY tratta alcuni aspetti legali connessi alla distribuzione dei
diversi componenti, dei programmi di utilità e di altre aree del prodotto che possono
far parte o essere associati a un’applicazione Delphi. Il documento DEPLOY è
installato nella directory principale di Delphi. Gli argomenti trattati comprendono,
tra l’altro
• .exe, .dll, e .bpl files
• Componenti e package di progettazione
README
Il documento README contiene le informazioni dell’ultimo minuto su Delphi, oltre
a informazioni che potrebbero influenzare i diritti di ridistribuzione dei componenti,
dei programmi di utilità o di altre aree del prodotto. Il documento README è
installato nella directory principale di Delphi.
Accordo di licenza
L’accordo di licenza di Delphi, un documento stampato, tratta gli altri diritti legali e
gli obblighi riguardanti Delphi.
II
Sviluppo di applicazioni database
Part II
Capitolo
Progettazione di applicazioni
Capitolo19
19
database
Le applicazioni database consentono agli utenti di interagire con le informazioni
memorizzate nei database. Questi forniscono la struttura per le informazioni, e ne
consentono la condivisione tra applicazioni differenti.
Delphi fornisce il supporto per le applicazioni database relazionali. I database
relazionali organizzano le informazioni in tabelle, che contengono righe (record) e
colonne (campi). Queste tabelle possono essere manipolate attraverso semplici
operazioni, note come calcoli relazionali.
Nella progettazione di un’applicazione database occorre capire come sono strutturati
i dati. In base alla struttura è possibile, quindi, progettare un’interfaccia per
visualizzare i dati all’utente e consentirgli di immettere nuove informazioni o di
modificare i dati esistenti.
In questo capitolo vengono riportate alcune considerazioni di carattere generale per
la progettazione di un’applicazione database e vengono analizzate le decisioni da
adottare per la definizione di un’interfaccia utente.
Tipi di database
I server di database relazionali agiscono in modo differente a seconda del modo
utilizzato per memorizzare le informazioni e a seconda del modo utilizzato per
permettere a più utenti di accedere contemporaneamente a quelle informazioni.
Delphi fornisce il supporto per due tipi di server database relazionale:
• I server di database remoti di solito risiedono in una macchina separata. A volte, i
dati provenienti da un server di database remoto non risiedere nemmeno in una
singola macchina, ma sono distribuiti su numerosi server. Benché i server di
database remoti si differenzino a seconda del modo utilizzato per memorizzare le
informazioni, essi presentano ai client un’interfaccia logica comune. Questa
interfaccia comune è SQL (Structured Query Language). Poiché si accede ad essi
utilizzando il linguaggio SQL, a volte vengono anche chiamati server SQL. (Un
altro nome utilizzato è Remote Database Management system o RDBMS.) Oltre ai
comuni comandi che compongono il linguaggio SQL, la maggior parte dei server
di database remoti supporta un “dialetto” univoco di SQL. Esempi di server SQL
sono InterBase, Oracle, Sybase, Informix, Microsoft SQL server e DB2.
• I database locali risiedono nell’unità locale o in una rete locale. Essi possiedono
API proprietarie per accedere ai dati. Quando sono condivisi da più utenti, usano
meccanismi di bloccaggio basati su file di database. A causa di ciò, a volte vengono
chiamati database basati su file. Esempi di database locali sono Paradox, dBASE,
FoxPro e Access.
Le applicazioni che usano i database locali sono chiamate applicazioni single-tier
perché l’applicazione e il database condividono un singolo file system. Le
applicazioni che utilizzano i server di database remoti sono definite applicazioni
two-tier o applicazioni multi-tier perché l’applicazione e il database operano su
sistemi (o tier) indipendenti.
La scelta del tipo di database da utilizzare dipende da numerosi fattori. Ad esempio,
i dati possono essere già memorizzati in un database esistente. Se si creano le tabelle
di database che saranno utilizzate dall’applicazione, sarà bene porsi le seguenti
domande:
• Quanti utenti condivideranno queste tabelle? I server di database remoti sono
progettati perché numerosi utenti possano accedervi contemporaneamente. Essi
forniscono il supporto per più utenti attraverso un meccanismo chiamato
transazioni. Anche alcuni database locali (come Local InterBase) forniscono il
supporto per le transazione, mentre la maggior parte fornisce solo meccanismi
basati sul blocco dei file e alcuni (come file dei dataset client) non forniscono
affatto alcun supporto multiutente.
• Quanti dati conterranno le tabelle? I server di database remoti possono contenere
molti più dati dei database locali. Alcuni server di database remoti sono progettati
per immagazzinare grandi quantità di dati mentre altri sono ottimizzati per altri
criteri (come gli aggiornamenti veloci).
• Quale tipo di prestazioni (velocità) si richiedono al database? Di solito i database
locali sono più rapidi dei server di database remoti perché risiedono nello stesso
sistema dell’applicazione database. Server di database remoti differenti sono
Transazioni
Una transazione è un gruppo di azioni che devono essere tutte portate a termine con
successo su una o più tabelle di un database prima che vengano inoltrate (rese
permanenti). Se una delle azioni del gruppo non riesce, tutte le azioni vengono
respinte (annullate).
Le transazioni assicurano che
• Tutti gli aggiornamenti di una singola transazione saranno effettuati oppure
annullati e riportati al loro stato precedente. Questo comportamento viene definito
atomicità.
• Una transazione è una trasformazione corretta dello stato di sistema, che preserva
gli invarianti di stato. Questo comportamento viene definito consistenza.
• Le transazioni simultanee non vedono i rispettivi risultati parziali o non
completati, che potrebbero creare inconsistenze nello stato di applicazione. Questo
comportamento viene definito isolamento.
• Gli aggiornamenti sottoposti ai record sopravvivono ai malfunzionamenti,
compresi i malfunzionamenti dovuti a problemi di comunicazione, di processo e
del sistema server. Questo comportamento viene definito resistenza.
Le transazioni proteggono dai guasti all’hardware che si verificano nel mezzo di un
comando o di un set di comandi del database. La registrazione transazionale
consente di recuperare lo stato resistente dopo un malfunzionamento dei supporti di
memorizzazione su disco. Le transazioni costituiscono anche la base del controllo di
simultaneità multiutente sui server SQL. Quando un utente interagisce con il
database solo tramite le transazioni, i suoi comandi non possono rompere l’unità
della transazione di un altro utente. Invece, il server SQL programma le transazioni
in arrivo, che hanno successo o falliscono globalmente.
Il supporto delle transazioni non è incluso nella maggior parte dei database locali,
anche se è previsto da Local InterBase. Inoltre, i driver BDE forniscono un supporto
transazionale limitato per alcuni database locali. Il supporto delle transazioni sul
database viene fornito dal componente che rappresenta la connessione al database.
Per dettagli sulla gestione delle transazioni utilizzando un componente database
connection, vedere “Gestione delle transazioni” a pagina 23-6.
Nelle applicazioni multi-tiered è possibile creare transazioni che includono azioni
diverse dalle operazioni del database o che riguardano più database. Per
informazioni dettagliate sull’uso delle transazioni nelle applicazioni multi-tier,
consultare “Gestione delle transazioni nelle applicazioni multi-tiered” a
pagina 30-18.
Architettura di un database
Architettura di un database
Le applicazioni database sono costituite dagli elementi dell’interfaccia utente, dai
componenti che rappresentano i dati contenuti dalle tabelle in quei database
(dataset). Il modo di organizzare queste parti genera l’architettura dell’applicazione
database
Struttura generale
Benché esistano molti modi differenti per organizzare i componenti in
un’applicazione database, la maggior parte segue lo schema generale illustrato nella
Figura 19.1:
Figura 19.1 Architettura generale di un database
Architettura di un database
Il modulo dati
Se l’interfaccia utente è stata isolata in schede indipendenti, è possibile utilizzare un
modulo dati per alloggiare i componenti che rappresentano le informazioni di
database (dataset) e i componenti che connettono questi dataset alle altre parti
dell’applicazione. Analogamente alle schede dell’interfaccia utente, è possibile
condividere i moduli dati nell’Object Repository in modo che possano essere
riutilizzati o condivisi tra le applicazioni.
Il datasource
Il primo elemento nel modulo dati è un datasource. Il datasource agisce come un
condotto tra l’interfaccia utente e un dataset che rappresenta le informazioni
contenute in un database. Numerosi controlli data-aware su una scheda possono
condividere un singolo datasource, nel quale caso ciò che viene visualizzato in ogni
controllo è sincronizzato in modo che, man mano che l’utente fa scorrere i record, in
ogni controllo viene visualizzato il valore corrispondente presente nei campi del
record corrente.
Il dataset
Il cuore dell’applicazione database è il dataset. Questo componente rappresenta un
insieme di record provenienti dal database sottostante. Questi record possono essere
i dati di una singola tabella di database, un sottoinsieme dei campi o dei record in
una tabella oppure informazioni provenienti da più tabelle unite in una singola vista.
Grazie all’utilizzo dei dataset, la logica dell’applicazione è esentata dalla necessità di
ristrutturare le tabelle fisiche nei database. Nel caso si cambi il database sottostante,
potrebbe essere necessario modificare il modo in cui il componente dataset specifica i
dati che contiene, ma il resto dell’applicazione potrebbe continuare a funzionare
senza modifiche. Per ulteriori informazioni sulle proprietà e sui metodi comuni dei
dataset, consultare il Capitolo 24, “I dataset”..
La connessione ai dati
I diversi tipi di dataset utilizzano meccanismi differenti per il collegamento alle
informazioni del database sottostante. Questi meccanismi differenti, a loro volta,
sono quelli che comportano le principali differenze nell’architettura delle
applicazioni database che è possibile costruire. Esistono quattro meccanismi di base
per il collegamento ai dati:
• Connessione diretta a un server di database. La maggior parte dei dataset utilizza
un discendente di TCustomConnection per rappresentare la connessione a un server
di database.
• Utilizzo di un file dedicato su disco. I dataset client supportano la capacità di
operare con un file dedicato su disco. Quando si opera con un file dedicato non è
Architettura di un database
Client application
Data module
UI
Data source Connection
Dataset
component
Database server
Architettura di un database
Architettura di un database
Data module
UI
Data source Client dataset File
Architettura di un database
Architettura di un database
tier o two-tier. Via via che la quantità di dati, il numero di utenti e il numero di
applicazioni differenti che accedono ai dati cresce, si può passare gradualmente a
un’architettura multi-tiered. Se si presume che si arriverà a utilizzare
un’architettura multi-tier, può riconvenienete iniziare lo sviluppo utilizzando un
dataset client e un dataset sorgente esterno. In questo modo, quando si sposterà
l’accesso ai dati e la logica di gestione su un tier intermedio, l’investimento fatto in
termini di sviluppo risuletà protetto poiché il codice potrà essere riutilizzato man
mano che l’applicazione cresce.
• TClientDataSet può collegarsi a qualsiasi dataset sorgente. Ciò significa che è
possibile utilizzare dataset custom (componenti forniti da terze parti) per i quali
non esiste alcun dataset client specializzato corrispondente. Alcune versioni di
Delphi includono anche componenti provider particolari che connettono un
dataset client a un documento XML invece che a un altro dataset. Il funzionamento
è analogo alla connessione di un dataset client a un altro dataset (sorgente), salvo
che il provider XML utilizza un documento XML al posto di un dataset. Per
informazioni su questi provider XML, vedere “Impiego di un documento XML
come origine di un provider” a pagina 32-8.)
Esistono due versioni dell’architettura che connette un dataset client a un dataset
esterno:
• Connessione di un dataset client a un altro dataset nella stessa applicazione.
• Utilizzo di un’architettura multi-tier.
Architettura di un database
Client application
Data module
UI
Data source Client dataset
Connection
Dataset Provider
component
Database server
Architettura di un database
UI
Application server
Unidirectional SQL
Provider dataset connection
Database server
Architettura di un database
Scrittura di report
Per consentire agli utenti di stampare le informazioni del database dai dataset
nell’applicazione, si possono usare Rave Report, come descritto in Chapter 21,
“Creazione di report con Rave Reports”.
Capitolo
20
Utilizzo dei controlli dati
Capitolo20
N I controlli associati ai dati più complessi per il supporto decisionale vengono descritti
nel Capitolo 22, “Uso dei componenti di supporto decisionale”.
Indipendentemente dai controlli data-aware che si sceglie di aggiungere
all’interfaccia, si applicano alcune funzionalità comuni. Queste sono descritti nel
prosieguo del capitolo.
N I componenti Datasource sono necessari anche per collegare dataset non annidati
nelle relazioni master-detail.
Per associare un controllo dati a un dataset,
1 Collocare un dataset in un modulo dati (o su una scheda), e impostarne le relative
proprietà nel modo opportuno.
2 Collocare un datasource nello stesso modulo dati (o scheda). Utilizzando l’Object
Inspector, impostarne la proprietà DataSet al nome del dataset collocato al punto 1.
3 Inserire un controllo dati dalla pagina Data Access della Component palette in una
scheda.
4 Utilizzando l’Object Inspector, impostare la proprietà DataSource del controllo al
datasource del componente collocato al punto 2.
5 Impostare la proprietà DataField del controllo al nome di un campo da
visualizzare, o selezionare un nome di campo dall’elenco a comparsa della
proprietà. Questa fase non vale per a TDBGrid, TDBCtrlGrid, e TDBNavigator
perché accedono a tutti i campi disponibili nel dataset.
6 Impostare la proprietà Active del dataset a True per visualizzare i dati del
controllo.
chiamato Post, ma prima che i dati vengano effettivamente registrati nel server di
database sottostante o nella cache locale.
L’evento OnStateChange si verifica quando cambia lo stato del dataset. Quando si
verifica questo evento, è possibile esaminare la proprietà State del dataset per
determinarne lo stato corrente.
Per esempio, il seguente gestore di evento OnStateChange attiva o disattiva i pulsanti
o le voci di menu in base allo stato corrente:
procedure Form1.DataSource1.StateChange(Sender: TObject);
begin
CustTableEditBtn.Enabled := (CustTable.State = dsBrowse);
CustTableCancelBtn.Enabled := CustTable.State in [dsInsert, dsEdit, dsSetKey];
CustTableActivateBtn.Enabled := CustTable.State in [dsInactive];
ƒ
end;
N Per ulteriori informazioni sugli stati del dataset, consultare “Determinazione degli
stati del dataset” a pagina 24-3.
N Il fatto che un dataset client possa aggiornare i dati dipende dal fatto che la tabella
del database sottostante consenta o meno gli aggiornamenti.
Anche se la proprietà CanModify del dataset è impostata True, affinché il controllo
possa registrare gli aggiornamenti nella tabella di database, è necessario impostare a
True anche la proprietà Enabled del datasource che connette il dataset al controllo. La
proprietà Enabled del datasource determina se il controllo può visualizzare i valori
dei campi del dataset e, di conseguenza, se un utente può modificare i valori e
registrare le modifiche. Se Enabled è True (impostazione predefinita), i controlli
possono visualizzare i valori dei campi.
Infine, è possibile controllare anche se l’utente può apportare modifiche ai dati
visualizzati nel controllo. La proprietà ReadOnly del controllo dati determina se un
utente può modificare i dati visualizzati dal controllo. Se è False (impostazione
predefinita), gli utenti possono modificare i dati. Ovviamente, sarà bene assicurarsi
che la proprietà ReadOnly del controllo sia True quando la proprietà CanModify del
dataset è False. In caso contrario, si darà falsamente all’utente l’impressione che possa
influire sui dati nella tabella del database sottostante.
In tutti i controlli dati, ad eccezione di TDBGrid, le modifiche apportate a un campo
vengono copiate nel componente field sottostante in un dataset quando viene
premuto il tasto Tab dal controllo. Se in un campo si preme Esc prima di Tab, il
controllo dati abbandona le modifiche e ripristina il valore del campo antecedente
alle modifiche.
In TDBGrid, le modifiche vengono confermate solo quando si passa a un altro record;
per annullare tutte le modifiche apportate a un qualsiasi record di un campo, è
possibile premere Esc prima di passare a un altro record.
Quando un record viene registrato, Delphi controlla tutti i componenti data-aware
associati al dataset per verificare se vi sono modifiche di stato. Se sorge un problema
di aggiornamento di un campo contenente dati modificati, Delphi solleva
un’eccezione e il record non viene modificato.
N Benché TDBRichEdit fornisca proprietà e metodi per immettere dati e lavorare con un
Rich Text, non fornisce nessun componente di interfaccia utente per rendere
disponibili all’utente queste opzioni di configurazione. L’applicazione deve
implementare l’interfaccia utente per rendere evidenti le capacità relative ai Rich
Text.
Per impostazione predefinita, TDBRichEdit permette a un utente di modificare un
testo di un campo memo. Per impedire editing, impostare la proprietà ReadOnly del
controllo rich edit a True. Per visualizzare i caratteri di tabulazione e permettere agli
utenti di registrarli in un campo memo, impostare la proprietà WantTabs a True. Per
limitare il numero di caratteri che l’utente può immettere nel campo memo del
database, usare la proprietà MaxLength. Il valore predefinito per MaxLength è 0, che
indica che non esiste alcun limite per i caratteri, tranne quello imposto dal sistema
operativo.
Poiché TDBRichEdit può visualizzare grossi volumi di dati, la visualizzazione
completa durante l’esecuzione può richiedere del tempo. Per ridurre il tempo
necessario a scorrere i record dei dati, TDBRichEdit dispone di una proprietà
AutoDisplay che controlla se i dati ai quali si accede devono essere visualizzati
automaticamente. Se si imposta AutoDisplay a False, invece dei dati effettivi
TDBRichEdit visualizza il nome di campo. Per vedere i dati veri e propri, fare doppio
clic sul controllo.
N In esecuzione, gli utenti possono utilizzare la ricerca incrementale per trovare gli
elementi di casella di riepilogo. Appena il controllo riceve il fuoco, ad esempio, se si
immette ’ROB’ sarà selezionato il primo elemento nella casella di riepilogo che inizia
con le lettere ROB. Se si immette un ulteriore carattere ’E’, sarà selezionato il primo
elemento che inizia con ’ROBE’, ad esempio ’Robert Johnson’. La ricerca non tiene
conto della differenza maiuscolo/minuscolo. Backspace ed Esc annullano la stringa di
ricerca corrente (ma lasciano la selezione intatta), analogamente a una pausa di due
secondi tra un tasto e l’altro.
N È possibile anche configurare una colonna in una griglia di dati in modo che agisca
come una casella combinata di consultazione. Per informazioni sulle operazioni,
consultare il paragrafo “Definizione di una colonna elenco di consultazione” a
pagina 20-23.
Se il campo del record attuale contiene valori di “True”, “Yes” o “On” la casella di
controllo viene attivata. Il confronto del campo con le stringhe ValueChecked non fa
differenza fra maiuscole e minuscole. Se un utente controlla una casella per la quale
ci sono stringhe ValueChecked multiple, la prima stringa è il valore che viene
assegnato al database.
Se il controllo non è attivo quando l’utente si sposta su un altro record, occorre
impostare la proprietà ValueUnchecked al valore che il controllo dovrebbe assegnare
al database. Per impostazione predefinita, questo valore è impostato a “False”, ma è
possibile dargli un qualsiasi valore alfanumerico adatto alle proprie esigenze. Mentre
il valore di ValueChecked è attivo, è anche possibile registrare un elenco di elementi
separati con punto e virgola. Se nessuno degli elementi corrisponde ai contenuti del
campo del record corrente, la casella di controllo risulta deselezionata.
Una casella di controllo associata ai dati viene disattivata ogni volta che il campo del
record attuale non contiene uno dei valori elencati nelle proprietà ValueChecked e
ValueUnchecked.
Se il campo a cui è associata una casella di controllo è un campo logico, la casella di
controllo controlla sempre se i contenuti del campo sono True, e si disattiva se i
contenuti del campo sono False. In questo caso, le stringhe immesse nelle proprietà
ValueChecked e ValueUnchecked non hanno effetto sui campi logici.
N Se il campo non coincide con nessuna stringa di Items, è ancora possibile selezionare
un pulsante di opzione a patto che il campo coincida con una stringa della proprietà
Values. Se il campo del record attivo non coincide con nessuna stringa di Items o
Values, non viene selezionato nessun pulsante di opzione.
La proprietà Values può contenere un elenco facoltativo di stringhe che possono
essere restituite al dataset quando un utente seleziona un pulsante di opzione e
assegna un record. Le stringhe vengono associate con i pulsanti in sequenza
numerica. La prima stringa è associata al primo pulsante, la seconda al secondo
pulsante e così via. Supponiamo, ad esempio, che Items contenga “Rosso”, “Giallo” e
Indicatore
di record
Questi tre fattori incidono sull’aspetto dei record visualizzati in un controllo griglia:
• Esistenza di oggetti colonna persistente definiti per la griglia utilizzando l’editor
Columns. Gli oggetti colonna persistente forniscono una grande flessibilità
nell’impostazione dell’aspetto della griglia e dei dati. Per informazioni sull’uso di
colonne persistenti, consultare “Creazione di una griglia personalizzata” a
pagina 20-18.
• Creazione di componenti campo persistente per il dataset visualizzato nella
griglia. Per ulteriori informazioni sulla creazione di componenti campo persistente
usando l’editor Fields, consultare il Capitolo 25, “Operazioni con i componenti
campo”.
• Impostazione della proprietà ObjectView del dataset per le griglie che visualizzano
i campi ADT e i campi array. Consultare “Visualizzazione dei campi ADT e array”
a pagina 20-24.
Un controllo griglia ha una proprietà Columns che è di per sé un wrapper in un
oggetto TDBGridColumns. TDBGridColumns è una raccolta di oggetti TColumn che
rappresentano tutte le colonne di un controllo griglia. Per impostare, in fase di
progettazione, gli attributi delle colonne, si può ricorrere all’editor Columns, oppure
si può usare la proprietà Columns della griglia per accedere alle proprietà, agli eventi
e ai metodi di TDBGridColumns in fase di esecuzione.
N Dal momento che le colonne persistenti non debbono essere associate a un campo del
dataset, e che più colonne possono far riferimento allo stesso campo, la proprietà
FieldCount di una griglia personalizzata può avere un valore inferiore o uguale a
quello della colonna della griglia. Si tenga presente che, se la colonna al momento
selezionata in una griglia personalizzata non è associata a un campo, la proprietà
SelectedField della griglia è NULL e la proprietà SelectedIndex è –1.
Le colonne persistenti possono essere configurate per visualizzare le celle delle
griglie come un elenco a comparsa in una casella combinata di valori di
consultazione di un altro dataset o di un elenco di opzioni statico, o come un pulsante
con puntini di sospensione (…) in una cella su cui si può fare clic per attivare degli
speciali visualizzatori di dati o delle finestre di dialogo correlate alla cella corrente.
per ogni campo nel dataset della griglia viene creata una nuova colonna persistenti.
In esecuzione sarà possibile poi aggiungere una colonna persistente chiamando il
metodo Add della lista di colonne:
DBGrid1.Columns.Add;
N Il riordino dei campi persistenti nel Fields editor riordina anche colonne di una
griglia standard, ma non quelle di una griglia custom.
N Per ripristinare il normale comportamento di una colonna a cui è stata assegnata una
lista esplicita di scelte, cancellare tutto il testo dalla lista di scelte utilizzando lo String
List editor.
Le Figura 20.3 e 20.4 mostrano la griglia con un campo ADT e con un campo array. La
Figura 20.3 mostra i campi ridotti. In questo stato non è possibile modificarli. La
Figura 20.4 mostra i campi espansi. Per espandere e per ridurre i campi, occorre farvi
sopra clic nella barra del titolo dei campi.
La tabella seguente elenca le proprietà che incidono sul modo in cui appaiono i campi
ADT e gli array in un TDBGrid:
Tabella 20.4 Proprietà che influiscono sul modo in cui i campi compositi vengono visualizzati
Proprietà Oggetto Funzione
Expandable TColumn Indica se la colonna può essere espansa in modo da mostrare i
campi figlio in colonne separate e modificabili. (a sola lettura)
Expanded TColumn Specifica se la colonna è espansa.
MaxTitleRows TDBGrid Specifica il numero massimo di righe di titolo che è possibile
visualizzare nella griglia.
ObjectView TDataSet Specifica se i campi sono visualizzati come “scomposti” o in
modo oggetto, in cui ogni campo oggetto può essere espanso e
compresso.
ParentColumn TColumn Fa riferimento all’oggetto TColumn che possiede la colonna del
campo figlio.
N Oltre ai campi di tipo ADT, alcuni dataset includono campi che fanno riferimento a
un altro dataset (campi dataset) o a un record in altri campi dataset (reference). Le
griglie data-aware visualizzano rispettivamente tali campi come “(DataSet)” o
“(Reference)”. In fase di esecuzione, alla destra di tali campi appare un pulsante con
ellissi. Facendo clic sul pulsante con ellissi viene attivata una nuova scheda con una
griglia che visualizza il contenuto del campo. Per i campi dataset, questa griglia
visualizza il dataset che rappresenta il valore del campo. Per campi di riferimento,
questa griglia contiene una singola riga che visualizza il record di un altro dataset.
Ci sono molti usi per questi eventi. Per esempio, si potrebbe scrivere un gestore per
l’evento OnDblClick che richiami un elenco da cui un utente possa scegliere un valore
da inserire in una colonna. Tale gestore userebbe la proprietà SelectedField per
determinare la riga e la colonna attive.
La tabella seguente riporta alcune delle proprietà specifiche delle griglie controllo
database che è possibile impostare in progettazione:
Per ulteriori informazioni sulle proprietà e sui metodi delle griglie controllo
database, consultare la guida in linea VCL Reference.
La Figura 20.6 mostra il navigatore che appare per impostazione predefinita quando,
in fase di progetto, lo si colloca su una scheda. Il navigatore è composto da una serie
di pulsanti che permettono a un utente di spostarsi da un record a un altro di un
dataset e di modificare, cancellare, inserire e assegnare record. La proprietà
VisibleButtons del navigatore consente di nascondere o di mostrare dinamicamente
un sottoinsieme di questi pulsanti.
Figura 20.6 Pulsanti del controllo TDBNavigator
Inserisci record Elimina record corrente
Record
successivo Invia modifiche record
N Non appena i valori del pulsante sono impostati a False, vengono rimossi da
TDBNavigator sulla scheda e i pulsanti che rimangono vengono espansi in ampiezza
per riempire il controllo. È possibile trascinare le maniglie del controllo per
ridimensionare i pulsanti.
cursore del mouse sui pulsanti del navigatore. Per impostazione predefinita
ShowHint è False.
La proprietà Hints controlla il testo del fumetto guida per ciascun pulsante. Per
impostazione predefinita, Hints è una lista di stringhe vuota. Quando Hints è vuota,
ogni pulsante del navigatore visualizza il testo guida predefinito. Per fornire un
fumetto guida personalizzato per i pulsanti del navigatore, usare lo String editor per
registrare nella proprietà Hints una riga separata di testo per il suggerimento
associato a ciascun pulsante. Se presenti, le stringhe create sovrascrivono i
suggerimenti predefiniti forniti dal controllo navigatore.
Panoramica
Rave Reports è uno strumento visuale di report basato su componenti che semplifica
il processo di gestione di report per un’applicazione. È possibile utilizzare Rave
Reports per creare diversi report, da semplici report suddivisi in sezioni a report più
complessi e altamente personalizzati. Le funzioni di Report includono:
• Memo con a capo automatico
• Grafici completi
• Giustificazioni
• Preciso posizionamento di pagina
• Configurazione della stampante
• Controllo di font
• Anteprima stampa
• Riutilizzo dei contenuti di un report
• PDF, HTML, RTF, e report di interpretazioni di testo
Primi passi
È possibile utilizzare Rave Reports sia con applicazioni VCL che con applicazioni
CLX per generare report a partire da dati sia di database, sia non di database. Il
seguente procedimento spiega come sia possibile aggiungere un semplice report ad
un’applicazione database esistente.
1 Aprire l’applicazione database in Delphi.
2 Dalla pagina Rave della Component palette, aggiungere il componente
TRvDataSetConnection a una scheda nell’applicazione.
3 Nell’Object Inspector, impostare la proprietà DataSet a un componente dataset che
sia già stato definito all’interno dell’applicazione.
4 Utilizzare il Rave Visual Designer per progettare il report e per creare un file di
progetto del report (.rav file).
a Scegliere Tools|Rave Designer per avviare Rave Visual Designer.
b Scegliere File|New Data Object per visualizzare la finestra di dialogo Data
Connections.
c Nell’elenco Data Object Type, selezionare Direct Data View e fare clic su Next.
d Nell’elenco Active Data Connections, selezionare RVDataSetConnection1 e fare
clic su Finish.
Nel Project Tree situato alla sinistra della finestra Rave Visual Designer,
espandere il nodo Data View Dictionary, quindi espandere il nodo appena
creato DataView1. I campi dei dati dell’applicazione vengono visualizzati sotto
il nodo DataView1.
e Scegliere Tools|Report Wizards|Simple Table per visualizzare Simple Table
wizard.
f Selezionare DataView1 e fare clic su Next.
g Selezionare due o tre campi che si vogliono visualizzare nel report e fare clic su
Next.
h Seguire i suggerimenti nelle successive pagine del wizard per impostare
l’ordine dei campi, i margini, i titoli e i font che devono essere utilizzati nel
report.
i Nell’ultima pagina del wizard, fare clic su Generate per completare il wizard e
per visualizzare il report in Page Designer.
j Scegliere File|Save as per visualizzare la finestra di dialogo Save As. Passare
alla directory in cui è situata l’applicazione Delphi e salvare il file di progetto
Rave come MyRave.rav.
k Rdurre la finestra di dialogo Rave Visual Designer e ritornare a Delphi.
5 Dalla pagina Rave della Component palette, aggiungere il componente Rave
project, TRvProject, alla scheda.
Per informazioni più dettagliate su come usare Rave Visual Designer, utilizzare il
menu Help o vedere la documentazione riguardante Rave Reports elencata nella
sezione “Per maggiori informazioni” a pagina 21-6.
Componenti VCL/CLX
I componenti VCL/CLX sono componenti non visuali che si aggiungono ad una
scheda in un applicazione VCL o CLX. Essi si trovano nella pagina Rave della
Component palette. Vi sono quattro categorie di componenti: engine, render, data
connection e Rave project.
Componenti Engine
I componenti Engine sono utilizzati per generare i report. I report possono essere
generati da una definizione visuale predefinita (utilizzando la proprietà Engine di
TRvProject), o effettuando chiamate alla libreria API Rave basata su codice
dall’interno dell’evento OnPrint. I componenti engine sono:
TRvNDRWriter
TRvSystem
Componenti Render
I componenti Render vengono utilizzati per convertire un file NDR (file report Rave
snapshot) o uno stream generato da TRvNDRWriter in una vasta gamma di formati.
Il rendering puo’ essere effettuato da programma o aggiunto alla configurazione
standard e alle finestre di dialogo di anteprima di TrvSystem, rilasciando un
componente render su una active forma, o un modulo dati all’interno
dell’applicazione. I componenti render sono:
TRvRenderPreview TRvRenderPrinter
TRvRenderPDF TRvRenderHTML
TRvRenderRTF TRvRenderText
Componenti di progetto
La barra strumenti Project fornisce i mattoni necessari per costruire qualunque
report. I componenti di progetto sono:
TRavePage
TRaveProjectManager
TRaveReport
Data objects
I componenti Data objects consentono la connessione ai dati o controllano l’accesso ai
report dal Rave Reporting Server. Il comando di menu File|New Data Object
visualizza la finestra di dialogo Data Connections, che è possibile utilizzare per
creare uno dei componenti data objects. I componenti data object sono:
TRaveDatabase TRaveDriverDataView TRaveSimpleSecurity
TRaveDirectDataView TRaveLookupSecurity
Componenti Standard
La barra strumenti Standard fornisce componenti che vengono utilizzati
frequentemente durante la progettazione di report. I componenti Standard sono:
TRaveBitmap TRaveMetaFile TRaveText
TRaveFontMaster TRavePageNumInit
TRaveMemo TRaveSection
Componenti Drawing
La barra strumenti Drawing fornisce componenti per creare linee e forme in un
report. Per i componenti che influiscono sul colore o sullo stile, utilizzare le barre
strumenti Fills, Lines, e Colors. I componenti drawing sono:
TRaveCircle TRaveLine TRaveVLine
TRaveEllipse TRaveRectangle
TRaveHLine TRaveSquare
Componenti Report
La barra strumenti Report fornisce componenti che vengono utilizzati molto spesso
in report associati ai dati. I componenti report sono:
Band Style Editor TRaveCalcText TRaveDataMirrorSection
DataText Editor TRaveCalcTotal TRaveDataText
TRaveBand TRaveDataBand TRaveRegion
TRaveCalcController TRaveDataCycle
TRaveCalcOp Component TRaveDataMemo
Capitolo
Panoramica
I componenti di supporto decisionale appaiono sulla pagina Decision Cube della
tavolozza Component:
• Il cubo decisionale, TDecisionCube, è un magazzino dati multidimensionale.
• La sorgente decisionale, TDecisionSource, definisce lo stato del pivot attivo di una
griglia o di un grafico decisionale.
• La query decisionale, TDecisionQuery, è una forma specializzata di TQuery usata
per definire i dati in un cubo decisionale.
• Il pivot decisionale, TDecisionPivot, consente di ingrandire o di rimpicciolire le
dimensioni del cubo decisionale o i campi con la semplice pressione di pulsanti.
• La griglia decisionale, TDecisionGrid, mostra dati mono e multidimensionali in
forma tabellare.
• Il grafico decisionale, TDecisionGraph, mostra i campi di una griglia decisionale
come un grafico dinamico che cambia al variare delle dimensioni dei dati.
La Figura 22.1 mostra tutti i componenti di supporto decisionale collocati su una
scheda in progettazione.
I crosstab
Decision pivot
Decision grid
Decision graph
I crosstab
Le tabelle incrociate, o crosstab, sono un modo di presentare sottoinsiemi di dati per
rendere più evidenti relazioni e andamenti. I campi della tabella diventano le
dimensioni del crosstab mentre i valori dei campi definiscono le categorie e i
riepiloghi all’interno di una dimensione.
È possibile usare i componenti di supporto decisionale per disporre sulle schede i
crosstab. TDecisionGrid mostra i dati in una tabella, mentre TDecisionGraph traccia
graficamente. TDecisionPivot dispone di pulsanti che semplificano la visualizzazione
o l’occultamento delle dimensioni e il loro spostamento tra le colonne e le righe.
I crosstab possono essere monodimensionali o multidimensionali.
Crosstab monodimensionali
I crosstab monodimensionali mostrano una riga (o una colonna) di riepilogo per le
categorie di una singola dimensione. Per esempio, se Payment è la dimensione di
colonna prescelta e Amount Paid è la categoria di riepilogo, il crosstab nella Figura
22.2 mostra l’importo pagato usando ogni singolo metodo.
Figura 22.2 Un crosstab mono-dimensionale
Crosstab multidimensionali
I crosstab multidimensionali usano dimensioni supplementari per le righe e/o per le
colonne. Per esempio, un crosstab bidimensionale può mostrare gli importi pagati in
base al metodo di pagamento per ciascun paese.
Un crosstab tridimensionale può mostrare gli importi pagati in base al metodo e alle
condizioni di pagamento, paese per paese, come mostrato nella Figura 22.3.
Figura 22.3 Crosstab tridimensionale
2 Aggiungere questi componenti alla scheda (usando poi l’Object Inspector per
collegarli come indicato di seguito:
• Un dataset, di solito TDecisionQuery (per maggiori informazioni, consultare
“Creazione di dataset decisionali con l’editor Decision Query” a pagina 22-6) o
TQuery
• Un cubo decisionale, TDecisionCube, collegato al dataset impostando la
proprietà DataSet al nome del dataset
• Una sorgente decisionale, TDecisionSource, collegato al cubo decisionale
impostando la proprietà di DecisionCube al nome del cubo decisionale
3 Aggiungere un pivot decisionale, TDecisionPivot, e collegarlo alla sorgente
decisionale con l’Object Inspector impostando la proprietà DecisionSource al
nome della sorgente decisionale appropriata. Il pivot decisionale è facoltativo ma
utile; permette allo sviluppatore e agli utenti finali della scheda di modificare le
dimensioni visualizzate in griglie o in grafici decisionali con la semplice pressione
di pulsanti.
Nel loro orientamento predefinito, quello orizzontale, i pulsanti sul lato sinistro
del pivot decisionale agiscono sui campi posti sul lato sinistro della griglia
decisionale (le righe); i pulsanti sul lato destro agiscono sui campi della parte
superiore della griglia decisionale (le colonne).
È possibile determinare dove fare apparire i pulsanti del pivot decisionale
impostando la proprietà GroupLayout a xtVertical, xtLeftTop o xtHorizontal
(impostazione predefinita). Per maggiori informazioni sulle proprietà del pivot
decisionale, consultare “Uso dei pivot decisionali” a pagina 22-10.
4 Aggiungere una o più griglie e grafici decisionali, collegandoli alla sorgente
decisionale. Per maggiori informazioni, consultare “Creazione e uso delle griglie
decisionali” a pagina 22-11 e “Creazione e uso dei grafici decisionali” a
pagina 22-14.
5 Usare l’editor della query decisionale o la proprietà SQL di TDecisionQuery (o di
TQuery) per specificare le tabelle, i campi e i riepiloghi da visualizzare nella griglia
o nel grafico. L’ultimo campo dell’istruzione SQL SELECT deve essere il campo di
riepilogo. Gli altri campi nell’istruzione SELECT devono essere i campi di GROUP
BY. Per istruzioni, consultare “Creazione di dataset decisionali con l’editor
Decision Query” a pagina 22-6.
6 Impostare la proprietà Active della query decisionale (o del componente dataset
alternativo) a True.
7 Usare la griglia e il grafico decisionali per mostrare e tracciare sotto forma di
grafico dimensioni dati differenti. Per istruzioni e suggerimenti, consultare “Uso
delle griglie decisionali” a pagina 22-11 e “Uso dei grafici decisionali” a
pagina 22-14.
Per vedere un’illustrazione che riporta tutti i componenti di supporto decisionale
collocati su una scheda, consultare la Figura 22.1 a pagina 22-2.
L’ordinamento dei campi SELECT deve coincidere con quello di GROUP BY.
Con TTable, occorre dire al cubo decisionale quali sono i campi della query da
considerare campi di raggruppamento e quali quelli da considerare campi di
riepilogo. Per eseguire questa operazione, compilare Dimension Type per ciascun
campo in DimensionMap della pagina Decision Cube. Occorre indicare se ciascun
campo è una dimensione o un riepilogo, e se un riepilogo, si deve fornirne il tipo.
Poiché le medie pivot dipendono dai calcoli SUM/COUNT, occorre fornire anche il
nome base del campo per consentire al cubo decisionale di confrontare le coppie di
aggregatori SUM e COUNT.
N Quando si usa l’editor Decision Query, la query inizialmente viene gestita nella
sintassi SQL ANSI-92, quindi tradotta (se necessario) nel dialetto usato dal server.
L’editor Decision Query legge e visualizza solo il formato SQL ANSI standard. La
traduzione del dialetto viene assegnata automaticamente alla proprietà SQL di
TDecisionQuery. Per modificare una query, effettuare l’editing della versione ANSI-92
in Decision Query anziché nella proprietà SQL.
Proprietà ed eventi
Di seguito sono elencate alcune proprietà ed eventi particolari che controllano
l’aspetto e il comportamento delle sorgenti decisionali:
• La proprietà ControlType di TDecisionSource indica se i pulsanti del pivot
decisionale devono agire come caselle di controllo (selezioni multiple) o come
pulsanti di opzione (selezioni mutuamente esclusive).
• Le proprietà SparseCols e SparseRows di TDecisionSource indicano se visualizzare o
meno le colonne o le righe senza valori; se True, vengono visualizzate le colonne o
le righe rade.
• TDecisionSource ha i seguenti eventi:
• OnLayoutChange si verifica quando l’utente esegue rotazioni o compressioni che
riorganizzano i dati.
• OnNewDimensions si verifica quando i dati vengono completamente modificati,
come, ad esempio, quando vengono alterati i campi di riepilogo o delle
dimensioni.
• OnSummaryChange si verifica quando viene modificato il riepilogo attuale.
TDecisionPivot agiscono sui campi posti sul lato sinistro di TDecisionGrid (le righe);
i pulsanti sul lato destro agiscono sui campi posti nella parte superiore di
TDecisionGrid (le colonne).
• È possibile determinare il punto in cui appaiono i pulsanti di TDecisionPivot
impostandone la proprietà GroupLayout a xtVertical, xtLeftTop, o xtHorizontal (che è
il valore predefinito ed è descritto nel paragrafo precedente).
grafici decisionali che sono collegati alla stessa sorgente decisionale presentano le
stesse dimensioni di dati. Per mostrare i diversi dati di riepilogo per le stesse
dimensioni, è possibile collegare più di un grafico decisionale alla stessa sorgente
decisionale. Per mostrare dimensioni diverse, collegare i grafici decisionali a sorgenti
decisionali diverse.
Nella Figura 22.4, ad esempio, il primo pivot decisionale e il primo grafico sono
collegati alla prima sorgente decisionale, mentre il secondo pivot decisionale e il
secondo grafico sono collegati alla seconda. In questo modo, ciascun grafico mostra
dimensioni diverse.
Figura 22.4 Grafici decisionali collegati a sorgenti decisionali diverse
usata. Per maggiori informazioni sulle proprietà e sulle tecniche descritte in questa
sezione, consultare TDecisionCube nella Guida in linea.
Capitolo
Connessione ai database
Capitolo23
23
La maggior parte dei componenti dataset può collegarsi direttamente a un server di
database. Appena connesso, il dataset comunica con il server automaticamente.
Quando si apre il dataset, esso si popola con i dati dal server e quando si registrano i
record, essi vengono restituiti al server e applicati. Un singolo componente
connection SQL può essere condiviso da più dataset oppure ciascun dataset può
utilizzare la propria connessione.
Ogni tipo del dataset si collega al server di database utilizzando il proprio tipo di
componente connection, progettato per funzionare con un singolo meccanismo di
accesso ai dati. La seguente tabella elenca questi meccanismi di accesso ai dati e i
componenti connection associati:
N Per un esame dei pro e dei contro che ognuno di questi meccanismi presenta, vedere
“Uso dei database” a pagina 19-1.
Il componente connection fornisce tutte le informazioni necessarie per stabilire una
connessione al database. Queste informazioni sono diverse per ogni tipo di
componente connection:
• Per informazioni sulla descrizione di una connessione basata su BDE, vedere
“Identificazione del database” a pagina 26-14.
• Per informazioni sulla descrizione di una connessione basata su ADO, vedere
“Connessione a un datastore mediante TADOConnection” a pagina 27-3
N Alcuni componenti connection generano anche altri eventi nel momento in cui
stabiliscono una connessione.
Una volta che la connessione è stata stabilita, tale connessione viene mantenuta attiva
finché c’è almeno un dataset attivo che la utilizza. Quando non ci sono più dataset
attivi, il componente connection rilascia la connessione. Alcuni componenti
connection rendono disponibile una proprietà KeepConnection che permette alla
connessione di rimanere aperta anche se tutti i dataset che la utilizzano sono chiusi.
Se KeepConnection è True, la connessione viene mantenuta aperta. Per connessioni a
server di database remoti o per applicazioni che aprono e chiudono dataset con una
certa frequenza, l’impostazione di KeepConnection a True riduce il traffico di rete e
velocizza l’applicazione. Se KeepConnection è False, la connessione viene interrotta
appena non vi è più alcun dataset attivo che utilizza il database. Se un dataset che
utilizza il database viene aperto in un secondo momento, la connessione deve essere
ristabilita e inizializzata.
alla clausola uses della unit che dichiara il componente connection. L’applicazione
visualizzerà la finestra di dialogo di login standard appena il server richiede un
nome utente e una password.
• Fornire le informazioni di login prima del tentativo di login. Ogni tipo di
componente connection utilizza un meccanismo diverso per la specifica del nome
utente e della password:
• Per i dataset BDE, dbExpress e InterBaseExpress, si può accedere ai parametri
di connessione nome utente e password tramite la proprietà Params. (Per i
dataset BDE, i valori dei parametri possono essere associati anche a un alias
BDE, mentre per i dataset dbExpress possono essere associati anche a un nome
di connessione).
• Per i dataset ADO, il nome utente e la password possono essere inclusi nella
proprietà ConnectionString (o forniti come parametri al metodo Open).
Se si specificano nome utente e password prima che il server li richieda, accertarsi
di impostare il LoginPrompt a False, in modo che non venga visualizzata la finestra
di dialogo login predefinita. Ad esempio, il codice seguente imposta il nome e la
password dell’utente per un componente SQl connection nel gestore di evento
BeforeConnect, decifrando una password crittografata memorizzata associata al
nome di connessione corrente:
procedure TForm1.SQLConnectionBeforeConnect(Sender: TObject);
begin
with Sender as TSQLConnection do
begin
if LoginPrompt = False then
begin
Params.Values['User_Name'] := 'SYSDBA';
Params.Values['Password'] := Decrypt(Params.Values['Password']);
end;
end;
end;
Si noti che l’impostazione del nome utente e della password in fase di
progettazione o l’utilizzo di stringhe direttamente nel codice fa sì che i valori
vengano incorporati nel file eseguibile dell’applicazione. In questo modo, i valori
sono ancora abbastanza facilmente reperibili, compromettendo in tal modo la
sicurezza del server.
• Preparare la propria gestione custom per l’evento di login. Il componente
connection genera un evento quando ha bisogno del nome utente e della
password.
• Per TDatabase, TSQLConnection e TIBDatabase questo è un evento OnLogin. Il
gestore di evento ha due parametri, il componente connection e una copia
locale dei parametri nome utente e password in una lista di stringhe.
(TSQLConnection include anche il parametro database). Perché questo evento si
verifichi, è necessario impostare la proprietà LoginPrompt a True. Un valore di
LoginPrompt impostato a False e l’assegnazione di un gestore all’evento OnLogin
crea una situazione in cui è impossibile connettersi al database perché la
delle transazioni” a pagina 23-10.) Per gestire più transazioni simultanee, impostare
il campo TransactionID del descrittore di transazione a un valore univoco.
TransactionID può essere un qualsiasi valore scelto dall’utente, a patto che sia
univoco (non sia cioè in conflitto con una qualsiasi altra transazione attualmente in
esecuzione). A seconda del server, le transazioni avviate da TSQLConnectionpossono
essere annidate (come quando si utilizza ADO) o sovrapposte.
var
TD: TTransactionDesc;
begin
TD.TransactionID := 1;
TD.IsolationLevel := xilREADCOMMITTED;
SQLConnection1.StartTransaction(TD);
Pe impostazione predefinita, nel caso di transazioni sovrapposte, la prima
transazione diventa inattiva non appena parte la seconda transazione, benché sia
possibile rimandare la conferma o l’annullamento della prima transazione ad una
fase successiva. Se si utilizza TSQLConnection con un database InterBase, è possibile
identificare ogni dataset nell’applicazione con una particolare transazione attiva,
impostandone la proprietà TransactionLevel. Ciò significa che, dopo avere avviato una
seconda transazione, è possibile continuare a gestire contemporaneamente entrambe
le transazioni, semplicemente associando un dataset alla transazione che si desidera.
MyOracleConnection.Commit;
Anche per TSQLConnection si utilizza il metodo Commit ma è necessario specificare
quale transazione si sta convalidando fornendo lo stesso descrittore della transazione
passato al metodo StartTransaction:
MyOracleConnection.Commit(TD);
Per TIBDatabase, si convalida un oggetto transazione utilizzando il metodo Commit:
IBDatabase1.DefaultTransaction.Commit;
Per TADOConnection, si convalida una transazione utilizzando il metodo
CommitTrans:
ADOConnection1.CommitTrans;
• Nella porzione di codice che gestisce l’eccezione, nel caso sia impossibile
ripristinare un errore di database.
• Nel codice dell’evento di un pulsante o di un menu, ad esempio quando l’utente fa
clic su un pulsante Cancel.
di isolamento più elevato (se disponibile). Se non c’è alcun livello più elevato
disponibile, appena si prova ad avviare una transazione il componente connection
solleva un’eccezione.
Utilizzando TSQLConnection, il livello di isolamento della transazione è controllato
dal campo IsolationLevel del descrittore della transazione.
Utilizzando InterBase Express, il livello di isolamento della transazione è controllato
da un parametro della transazione.
N Execute può solo eseguire un’istruzione SQL alla volta. Non è possibile per eseguire
più istruzioni SQL con una singola chiamata a Execute, come di solito si fa con i
programmi di utilità di scrittura di codice SQL. Per eseguire più di un’istruzione,
chiamare Executepiù volte.
È relativamente facile eseguire un’istruzione che non include nessun parametro. Ad
esempio, il seguente codice esegue un’istruzione CREATE TABLE (DDL) senza alcun
parametro su un componente TSQLConnection:
procedure TForm1.CreateTableButtonClick(Sender: TObject);
var
SQLstmt: String;
begin
SQLConnection1.Connected := True;
SQLstmt := 'CREATE TABLE NewCusts ' +
'( ' +
' CustNo INTEGER, ' +
' Company CHAR(40), ' +
' State CHAR(2), ' +
' PRIMARY KEY (CustNo) ' +
')';
SQLConnection1.Execute(SQLstmt, nil, nil);
end;
Per utilizzare parametri, è necessario creare un oggetto TParams. Per ogni valore di
parametro, utilizzare il metodo TParams.CreateParam per aggiungere un oggetto
TParam. Quindi utilizzare le proprietà di TParam per descrivere il parametro e
impostarne il valore.
Questo procedimento è illustrato nell’esempio seguente che utilizza TDatabase per
eseguire un’istruzione INSERT. L’istruzione INSERT ha un singolo parametro con
nome :StateParam. Viene creato un oggetto TParams (di nome stmtParams) per fornire
il valore “CA” a quel parametro.
procedure TForm1.INSERT_WithParamsButtonClick(Sender: TObject);
var
SQLstmt: String;
stmtParams: TParams;
begin
stmtParams := TParams.Create;
try
Database1.Connected := True;
stmtParams.CreateParam(ftString, 'StateParam', ptInput);
stmtParams.ParamByName('StateParam').AsString := 'CA';
SQLstmt := 'INSERT INTO "Custom.db" '+
'(CustNo, Company, State) ' +
'VALUES (7777, "Robin Dabank Consulting", :StateParam)';
Database1.Execute(SQLstmt, stmtParams, False, nil);
finally
stmtParams.Free;
end;
end;
Se l’istruzione SQL include un parametro ma non è stato preparato un oggetto
TParam per fornirgli un valore, l’istruzione SQL può generare un errore al momento
Ottenimento di metadati
I: Integer;
begin
with MyDBConnection do
begin
for I := 0 to DataSetCount - 1 do
DataSets[I].DisableControls;
end;
end;
Ottenimento di metadati
Tutti i componenti database connection possono acquisire dal server di database liste
di metadati, benché essi si differenzino in base al tipo di metadati che acquisiscono. I
metodi per l’acquisizione di metadati riempiono una lista di stringhe con i nomi delle
diverse entità disponibili sul server. È possibile utilizzare quindi queste
informazioni, ad esempio, per permettere agli utenti di selezionare dinamicamente
una tabella in fase di esecuzione.
È possibile utilizzare un componente TADOConnection per acquisire metadati sulle
tabelle e sulle procedure registrate disponibili nel datastore ADO. È possibile
utilizzare quindi queste informazioni, ad esempio, per permettere agli utenti di
selezionare dinamicamente una tabella o una procedura registrata in fase di
esecuzione.
Ottenimento di metadati
Ottenimento di metadati
Capitolo
24 I dataset
Capitolo24
I dataset 24-1
Copyright © 11/29/00, Inprise Corporation. All rights reserved. INPRISE CONFIDENTIAL
November 29, 2000 2:20 pm (J:\source\Devguide\BOOK\Delphonly\1_intro.fm5)
I dataset 24-3
Copyright © 11/29/00, Inprise Corporation. All rights reserved. INPRISE CONFIDENTIAL
November 29, 2000 2:20 pm (J:\source\Devguide\BOOK\Delphonly\1_intro.fm5)
I dataset 24-5
Copyright © 11/29/00, Inprise Corporation. All rights reserved. INPRISE CONFIDENTIAL
November 29, 2000 2:20 pm (J:\source\Devguide\BOOK\Delphonly\1_intro.fm5)
l’interfaccia utente (ad esempio, per aggiornare una barra di stato riporta
informazioni sul record corrente).
TDataSet definisce due proprietà booleane che forniscono informazioni utili sulla
posizione del cursore tra i record di un dataset.
I dataset 24-7
Copyright © 11/29/00, Inprise Corporation. All rights reserved. INPRISE CONFIDENTIAL
November 29, 2000 2:20 pm (J:\source\Devguide\BOOK\Delphonly\1_intro.fm5)
Eof
Quando Eof è True, indica che il cursore è inequivocabilmente posizionato sull’ultima
riga di un dataset. Eof è impostato a True quando un’applicazione:
• Apre un dataset vuoto.
• Chiama il metodo Last di un dataset.
• Chiama il metodo Next di un dataset e il metodo non riesce a compiere alcuna
operazione (perché il cursore si trova all’ultima riga del dataset).
• Chiama SetRange su un intervallo o dataset vuoto.
In tutti gli altri casi, Eof è False; si deve presupporre che Eof sia False, a meno che si
verifichi una delle suddette condizioni e la proprietà è stata verificata direttamente.
Eof viene comunemente verificata in una condizione di ciclo, per controllare
l’elaborazione in sequenza di tutti i record di un dataset. Se viene aperto un dataset
contenente record (o se viene chiamato First) Eof è False. Per elaborare tutti record nel
dataset uno per volta, creare un ciclo che si sposta di record in record chiamando il
metodo Next e termini quando Eof è False. Eof rimarrà False finché non si chiama Next
e il cursore è già posizionato sull’ultimo record.
Il seguente codice illustra un modo per impostare un ciclo di elaborazione dei record
per un dataset denominato CustTable:
CustTable.DisableControls;
try
CustTable.First; { Go to first record, which sets Eof False }
while not CustTable.Eof do { Cycle until Eof is True }
begin
{ Process each record here }
ƒ
CustTable.Next; { Eof False on success; Eof True when Next fails on last record }
end;
finally
CustTable.EnableControls;
end;
Bof
Quando Bof è True, indica che il cursore è posizionato inequivocabilmente sulla
prima riga di un dataset. Bof è impostato a True quando un’applicazione:
• Apre un dataset.
• Chiama il metodo First di un dataset.
• Chiama il metodo Prior di un dataset e il metodo non riesce a compiere alcuna
operazione (perché il cursore si trova alla prima riga del dataset).
• Chiama SetRange su un intervallo o dataset vuoto.
Bof è False in tutti gli altri casi; si deve presupporre che Bof sia False, a meno che si
verifichi una delle suddette condizioni e la proprietà è stata verificata direttamente.
Come Eof, Bof può essere inserita in una condizione di ciclo per controllare
l’elaborazione in sequenza dei record di un dataset. Il seguente codice illustra un
modo per impostare un ciclo di elaborazione dei record per un dataset denominato
CustTable:
CustTable.DisableControls; { Speed up processing; prevent screen flicker }
try
while not CustTable.Bof do { Cycle until Bof is True }
begin
{ Process each record here }
ƒ
CustTable.Prior; { Bof False on success; Bof True when Prior fails on first record }
end;
finally
CustTable.EnableControls; { Display new current row in controls }
end;
I dataset 24-9
Copyright © 11/29/00, Inprise Corporation. All rights reserved. INPRISE CONFIDENTIAL
November 29, 2000 2:20 pm (J:\source\Devguide\BOOK\Delphonly\1_intro.fm5)
La proprietà Bookmark
La proprietà Bookmark indica quale segnalibro tra un qualsiasi numero di segnalibri
dell’applicazione è quello corrente. Bookmark è una stringa che identifica il segnalibro
attuale. Ogni volta che si aggiunge un altro segnalibro, questo diviene il segnalibro
corrente.
Il metodo GetBookmark
Per creare un segnalibro, è necessario dichiarare nell’applicazione una variabile di
tipo TBookmark e chiamare quindi GetBookmark per allocare un’area di memoria per la
variabile e impostarne il valore a una posizione specifica del dataset. Il tipo
TBookmark è un puntatore.
Il metodo CompareBookmarks
Si può chiamare CompareBookmarks anche per vedere se un segnalibro al quale ci si
desidera muovere è diverso da un altro (o da quello corrente). Se i due segnalibri
fanno riferimento allo stesso record (o se entrambi sono nil), CompareBookmarks
restituisce 0.
Il metodo FreeBookmark
FreeBookmark libera la memoria assegnata a un determinato segnalibro, quando
quest’ultimo non serve più. È opportuno chiamare FreeBookmark prima di riutilizzare
un segnalibro esistente.
Uso di Locate
Locate posiziona il cursore sulla prima riga corrispondente a un insieme specificato di
criteri di ricerca. Nella forma più semplice, a Locate viene passato il nome di una
colonna in cui eseguire la ricerca, un valore di campo che rappresenta il criterio di
ricerca e un flag di opzioni che specifica se la ricerca deve differenziare i caratteri
maiuscoli e minuscoli o se è valida la corrispondenza parziale alle chiavi. (Per
corrispondenza di chiave parziale si intende la condizione per cui è sufficiente che la
stringa di criterio corrisponda alla parte iniziale del valore del campo). Per esempio,
il seguente codice sposta il cursore alla prima riga di CustTable, dove il valore della
colonna Company è ”Professional Divers, Ltd.”:
var
LocateSuccess: Boolean;
SearchOptions: TLocateOptions;
begin
SearchOptions := [loPartialKey];
LocateSuccess := CustTable.Locate('Company', 'Professional Divers, Ltd.', SearchOptions);
end;
Se Locate trova una corrispondenza, il primo record contenente la corrispondenza
diventa il record corrente. Locate restituisce True se trova un record corrispondente,
False in caso contrario. Se non vengono trovate corrispondenze, il record corrente non
cambia.
La vera potenza di Locate può essere apprezzata quando si desidera effettuare
ricerche su più colonne e specificare valori multipli da cercare. I valori da cercare
sono Variant, pertanto è possibile specificare tipi di dati diversi nei criteri di ricerca.
Per specificare più colonne in una stringa di ricerca, separare le singole voci della
stringa con un punto e virgola.
I dataset 24-11
Copyright © 11/29/00, Inprise Corporation. All rights reserved. INPRISE CONFIDENTIAL
November 29, 2000 2:20 pm (J:\source\Devguide\BOOK\Delphonly\1_intro.fm5)
Poiché i valori da cercare sono Variant, se si passano più valori è necessario o passare
come argomento un array Variant (per esempio, i valori restituiti dal metodo Lookup),
oppure occorre costruire nel codice l’array Variant utilizzando la funzione
VarArrayOf. Il seguente codice illustra una ricerca eseguita su più colonne, adottando
valori di ricerca multipli e accettando la corrispondenza parziale alle chiavi:
with CustTable do
Locate('Company;Contact;Phone', VarArrayOf(['Sight Diver','P']), loPartialKey);
Locate adotta il metodo più veloce possibile per trovare record corrispondenti. Se le
colonne in cui effettuare la ricerca sono indicizzate e l’indice è compatibile con le
opzioni di ricerca specificate, Locate utilizza l’indice.
Uso di Lookup
Lookup cerca la prima riga corrispondente ai criteri di ricerca specificati. Se trova una
riga corrispondente, determina la rielaborazione dei campi calcolati e dei campi di
ricerca associati al dataset, quindi restituisce uno o più campi tratti dalla riga
corrispondente. Lookup non sposta il cursore sulla riga corrispondente, ma restituisce
solo valori estratti da essa.
Nella forma più semplice, a Lookup viene passato il nome del campo in cui eseguire la
ricerca, il valore di campo che rappresenta il criterio di ricerca e il campo o i campi da
restituire. Per esempio, il seguente codice cerca il primo record di CustTable in cui il
valore del campo Company sia ”Professional Divers, Ltd.” e restituisce il nome
dell’azienda, la persona da contattare e il numero di telefono dell’azienda:
var
LookupResults: Variant;
begin
LookupResults := CustTable.Lookup('Company', 'Professional Divers, Ltd.',
'Company;Contact; Phone');
end;
Lookup restituisce i valori per i campi specificati dal primo record corrispondente che
trova. I valori vengono restituiti come Variant. Se viene richiesto più di un valore,
Lookup restituisce un array Variant. Se non esiste alcun record corrispondente, Lookup
restituisce un Variant Null. Per maggiori informazioni sugli array Variant, consultare
la Guida in linea.
L’effettiva potenza di Lookup entra in gioco quando si vogliono effettuare ricerche su
più colonne e si specificano più valori da cercare. Per specificare stringhe contenenti
più colonne o campi risultato, separare i singoli campi degli elementi della stringa
con dei punti e virgola.
Poiché i valori da cercare sono Variant, se si passano più valori è necessario o passare
come argomento un array Variant (per esempio, i valori restituiti dal metodo Lookup),
oppure occorre costruire nel codice l’array Variant utilizzando la funzione
VarArrayOf. Il codice seguente illustra una ricerca di lookup su più colonne:
var
LookupResults: Variant;
begin
with CustTable do
N I filtri valgono per ogni record reperito in un dataset. Quando devono essere filtrati
volumi ingenti di dati, invece di utilizzare i filtri può essere più efficace ricorrere a
una query per limitare il reperimento dei record, oppure impostare un intervallo in
una tabella indicizzata.
I dataset 24-13
Copyright © 11/29/00, Inprise Corporation. All rights reserved. INPRISE CONFIDENTIAL
November 29, 2000 2:20 pm (J:\source\Devguide\BOOK\Delphonly\1_intro.fm5)
Creazione di filtri
Ci sono due modi per creare un filtro per un dataset:
• Specificare semplici condizioni di filtro nella proprietàFilter. Filter è utile
soprattutto per creare e applicare filtri in fase di esecuzione.
• Scrivere un gestore di evento OnFilterRecord per condizioni del filtro semplici o
complesse. Con OnFilterRecord, si specificano in fase di progetto le condizioni di
filtro. A differenza della proprietà Filter, che è limitata a una singola stringa che
contiene la logica del filtro, un evento OnFilterRecord può sfruttare salti
condizionali e cicli per creare complesse condizioni di filtro multi-livello.
Il vantaggio principale di creare filtri usando la proprietà Filter è che un’applicazione
può creare, modificare e applicare dinamicamente filtri, (per esempio, in risposta a
un input dell’utente). Lo svantaggio principale consiste nel fatto che le condizioni del
filtro devono essere esprimibili in una singola stringa di testo, non si può far uso di
costrutti di diramazione condizionale o ciclici, e non è possibile verificare o
confrontare valori con valori che non siano già presenti nel dataset.
I vantaggi dell’evento OnFilterRecord sono che un filtro può essere complesso e
variabile, può essere basato su molte righe di codice che usano strutture condizionali
e cicliche, e può confrontare valori del dataset con valori esterni al dataset, come ad
esempio il testo in una casella di testo. Il principale punto debole di OnFilterRecord è
che si imposta il filtro in fase di progetto e quindi non può essere cambiato in risposta
a un input dell’utente. (È comunque possibile creare molti gestori di filtro e passare
dall’uno all’altro in risposta alle condizioni generali di un’applicazione).
Le sezioni che seguono descrivono come creare filtri usando la proprietà Filter e il
gestore di evento OnFilterRecord.
N Dopo aver specificato un valore di Filter, si imposti a True la proprietà Filtered per
applicare il filtro al dataset.
I filtri possono confrontare i valori dei campi con letterali e costanti usando i seguenti
operatori logici e di confronto:
I dataset 24-15
Copyright © 11/29/00, Inprise Corporation. All rights reserved. INPRISE CONFIDENTIAL
November 29, 2000 2:20 pm (J:\source\Devguide\BOOK\Delphonly\1_intro.fm5)
I dataset 24-17
Copyright © 11/29/00, Inprise Corporation. All rights reserved. INPRISE CONFIDENTIAL
November 29, 2000 2:20 pm (J:\source\Devguide\BOOK\Delphonly\1_intro.fm5)
Tabella 24.7 Metodi dei dataset per inserire, aggiornare e cancellare dati
Metodo Descrizione
Edit Imposta il dataset in modalità dsEdit, se già non è nello stato dsEdit o dsInsert.
Append Invia i dati in attesa, sposta il record attivo alla fine del dataset e pone il dataset in
modalità dsInsert.
Insert Invia i dati in attesa e pone il dataset in modalità dsInsert.
Post Cerca di registrare nel database il record nuovo o modificato. Se l’operazione riesce,
il dataset torna allo stato dsBrowse; se non riesce, il dataset rimane nello stato
corrente.
Cancel Annulla l’operazione corrente e pone il dataset in modalità dsBrowse.
Delete Cancella il record corrente e pone il dataset in modalità dsBrowse.
N Anche se un dataset è nello stato dsEdit, la modifica dei record può non riuscire per i
database basati su SQL se l’utente dell’applicazione non possiede i privilegi di
accesso SQL appropriati.
Quando un dataset è in modalità dsEdit, un utente può modificare i valori dei campi
del record corrente che appaiono nei controlli associati ai dati di una scheda. I
controlli associati ai dati per i quali la modifica è consentita chiamano
automaticamente Post quando un utente esegue un’operazione che cambia il record
corrente (per esempio lo spostamento a un altro record in una griglia).
Se nelle schede è previsto un componente Navigator, gli utenti possono annullare le
modifiche facendo clic sul pulsante Cancel del Navigator. Annullando le modifiche,
viene ripristinato lo stato dsBrowse del dataset.
N Anche se un dataset è nello stato dsInsert, l’aggiunta di record può non andare a buon
fine per i database basati su SQL nel caso l’utente dell’applicazione non abbia i
privilegi di accesso SQL appropriati.
Quando un dataset è in modalità dsInsert, un utente o un’applicazione può immettere
valori nei campi associati al nuovo record. Ad eccezione dei controlli griglia e
Navigator, non esistono differenze visibili a un utente tra Insert e Append. Chiamando
Insert, nella griglia appare una riga vuota sopra quello che era il record corrente.
Chiamando Append, la griglia viene fatta scorrere fino all’ultimo record del dataset,
I dataset 24-19
Copyright © 11/29/00, Inprise Corporation. All rights reserved. INPRISE CONFIDENTIAL
November 29, 2000 2:20 pm (J:\source\Devguide\BOOK\Delphonly\1_intro.fm5)
appare una riga vuota nella parte inferiore della griglia e i pulsanti Next e Last
vengono disattivati in qualsiasi componente Navigator associato al dataset.
I controlli associati ai dati per i quali è consentito l’inserimento chiamano
automaticamente Post quando un utente esegue un’operazione che cambia il record
corrente (per esempio lo spostamento a un altro record in una griglia). in caso
contrario, Post deve essere chiamato nel codice.
Post scrive il nuovo record nel database oppure, se sono abilitati gli aggiornamenti in
cache, Post scrive il record in una cache in memoria. Per scrivere nel database gli
inserimenti e le aggiunte in cache, chiamare il metodo ApplyUpdates del dataset.
Inserimento di record
Insert apre un nuovo record vuoto prima del record corrente e imposta il record
vuoto come record corrente, cosicché l’utente o il codice dell’applicazione possa
immettervi valori di campi.
Quando un’applicazione chiama Post (o ApplyUpdates se gli aggiornamenti in cache
sono consentiti), un record appena inserito può essere scritto nel database in tre
modi:
• Per le tabelle Paradox e dBASE indicizzate, il record viene inserito nel dataset in
una posizione basata sul relativo indice.
• Per le tabelle Paradox e dBASE non indicizzate, il record viene inserito nel dataset
nella posizione corrente.
• Per i database SQL, il punto di inserimento fisico dipende dall’implementazione.
Se la tabella è indicizzata, l’indice viene aggiornato con le informazioni del nuovo
record.
Aggiunta di record
Append apre un nuovo record vuoto alla fine del dataset e lo imposta come record
corrente, cosicché un utente o il codice dell’applicazione possa immettervi valori di
campi.
Quando un’applicazione chiama Post (o ApplyUpdates se gli aggiornamenti in cache
sono consentiti), un record appena inserito può essere scritto nel database in tre
modi:
• Per le tabelle Paradox e dBASE indicizzate, il record viene inserito nel dataset in
una posizione basata sul relativo indice.
• Per le tabelle Paradox e dBASE non indicizzate, il record viene aggiunto alla fine
del dataset.
• Per i database SQL, il punto fisico in cui avviene l’aggiunta dipende
dall’applicazione. Se la tabella è indicizzata, l’indice viene aggiornato con le
informazioni del nuovo record.
Cancellazione di record
Utilizzare il metodo Delete per cancellare il record corrente in un dataset attivo.
Quando si chiama il metodo Delete,
• Il dataset riceve un evento BeforeDelete.
• Il dataset tenta di cancellare il record corrente.
• Il dataset ritorna allo stato dsBrowse.
• Il dataset riceve un evento AfterDelete.
Se si vuole evitare la cancellazione nel gestore di evento BeforeDelete, si può chiamare
la procedura globale Abort:
procedure TForm1.TableBeforeDelete (Dataset: TDataset)
begin
if MessageDlg('Delete This Record?', mtConfirmation, mbYesNoCancel, 0) <> mrYes then
Abort;
end;
Se Delete non va a buon fine, genera un evento OnDeleteError. Se il gestore di evento
OnDeleteError non può risolvere il problema, il dataset rimane nello stato dsEdit. Se
Delete va a buon fine, il dataset ritorno allo stato dsBrowse e il record successivo a
quello cancellato diventa il record corrente.
Se si utilizzano gli aggironamenti in cache, il record cancellato non viene rimosso
dalla tabella di database sottostante finché non si chiama ApplyUpdates.
Se nelle schede è previsto un componente navigator, gli utenti possono cancellare il
record corrente facendo clic sul pulsante Delete del Navigator. Nel codice, è
necessario chiamare esplicitamente Delete per rimuovere il record corrente.
I dataset 24-21
Copyright © 11/29/00, Inprise Corporation. All rights reserved. INPRISE CONFIDENTIAL
November 29, 2000 2:20 pm (J:\source\Devguide\BOOK\Delphonly\1_intro.fm5)
W Il metodo Close non chiama implicitamente Post. Per registrare in modo esplicito
qualsiasi modifica in sospeso, occorre usare l’evento BeforeClose.
Questi metodi accettano come argomento un array di valori, in cui ciascun valore
corrisponde a una colonna nel dataset sottostante. I valori possono essere letterali,
variabili o NULL. Se il numero di valori di un argomento è inferiore al numero di
colonne di un dataset, i valori rimanenti sono considerati NULL.
Per i dataset non indicizzati, AppendRecord aggiunge un record alla fine del dataset,
mentre InsertRecord inserisce un record dopo la posizione corrente del cursore. Per le
tabelle indicizzate, entrambi i metodi inseriscono il record nella tabella alla posizione
corretta, in base all’indice. In entrambi i casi, i metodi spostano il cursore alla
posizione del record.
SetFields assegna i valori specificati nell’array di parametri ai campi del dataset. Per
utilizzare SetFields, un’applicazione deve innanzi tutto chiamare Edit per portare il
dataset in modalità dsEdit. Per applicare le modifiche al record corrente, deve
eseguire un’operazione Post.
Se si usa SetFields per modificare alcuni campi di un record esistente, ma non tutti, è
possibile passare valori NULL per i campi che non devono essere modificati. Se non
vengono forniti abbastanza valori per tutti i campi di un record, SetFields assegna ad
essi valori NULL. I valori NULL sovrascrivono tutti i valori già esistenti in quei
campi.
Ad esempio, si supponga che un database abbia una tabella COUNTRY contenenti le
colonne Name, Capital, Continent, Area e Population. Se un componente TTable
denominato CountryTable fosse collegato alla tabella COUNTRY, la seguente
istruzione inserirebbe un record nella tabella COUNTRY:
CountryTable.InsertRecord(['Japan', 'Tokyo', 'Asia']);
Questa istruzione non specifica valori per Area e Population, pertanto in
corrispondenza di tali campi vengono inseriti valori NULL. La tabella è indicizzata in
base a Name, quindi l’istruzione inserirebbe il record in base alla collazione alfabetica
di ”Japan”.
Per aggiornare il record, un’applicazione potrebbe usare il seguente codice:
with CountryTable do
begin
if Locate('Name', 'Japan', loCaseInsensitive) then;
begin
Edit;
SetFields(nil, nil, nil, 344567, 164700000);
Post;
end;
end;
I dataset 24-23
Copyright © 11/29/00, Inprise Corporation. All rights reserved. INPRISE CONFIDENTIAL
November 29, 2000 2:20 pm (J:\source\Devguide\BOOK\Delphonly\1_intro.fm5)
Questo codice assegna i valori ai campi Area e Population e quindi li registra nel
database. I tre puntatori NULL si comportano come segnaposto per le prime tre
colonne, in modo da preservarne il contenuto attuale.
W OnCalcFields viene chiamato frequentemente, quindi il codice scritto per esso deve
essere breve. Inoltre, se AutoCalcFields è True, OnCalcFields non deve eseguire alcuna
azione che modifica il dataset (o il dataset collegato se fa parte di una relazione
master/detail), perché ciò può dar luogo a ricorsività. Per esempio, se OnCalcFields
esegue un’operazione Post e AutoCalcFields è True, OnCalcFields viene chiamato
nuovamente, dando origine a un’altra operazione Post, e così via.
Quando viene eseguito OnCalcFields, il dataset passa in modalità dsCalcFields. Questo
stato impedisce modifiche o aggiunte ai record di un dataset, ad eccezione dei campi
calcolati che il gestore è previsto possa modificare. Il motivo per prevenire altre
modifiche è dovuto al fatto che OnCalcFields utilizza i valori contenuti in altri campi
per derivare i valori dei campi calcolati. Eventuali modifiche a questi altri campi,
potrebbero invalidare i valori assegnati ai campi calcolati. Dopo il completamento di
OnCalcFields, il dataset torna allo stato dsBrowse.
Tipi di dataset
La sezione “Utilizzo dei discendenti di TDataSet” a pagina 24-2 classifica i
discendenti di TDataSet in base la metodo che essi utilizzano per accedere ai propri
dati. Un altro metodo utile per classificare i discendenti di TDataSet è quello di
considerare il tipo di server dati che essi rappresentano. In base a quest’ottica, ci sono
tre classi di base di dataset:
Tipi di dataset
• Dataset di tipo tabella: I dataset di tipo tabella rappresentano una singola tabella
di un server di database, comprese tutte le sue righe e colonne. I dataset di tipo
tabella includono TTable, TADOTable, TSQLTable e TIBTable.
I dataset di tipo tabella permettono di sfruttare indici definiti sul server. Poiché c’è
una corrispondenza biunivoca tra tabella di database e dataset, è possibile
utilizzare gli indici server definiti per la tabella di database. Gli indici permettono
all’applicazione di ordinare i record nella tabella, di velocizzare ricerche e
consultazioni e possono costituire la base di una relazione master/detail. Inoltre,
alcuni dataset di tipo tabella sfruttano il vantaggio della relazione uno-a-uno
esistente tra il dataset e la tabella di database per permettere di eseguire
operazioni a livello di tabella, come la creazione e la cancellazione di tabelle di
database.
• Dataset di tipo query: I dataset di tipo query rappresentano un singolo comando
SQL o una query. Le query possono rappresentare il set risultato derivante
dall’esecuzione di un comando (di solito un’istruzione SELECT) o possono
eseguire un comando che non restituisce alcun record (ad esempio, un’istruzione
UPDATE). I dataset di tipo query includono TQuery, TADOQuery, TSQLQuery e
TIBQuery.
Per utilizzare un dataset di tipo query, è necessario avere familiarità con SQL e con
l’implementazione SQL del server, compresi eventuali limiti e ampliamenti allo
standard SQL-92. Se non si padronanza di SQL, potrebbe valer la pena acquistare
un manuale tecnico che tratti SQL in dettaglio. Uno dei migliori è Understanding
the New SQL: A Complete Guide, di Jim Melton e Alan R. Simpson, edito da Morgan
Kaufmann.
• Dataset di tipo procedura registrata: I dataset di tipo procedura registrata
rappresentano una procedura registrata sul server di database. I dataset di tipo
procedura registrata includono TStoredProc, TADOStoredProc, TSQLStoredProc e
TIBStoredProc.
Una procedura registrata è un programma indipendente scritto nella linguaggio di
procedure e trigger specifici del sistema di database utilizzato. Di solito gestiscono
operazioni relative al database ripetute di frequente, e risultano particolarmente
utili per operazioni che agiscono su grandi quantità di record o che utilizzano
funzioni di aggregazione o matematiche. Di solito l’utilizzo di procedure
registrate migliora le prestazioni di un’applicazione database:
• Sfruttando l’enorme potenza e velocità di elaborazione tipiche dei server.
• Riducendo il traffico di rete perché tutte le elaborazioni vengono spostate sul
server.
Le procedure registrate possono restituire o meno dei dati. Quelle che
restituiscono dati possono restituirli come un cursor (in modo analogo al risultato
di una query SELECT), come più cursor (restituendo in effetti più dataset) o
restituire dati nei parametri di output. Queste differenze dipendono in parte dal
server: alcuni server non permettono alle procedure registrate di restituire dati o
permettono solo parametri di output. Altri server invece non supportano affatto le
procedure registrate. Per determinare cosa è possibile fare, consultare la
documentazione del server.
I dataset 24-25
Copyright © 11/29/00, Inprise Corporation. All rights reserved. INPRISE CONFIDENTIAL
November 29, 2000 2:20 pm (J:\source\Devguide\BOOK\Delphonly\1_intro.fm5)
I dataset 24-27
Copyright © 11/29/00, Inprise Corporation. All rights reserved. INPRISE CONFIDENTIAL
November 29, 2000 2:20 pm (J:\source\Devguide\BOOK\Delphonly\1_intro.fm5)
N Nel caso di tabelle Paradox, l’indice principale è senza nome e non viene quindi
restituito da GetIndexNames. Con una tabella Paradox, comunque, è sempre possibile
reimpostare l’indice in uso all’indice principale, dopo avere utilizzato un indice
alternativo, impostando la proprietà IndexName a una stringa vuota.
Per ottenere informazioni sui campi dell’indice corrente, utilizzare
• La proprietà IndexFieldCount, per determinare il numero di colonne nell’indice.
• La proprietà IndexFields, per esaminare una lista dei componenti campo per le
colonne che comprendono l’indice.
Il codice seguente mostra come si protrebbero utilizzare IndexFieldCount e IndexFields
per passare in sequenza una lista di nomi di colonna in un’applicazione:
var
I: Integer;
ListOfIndexFields: array[0 to 20} of string;
begin
with CustomersTable do
begin
for I := 0 to IndexFieldCount - 1 do
ListOfIndexFields[I] := IndexFields[I].FieldName;
end;
end;
N IndexFieldCount non è valido per una tabella dBASE aperta in base a un indice di
espressione.
CustomersTable.IndexName := 'CustDescending';
I dataset 24-29
Copyright © 11/29/00, Inprise Corporation. All rights reserved. INPRISE CONFIDENTIAL
November 29, 2000 2:20 pm (J:\source\Devguide\BOOK\Delphonly\1_intro.fm5)
GotoKey e FindKey sono funzioni booleane che, se vanno a buon fine, spostano il
cursore a un record corrispondente e restituiscono True. Se la ricerca è infruttuosa, il
cursore non viene spostato e queste funzioni restituiscono False.
GotoNearest e FindNearest ricollocano sempre il cursore o sulla prima corrispondenza
esatta trovata o, nel caso non venga trovata alcuna corrispondenza, sul primo record
che è maggiore dei criteri di ricerca specificati.
Se esiste un record che contiene ”Sm” come primi due caratteri del valore del primo
campo indicizzato, il cursore viene posizionato su quel record. Altrimenti, la
posizione del cursore non cambia e GotoNearest restituisce False.
Specifica del record corrente dopo una ricerca andata a buon fine
Per impostazione predefinita, una ricerca che va a buon fine posiziona il cursore sul
primo record che corrisponde ai criteri di ricerca. Se si preferisce, è possibile
impostare la proprietà KeyExclusive a True in modo da posizionare il cursore sul
record immediatamente successivo al primo record corrispondente.
Per impostazione predefinita, KeyExclusive èFalse, il che significa che le ricerche che
vanno a buon fine posizionano il cursore sul primo record corrispondente.
I dataset 24-31
Copyright © 11/29/00, Inprise Corporation. All rights reserved. INPRISE CONFIDENTIAL
November 29, 2000 2:20 pm (J:\source\Devguide\BOOK\Delphonly\1_intro.fm5)
Ad esempio, si supponga di aver già eseguita una ricerca nella tabella Employee in
base al campo City dell’indice ”CityIndex”. Si supponga inoltre che ”CityIndex”
includa anche i campi City e Company. Per trovare un record con un determinato
nome di azienda in una determinata città, utilizzare il seguente codice:
Employee.KeyFieldCount := 2;
Employee.EditKey;
Employee['Company'] := Edit2.Text;
Employee.GotoNearest;
I dataset 24-33
Copyright © 11/29/00, Inprise Corporation. All rights reserved. INPRISE CONFIDENTIAL
November 29, 2000 2:20 pm (J:\source\Devguide\BOOK\Delphonly\1_intro.fm5)
Modifica di un intervallo
Due funzioni permettono di modificare le condizioni esistenti dei limiti estremi di un
intervallo: EditRangeStart, per modificare i valori iniziali di un intervallo; ed
EditRangeEnd, per modificare i valori finali dell’intervallo.
Il processo per modificare e applicare un intervallo implica questi passi generali:
1 Porre il dataset nello stato dsSetKey e modificare il valore iniziale dell’indice
dell’intervallo.
2 Modifica del valore finale dell’indice dell’intervallo.
3 Applicare l’intervallo al dataset.
È possibile modificare o il singolo valore iniziale o finale dell’intervallo, oppure si
possono modificare entrambe le condizioni dei limiti estremo. Se si modificano le
condizioni relative ai limiti estremi di un intervallo che è attualmente applicato a un
I dataset 24-35
Copyright © 11/29/00, Inprise Corporation. All rights reserved. INPRISE CONFIDENTIAL
November 29, 2000 2:20 pm (J:\source\Devguide\BOOK\Delphonly\1_intro.fm5)
Applicazione di un intervallo
Quando si specifica un intervallo, le condizioni di limite che vengono definite non
diventano effettive finché non si applica l’intervallo. Affinché un intervallo entri in
vigore, si deve chiamare il metodo ApplyRange. ApplyRange limita immediatamente la
vista e l’accesso da parte di un utente solo ai dati inclusi nel sottoinsieme specificato
del dataset.
Annullamento di un intervallo
Il metodo CancelRange pone fine all’applicazione di un intervallo e ripristina l’accesso
all’intero dataset. Anche se l’annullamento un intervallo ripristina l’accesso a tutti i
record nel dataset, le condizioni di limite di quell’intervallo sono ancora disponibili,
rendendo possibile riapplicare l’intervallo in un momento successivo. I limiti di
intervallo vengono conservati finché non si forniscono nuovi limiti per intervallo o
non si modificano i limiti esistenti. Ad esempio, il seguente codice è valido:
ƒ
MyTable.CancelRange;
ƒ
{later on, use the same range again. No need to call SetRangeStart, etc.}
MyTable.ApplyRange;
ƒ
I dataset 24-37
Copyright © 11/29/00, Inprise Corporation. All rights reserved. INPRISE CONFIDENTIAL
November 29, 2000 2:20 pm (J:\source\Devguide\BOOK\Delphonly\1_intro.fm5)
Le istruzioni successive consentono di creare una semplice scheda in cui l’utente può
esaminare ad uno ad uno i record dei clienti e visualizzare tutti gli ordini relativi al
cliente corrente. La tabella master è la tabella CustomersTable e la tabella dettaglio è
OrdersTable. L’esempio utilizza il componente basto su BDE TTable, ma è possibile
utilizzare gli stessi metodi per collegare qualsiasi dataset di tipo tabella.
1 Collocare in un modulo dati due componenti TTable e due componenti
TDataSource.
2 Impostare le proprietà del primo componente TTable come segue:
• DatabaseName : DBDEMOS
• TableName : CUSTOMER
• Name : CustomersTable
3 Impostare le proprietà del secondo componente TTable come segue:
• DatabaseName : DBDEMOS
• TableName : ORDERS
• Name : OrdersTable
4 Impostare le proprietà del primo componente TDataSource come segue:
• Name : CustSource
• DataSet : CustomersTable
5 Impostare le proprietà del secondo componente TDataSource come segue:
• Name : OrdersSource
• DataSet : OrdersTable
6 Collocare su una scheda due componenti TDBGrid.
7 Scegliere File|Use Unit per specificare che la scheda dovrebbe utilizzare il modulo
dati.
8 Impostare la proprietà DataSource del primo componente griglia a ”CustSource”, e
impostare la proprietà DataSource della seconda griglia a ”OrdersSource”.
9 Impostare la proprietà MasterSource di OrdersTable a ”CustSource”. In questo
modo la tabella CUSTOMER (la tabella principale) e la tabella ORDERS (la tabella
di dettaglio) risultano collegate.
10 Fare doppio clic nell’Object Inspector sulla casella del valore della proprietà
MasterFields in modo da richiamare il Field Link Designer e impostare le seguenti
proprietà:
• Nel campo Available Indexes, scegliere CustNo per collegare le due tabelle in
base al campo CustNo.
• Selezionare CustNo in entrambe le liste dei campi Detail Fields e Master Fields.
• Fare clic sul pulsante Add per aggiungere questa condizione di join. Nella lista
Joined Fields viene visualizzato ”CustNo-> CustNo”.
• Scegliere OK per confermare le selezioni e uscire da Field Link Designer.
11 Impostare le proprietà Active di CustomersTable e OrdersTable a True per
visualizzare i dati nelle griglie sulla scheda.
I dataset 24-39
Copyright © 11/29/00, Inprise Corporation. All rights reserved. INPRISE CONFIDENTIAL
November 29, 2000 2:20 pm (J:\source\Devguide\BOOK\Delphonly\1_intro.fm5)
una tabella SQL su un server remoto e il server limita l’accesso alla tabella alla sola
lettura).
N Questo non è vero per TClientDataSet, che determina se gli utenti possono modificare
i dati provenienti da informazioni che il provider di dataset fornisce mediante
pacchetti dati. Anche per TSQLTable, che è un dataset unidirezionale e perciò sempre
a sola lettura, non è vero.
Quando si apre la tabella, è possibile controllare la proprietà CanModify per accertare
se il database sottostante (o il provider di dataset) permette agli utenti di modificare i
dati nella tabella. Se CanModify è False, l’applicazione non può scrivere nel database.
Se CanModify è True, l’applicazione può scrivere nel database a condizione che la
proprietà ReadOnly della tabella sia False.
ReadOnly determina se un utente può sia visualizzare che modificare i dati. Se
ReadOnly è False (impostazione predefinita), un untente può vedere e modificare i
dati. Per limitare l’utente alla visualizzazione dei dati, impostare ReadOnly a True
prima di aprire la tabella.
Creazione di tabelle
TTable e TIBTable permettono entrambi di creare la tabella di database sottostante
senza utilizzare SQL. Allo stesso modo, TClientDataSet permette di creare un dataset
quando non si sta operando con un provider di dataset. Utilizzando TTable e
TClientDataSet, è possibile creare la tabella in progettazione o in esecuzione. Solo
TIBTable permette di creare tabelle in esecuzione.
Prima di potere creare la tabella, è necessario aver impostato alcune proprietà per
specificare la struttura della tabella che si vuole creare. In particolare, è necessario
specificare:
• Il database che conterrà la nuova tabella. Per TTable, si specifica il database
utilizzando la proprietà DatabaseName. Per TIBTable, è necessario utilizzare un
componente TIBDatabase, assegnato alla proprietà Database. (I dataset client non
utilizzano un database).
• Il tipo del database (solo per TTable). Impostare la proprietà TableType al tipo di
tabella richiesto. Per tabelle Paradox, dBASE o ASCII, impostare rispettivamente
TableType a ttParadox, a ttDBase o ttASCII. Per tutti gli altri tipi di tabella, impostare
TableType a ttDefault.
• Il nome della tabella che si vuole creare. Sia TTable che TIBTable hanno una
proprietà TableName per il nome della nuova tabella. I dataset client non utilizzano
un nome della tabella, ma, prima di salvare la nuova tabella, si dovrebbe
specificare la proprietà FileName. Se si crea una tabella che duplica il nome di una
tabella esistente, la tabella esistente e tutti i suoi dati saranno sovrascritti dalla
tabella appena creata. La vecchia tabella e i suoi dati non potranno essere
recuperati. Per evitare di sovrascrivere una tabella esistente, è possibile controllare
la proprietà Exists in esecuzione. Exists è disponibile solo per TTable e TIBTable.
• I campi della nuova tabella. È possibile farlo in due modi:
• È possibile aggiungere definizioni di campo alla proprietà FieldDefs. In
progettazione, fare doppio clic nell’Object Inspector sulla proprietà FieldDefs
per richiamare il Collection editor. Utilizzare il Collection editor per
aggiungere, cancellare o modificare le proprietà delle definizioni dei campi. In
esecuzione, cancellare qualsiasi definizione di campo esistente e quindi
utilizzare il metodo AddFieldDef per aggiungere ogni nuova definizione di
campo. Per ogni nuova definizione di campo, impostare le proprietà
dell’oggetto TFieldDef per specificare gli attributi desiderati per il campo.
• In alternativa, è possibile utilizzare anche componenti campo persistenti. In
progettazione, fare doppio clic sul datset per richiamare il Fields editor. Nel
Fields editor, fare clic destro e scegliere il comando New Field. Descrivere le
proprietà di base del campo. Una volta creato il campo, è possibile modificarne
le proprietà nell’Object Inspector selezionando il campo Fields Editor.
• Gli indici per la nuova tabella (facoltativo). In progettazione, fare doppio clic
nell’Object Inspector sulla proprietà IndexDefs per richiamare il Collection editor.
Utilizzare il Collection editor per aggiungere, cancellare o modificare le proprietà
delle definizioni degli indici. In esecuzione, cancellare qualsiasi definizione di
indice esistente e quindi utilizzare il metodo AddIndexDef per aggiungere ogni
nuova definizione di indice. Per ogni nuova definizione di indice, impostare le
proprietà dell’oggetto TIndexDef per specificare gli attributi desiderati per l’indice.
I dataset 24-41
Copyright © 11/29/00, Inprise Corporation. All rights reserved. INPRISE CONFIDENTIAL
November 29, 2000 2:20 pm (J:\source\Devguide\BOOK\Delphonly\1_intro.fm5)
N Quando si creano tabelle Oracle8, è impossibile creare campi oggetto (campi ADT,
campi array e campi dataset).
Il seguente codice crea una nuova tabella in esecuzione e la associa all’alias
DBDEMOS. Prima di creare la nuova tabella, verifica che il nome di tabella fornito
non corrisponda al nome di una tabella esistente:
var
TableFound: Boolean;
begin
with TTable.Create(nil) do // create a temporary TTable component
begin
try
{ set properties of the temporary TTable component }
Active := False;
DatabaseName := 'DBDEMOS';
TableName := Edit1.Text;
TableType := ttDefault;
{ define fields for the new table }
FieldDefs.Clear;
with FieldDefs.AddFieldDef do begin
Name := 'First';
DataType := ftString;
Size := 20;
Required := False;
end;
with FieldDefs.AddFieldDef do begin
Name := 'Second';
DataType := ftString;
Size := 30;
Required := False;
end;
{ define indexes for the new table }
IndexDefs.Clear;
with IndexDefs.AddIndexDef do begin
Name := '';
Fields := 'First';
Options := [ixPrimary];
end;
TableFound := Exists; // check whether the table already exists
if TableFound then
if MessageDlg('Overwrite existing table ' + Edit1.Text + '?',
mtConfirmation, mbYesNoCancel, 0) = mrYes then
TableFound := False;
if not TableFound then
CreateTable; // create the table
finally
Free; // destroy the temporary TTable when done
end;
end;
end;
Cancellazione di tabelle
TTable e TIBTable permettono di cancellare tabelle dalla tabella di database
sottostante senza utilizzare SQL. Per cancellare una tabella in esecuzione, chiamare il
metodo DeleteTable del dataset. Ad esempio, la seguente istruzione elimina la tabella
sottostante un dataset:
CustomersTable.DeleteTable;
W Quando si cancella una tabella con DeleteTable, la tabella e tutti i suoi dati vanno
definitivamente perduti.
Se si utilizza TTable, è possibile anche cancellare le tabelle in progettazione: fare clic
destro sul componente tabella e selezionare Delete Table dal menu di scelta rapida.
La scelta di menu Delete Table è disponibile solo se il componente tabella
rappresenta una tabella di database esistente (le proprietà DatabaseName e TableName
specificano una tabella esistente).
Svuotamento di tabelle
Molti dataset di tipo tabella forniscono un singolo metodo che permette di cancellare
tutte le righe di dati nella tabella.
• Per TTable e per TIBTable, è possibile cancellare tutti i record chiamando in
esecuzione il metodo EmptyTable:
PhoneTable.EmptyTable;
• Per TADOTable, è possibile utilizzare il metodo DeleteRecords.
PhoneTable.DeleteRecords;
• Anche per TSQLTable è possibile utilizzare il metodo DeleteRecords. Si noti,
tuttavia, che la versione TSQLTable di DeleteRecords non richiede mai alcun
parametro.
PhoneTable.DeleteRecords;
• Per i dataset client, è possibile utilizzare il metodo EmptyDataSet.
PhoneTable.EmptyDataSet;
N Per tabelle su server SQL, questi metodi vanno a buon fine solo se si ha il privilegio
DELETE per la tabella.
I dataset 24-43
Copyright © 11/29/00, Inprise Corporation. All rights reserved. INPRISE CONFIDENTIAL
November 29, 2000 2:20 pm (J:\source\Devguide\BOOK\Delphonly\1_intro.fm5)
Sincronizzazione di tabelle
Se si hanno due o più dataset che rappresentano la stessa tabella di database ma non
condividono un componente datasource, ogni dataset ha la propria vista sui dati e il
proprio record corrente. Se si accede ai record utilizzando ognuno dei due dataset, i
record correnti dei componenti saranno diversi.
Se tutti i dataset sono istanze di TTable o di TIBTable o sono tutti dataset client,
chiamando il metodo GotoCurrent è possibile forzare il record corrente di ognuno di
questi dataset a eguagliare quello degli altri. GotoCurrent imposta il record corrente
del proprio dataset al record corrente di un dataset corrispondente. Ad esempio, il
seguente codice imposta il record corrente di CustomerTableOne in modo che sia lo
stesso del record corrente di CustomerTableTwo:
CustomerTableOne.GotoCurrent(CustomerTableTwo);
I dataset 24-45
Copyright © 11/29/00, Inprise Corporation. All rights reserved. INPRISE CONFIDENTIAL
November 29, 2000 2:20 pm (J:\source\Devguide\BOOK\Delphonly\1_intro.fm5)
N Con alcune versioni di Delphi, se si utilizza TQuery, è possibile anche utilizzare SQL
Builder per costruire una query in base a una rappresentazione visibile delle tabelle e
dei campi in un database. Per utilizzare SQL Builder, selezionare il componente
query, fare clic destro su esso per richiamare il menu di scelta rapida e scegliere
Graphical Query Editor. Per apprendere l’utilizzo di SQL Builder, aprirlo e
utilizzarne la Guida in linea.
Poiché la proprietà SQL è un oggetto TStrings, è possibile caricare il testo della query
da un file chiamando il metodo LoadFromFile di TStrings.
MyQuery.SQL.LoadFromFile('custquery.sql');
Per copiare il contenuto di un oggetto string list nella proprietà SQL è possibile
utilizzare anche il metodo Assign della proprietà SQL. Prima di copiare la nuova
istruzione, il metodo Assign cancella automaticamente il contenuto corrente della
proprietà SQL:
MyQuery.SQL.Assign(Memo1.Lines);
I dataset 24-47
Copyright © 11/29/00, Inprise Corporation. All rights reserved. INPRISE CONFIDENTIAL
November 29, 2000 2:20 pm (J:\source\Devguide\BOOK\Delphonly\1_intro.fm5)
N L’editor Parameter collection è lo stesso editor di collection che viene visualizzato per
altre proprietà di tipo collection. Dal momento che l’editor è condiviso con altre
proprietà, il relativo menu contestuale contiene i comandi Add e Delete. Tuttavia, tali
comandi non sono mai abilitati per i parametri delle query. L’unico modo per
aggiungere o cancellare parametri è utilizzare l’istruzione SQL.
Per ciascun parametro, selezionarlo nell’editor Parameter collection. Quindi
utilizzare l’Object Inspector per modificarne le proprietà.
Quando si utilizzerà la proprietà Params (oggetti TParam), si vorrà esaminare o
modificare quanto segue:
• La proprietà DataType elenca il tipo di dati per il valore del parametro. Per alcuni
dataset, questo valore potrebbe già essere inizializzato correttamente. Se il dataset
non è stato in grado di dedurre il tipo, DataType è ftUnknown ed è necessario
modificarlo per indicare il tipo del valore del parametro.
La proprietà DataType elenca il tipo di dati logico per il parametro. Di solito, questi
tipi di dati si conformano ai tipi di dati del server. Per mappature specifiche dei
tipi di dati con i tipi di dati gestiti dal server, vedere la documentazione del
meccanismo di accesso ai dati (BDE, dbExpress, InterBase).
• La proprietà ParamType elenca il tipo del parametro selezionato. Nel caso delle
query, la proprietà è sempre ptInput, perché le query possono contenere solo
parametri di input. Se il valore di ParamType è ptUnknown, modificarlo in ptInput.
• La proprietà Value specifica un valore per il parametro selezionato. Se
l’applicazione fornisce il valore del parametro in esecuzione, è possibile non
compilare Value.
Quando si utilizzerà la proprietà Parameters (oggetti TParameter), si vorrà esaminare o
modificare quanto segue:
• La proprietà DataType elenca il tipo di dati per il valore del parametro. Per alcuni
tipi di dati, è necessario fornire ulteriori informazioni:
• La proprietà NumericScale indica il numero di cifre decimali per parametri
numerici.
I dataset 24-49
Copyright © 11/29/00, Inprise Corporation. All rights reserved. INPRISE CONFIDENTIAL
November 29, 2000 2:20 pm (J:\source\Devguide\BOOK\Delphonly\1_intro.fm5)
record principale. Benché sia possibile scrivere del codice per compiere l’operazione
utilizzando un gestore di evento, tutti i dataset di tipo query tranne TIBQuery
forniscono un meccanismo più semplice grazie all’utilizzo della proprietà DataSource.
Se i valori dei parametri di una query parametrizzata non vengono collegati in fase di
progettazione o specificati in esecuzione, i dataset di tipo query tentano di fornire un
valore ai parametri in base alla proprietà DataSource. DataSource identifica un dataset
differente che viene esaminato alla ricerca di nomi di campo che corrispondano ai
nomi dei parametri non collegati. Questo dataset di ricerca può essere un qualsiasi
tipo di dataset. Prima di creare il dataset di dettaglio che lo utilizza, è necessario
creare e riempire il dataset di ricerca. Se nel dataset di ricerca vengono trovate le
corrispondenze, il dataset di dettaglio collega i valori dei parametri ai valori dei
campi nel record corrente a cui punta la sorgente dati.
Per illustrare il funzionamento, si prendano in esame due tabelle: una tabella di
clienti e una tabella di ordini. Per ogni cliente, la tabella degli ordini contiene una
serie di ordini fatti dal cliente. La tabella Customer include un campo ID che specifica
un codice cliente univoco. La tabella degli ordini include un campo CustID che
specifica l’ID del cliente che ha fatto un ordine.
Il primo passo consiste nel configurare il dataset Customer:
1 Aggiungere all’applicazione un dataset di tipo tabella e collegarlo alla tabella
Customer.
2 Aggiungere un componente TDataSource di nome CustomerSource. Impostarne la
proprietà DataSet al dataset aggiunto al punto 1. Questo datasorce ora rappresenta
il dataset Customer.
3 Aggiungere un dataset di tipo query e impostarne la proprietà SQL a
SELECT CustID, OrderNo, SaleDate
FROM Orders
WHERE CustID = :ID
Si noti che il nome del parametro è identico al nome del campo nella tabella master
(Customer).
4 Impostare la proprietà DataSource del dataset di dettaglio a CustomerSource.
L’impostazione di questa proprietà rende il dataset di dettaglio una query
collegata.
In esecuzione, al parametro :ID dell’istruzione SQL per il dataset di dettaglio non
viene assegnato un valore, e pertanto il dataset cerca fra le colonne del dataset
identificato da CustomersSource una corrispondenza del parametro in base al nome.
CustomersSource ricava i propri dati dal dataset master, il quale, a sua volta, ricava i
propri dati dalla tabella Customer. Poiché la tabella Customer contiene una colonna
di nome ”ID”, il valore del campo ID nel record corrente del dataset master viene
assegnato al parametro :ID dell’istruzione SQL del dataset di dettaglio. I dataset sono
collegati tramite una relazione master-detail. Ogni volta che nel dataset Customers il
record corrente cambia, viene eseguita l’istruzione SELECT del dataset di dettaglio
per ricercare tutti gli ordini in base all’identificativo del cliente corrente.
Preparazione di query
La preparazione di una query è un passo facoltativo che precede l’esecuzione della
query. La preparazione di una query sottomette l’istruzione SQL e gli eventuali
parametri allo strato di accesso ai dati e al server di database per l’analisi sintattica e
per l’allocazione e l’ottimizzazione delle risorse. Con alcuni dataset, in fase di
preparazione della query, il dataset può eseguire delle ulterori operazioni di
configurazione. Queste operazioni migliorano le prestazioni della query, rendendo
più rapida l’applicazione, specialmente quando funzionano con query aggiornabili.
Un’applicazione può preparare una query impostando la proprietà Prepared a True.
Se non si prepara una query prima di eseguirla, il dataset la prepara
automaticamente ogni volta che si chiamano i metodi Open o ExecSQL. Sebbene il
dataset prepari le query automaticamente, è possibile migliorare le prestazioni
preparando esplicitamente il dataset prima di aprirlo per la prima volta.
CustQuery.Prepared := True;
Quando si prepara esplicitamente il dataset, le risorse allocate per l’esecuzione
dell’istruzione non vengono liberate finché non si imposta Prepared a False.
Impostare la proprietà Prepared a False se si desidera essere certi che il dataset vengo
preparato di nuovo prima dell’esecuzione (ad esempio, se si aggiunge un parametro.
N Quando si modifica il testo della proprietà SQL di una query, il dataset si chiude
automaticamente e annulla la preparazione della query.
I dataset 24-51
Copyright © 11/29/00, Inprise Corporation. All rights reserved. INPRISE CONFIDENTIAL
November 29, 2000 2:20 pm (J:\source\Devguide\BOOK\Delphonly\1_intro.fm5)
I dataset 24-53
Copyright © 11/29/00, Inprise Corporation. All rights reserved. INPRISE CONFIDENTIAL
November 29, 2000 2:20 pm (J:\source\Devguide\BOOK\Delphonly\1_intro.fm5)
I dataset 24-55
Copyright © 11/29/00, Inprise Corporation. All rights reserved. INPRISE CONFIDENTIAL
November 29, 2000 2:20 pm (J:\source\Devguide\BOOK\Delphonly\1_intro.fm5)
I dataset 24-57
Copyright © 11/29/00, Inprise Corporation. All rights reserved. INPRISE CONFIDENTIAL
November 29, 2000 2:20 pm (J:\source\Devguide\BOOK\Delphonly\1_intro.fm5)
var
DataSet2: TCustomSQLDataSet;
begin
DataSet2 := SQLStoredProc1.NextRecordSet;
...
Con TSQLStoredProc, il metodo NextRecordSet restituisce un nuovo componente
TCustomSQLDataSet che fornisce l’accesso al successivo set di record. In
TADOStoredProc, NextRecordset restituisce un’interfaccia che può essere assegnata
alla proprietà RecordSet di un dataset ADO esistente. Per entrambe le classi, il metodo
restituisce il numero di record nel dataset restituito come parametro di output.
La prima volta che si chiama NextRecordSet, il metodo restituisce il secondo set di
record. La successiva chiamata a NextRecordSet restituisce nuovamente un terzo
dataset e così via, finché non vi sono più altri set di record. Quando non vi sono più
altri dataset, NextRecordSet restituisce nil.
Capitolo
Man mano che si passa da un record a un altro all’interno del dataset, un componente
campo permette di visualizzare e modificare il valore di quel campo nel record
corrente.
I vari componenti campo hanno sia molte proprietà in comune (ad esempio
DisplayWidth e Alignment), sia proprietà specifiche in base al relativo tipo di dati (ad
esempio Precision per TFloatField). Ciascuna di queste proprietà influenza il modo in
cui appaiono i dati in una scheda agli utenti di un’applicazione. Alcune proprietà,
come Precision, possono anche influire sul valore che l’utente può immettere in un
controllo durante la modifica o l’inserimento dei dati.
Tutti i componenti campo di un dataset sono dinamici (generati automaticamente in
base alla struttura associata delle tabelle del database), o persistenti (generati in base
ai nomi di campo e proprietà specifici impostati nel Fields editor). I campi dinamici e
persistenti hanno potenza differente e sono adatti a tipi differenti di applicazioni. Le
sezioni seguenti descrivono in maggior dettaglio i campi dinamici e persistenti e
suggeriscono come scegliere fra l’uno e l’altro tipo.
N Una delle ragioni principali per usare i campi persistenti consiste nel fatto che essi
consentono di controllare completamente l’aspetto e la visualizzazione dei dati. È
anche possibile controllare l’aspetto delle colonne nelle griglie associate ai dati. Per
informazioni su come controllare l’aspetto delle colonne nelle griglie, consultare
“Creazione di una griglia personalizzata” a pagina 20-18.
Nuovi campi persistenti servono solo ai fini della visualizzazione. I dati contenuti in
esecuzione non vengono conservati, o perché esistono già altrove nel database o
perché sono provvisori. La struttura fisica dei dati associati al dataset non viene
modificata in alcun modo.
Per creare un nuovo componente campo persistente, occorre chiamare il menu
contestuale di Fields editor e scegliere New Field. Appare così la finestra di dialogo
New Field.
La finestra di dialogo New Fields contiene tre caselle di gruppo: Field properties,
Field type e Lookup definition.
• La casella di gruppo Field properties permette di immettere informazioni generali
sui componenti campo. Immettere il nome del campo nella casella di testo Name.
Il nome immesso corrisponde alla proprietà FieldName del componente campo. La
finestra di dialogo New Field utilizza questo nome per costruire un nome di
componente nella casella di testo Component. Il nome visualizzato nella casella di
testo Component corrisponde alla proprietà Name del componente campo ed è
fornito solo a fini informativi (Name è l’identificativo utilizzato nel codice sorgente
per fare riferimento al componente campo). La finestra di dialogo elimina
qualsiasi cosa immessa direttamente nella casella di testo Component.
• La casella combinata Type del gruppo Field properties permette di specificare il
tipo di dati del componente campo. È necessario indicare un tipo di dati per
qualsiasi nuovo componente campo creato. Per esempio, per visualizzare valori di
valuta in virgola mobile in un campo, selezionare Currency nell’elenco a discesa.
Utilizzare la casella di testo Size per specificare il numero massimo di caratteri che
possono essere visualizzati o immessi in un campo basato su stringhe, oppure la
dimensione dei campi Bytes e VarBytes. Per tutti gli altri tipi di dati, Size è privo di
significato.
• Il gruppo di pulsanti di opzione Field consente di specificare il tipo del nuovo
componente campo da creare. Il tipo predefinito è Data. Se si sceglie Lookup,
vengono attivate le caselle di testo Dataset e Source Fields nella casella del gruppo
della definizione Lookup. È anche possibile creare campi di tipo Calculated e, se si
sta lavorando con un dataset client, si possono creare campi di tipo InternalCalc o
Aggregate. La tabella seguente descrive i tipi di campi che si possono creare:
La casella di gruppo Lookup viene utilizzata solo per creare campi di ricerca. Per
maggiori informazioni, consultare “Definizione di un campo di consultazione” a
pagina 25-9.
N Anche se è un nuovo campo, il campo definito per sostituire un campo esistente deve
derivare i valori dei propri dati da una colonna esistente in una tabella associata a un
dataset.
Per creare un campo dati di sostituzione per un campo di una tabella sottostante un
dataset:
1 Rimuovere il campo dall’elenco dei campi persistenti assegnati per il dataset,
quindi scegliere New Field dal menu contestuale.
2 Nella finestra di dialogo New Field immettere nella casella di testo Name il nome
di un campo esistente nella tabella del database. Non immettere un nuovo nome
di campo. In questo modo, si specifica il nome del campo dal quale il nuovo
campo deriverà i dati.
3 Scegliere un nuovo tipo di dati per il campo dalla casella combinata Type. Il tipo di
dati scelto deve essere diverso da quello del campo che si sta sostituendo. Non è
possibile sostituire un campo stringa di una determinata dimensione con un
campo stringa di dimensione diversa. Si deve tenere presente che, anche se il tipo
di dati sarà diverso, deve pur sempre essere compatibile con il tipo di dati del
campo nella tabella sottostante.
4 All’occorrenza, immettere le dimensioni del campo nella casella di modifica Size.
Size vale solo per i campi di tipo TStringField, TBytesField e TVarBytesField.
5 Selezionare Data nel gruppo Field type, se già non è selezionato.
6 Scegliere OK. La finestra di dialogo New Field verrà chiusa, il campo dati appena
definito sostituirà il campo esistente specificato al punto 1 e i componenti nella
dichiarazione type del modulo di dati o della scheda saranno aggiornati.
Per modificare le proprietà o gli eventi associati a un componente campo, selezionare
il nome del componente nella casella di riepilogo di Fields Editor, quindi modificare
le relative proprietà o i relativi eventi con l’Object Inspector. Per ulteriori
informazioni sulla modifica delle proprietà e degli eventi dei componenti campo,
vedere “Impostazione di proprietà ed eventi dei campi persistenti” a pagina 25-11.
1 Nella casella di modifica Name, immettere un nome per il campo calcolato. Non si
può utilizzare il nome di un campo esistente.
2 Nella casella combinata Type, scegliere un tipo di dati per il campo.
3 All’occorrenza, immettere le dimensioni del campo nella casella di modifica Size.
Size vale solo per i campi di tipo TStringField, TBytesField e TVarBytesField.
4 Selezionare l’opzione Calculated o InternalCalc nel gruppo Field type.
InternalCalc è disponibile solo se si opera con un dataset client. La differenza
significativa fra questi tipi di campi calcolati è che i valori calcolati per un campo
InternalCalc sono memorizzati e recuperati come parte dei dati del dataset client.
5 Scegliere OK. Il campo calcolato appena definito verrà automaticamente aggiunto
alla fine dell’elenco dei campi persistenti nella casella di riepilogo di Fields Editor
e il componente verrà automaticamente aggiunto al codice sorgente nella
dichiarazione type della scheda.
6 Inserire il codice che calcola i valori per il campo nel gestore di evento OnCalcFields
del dataset. Per ulteriori informazioni sulla scrittura del codice per calcolare i
valori dei campi, vedere “Programmazione di un campo calcolato” a pagina 25-8.
T È possibile usare una cache di ricerca per fornire i valori tramite programma anziché
tramite un dataset secondario. Assicurarsi che la proprietà LookupDataSet sia nil.
Quindi, utilizzare il metodo Add della proprietà LookupList per riempirlo con i valori
di consultazione. Impostare la proprietà LookupCache a True. Il campo userà l’elenco
di ricerca fornito senza sovrascriverlo con i valori di un dataset di ricerca.
Se i KeyFields di ogni record di DataSet hanno valori diversi, il carico di lavoro
derivante dal cercare i valori nella cache può essere maggiore di qualsiasi beneficio in
prestazioni fornito dalla cache. Il carico di lavoro derivante dal cercare i valori nella
cache aumenta col numero di valori distinti che possono essere richiesti da KeyFields.
Se LookupDataSet è volatile, mettere in cache valori di consultazione può condurre a
risultati imprecisi. Per aggiornare i valori nella cache di consultazione occorre
chiamare RefreshLookupList. Se LookupDataSet è volatile, mettere in cache valori di
consultazione può condurre a risultati imprecisi. Per aggiornare i valori nella cache
di consultazione occorre chiamare.
Quando in l’esecuzione si imposta LookupCache, per inizializzare la cache occorre
chiamare RefreshLookupList.
1 Immettere un nome per il campo nella casella di modifica Name. Non si può
utilizzare il nome di un campo esistente.
2 Scegliere il tipo di dati di aggregazione per il campo dalla casella combinata Type.
3 Selezionare Aggregate nel gruppo di pulsanti di opzioni per Field type.
4 Scegliere OK. Il campo di aggregazione appena definito viene aggiunto
automaticamente al dataset client, e la sua proprietà Aggregates viene poi
aggiornata per includere la specifica di aggregazione appropriata.
5 Inserire l’operazione di calcolo prevista per l’aggregazione nella proprietà
ExprText del campo di aggregazione appena creato. Per ulteriori informazioni
sulla definizione di un campo di aggregazione, consultare “Specifica delle
aggregazioni” a pagina 29-12.
Una volta creato un TAggregateField persistente, è possibile collegare un controllo
TDBText al campo di aggregazione. Il controllo TDBText visualizzerà poi il valore del
campo di aggregazione che è pertinente al record attivo del dataset client sottostante.
Non tutte le proprietà sono disponibili per tutti i componenti campo. Per esempio, un
componente campo di tipo TStringField non possiede proprietà Currency, MaxValue o
DisplayFormat, mentre un componente di tipo TFloatField non possiede la proprietà
Size.
Anche se lo scopo della maggior parte delle proprietà è semplice, alcune proprietà,
quali Calculated, richiedono ulteriori operazioni di programmazione perché siano
veramente utili. Altre, quali DisplayFormat, EditFormat e EditMask, sono correlate; le
loro impostazioni devono essere coordinate. Per ulteriori informazioni sull’uso di
DisplayFormat, EditFormat e EditMask, vedere “Controllo e mascheratura dell’input” a
pagina 25-15.
E questa istruzione modifica l’ordine dei campi impostando a 3 la proprietà Index del
campo CityStateZip nella tabella Customer
CustomersCityStateZip.Index := 3;
N Set di attributi e Data Dictionary sono solo disponibili per i dataset BDE.
Per creare un set di attributi basato su un componente campo in un dataset:
1 Fare doppio clic sul dataset per richiamare il Fields editor.
2 Selezionare il campo per cui impostare le proprietà.
3 Impostare le proprietà desiderate per il campo nell’Object Inspector.
4 Fare clic con il pulsante destro del mouse sulla casella di riepilogo di Fields Editor
per aprire il menu contestuale.
5 Scegliere Save Attributes per salvare le impostazioni delle proprietà del campo
attivo come set di attributi nel Data Dictionary.
Il nome predefinito del set di attributi è quello del campo attivo. Se dal menu
contestuale si sceglie Save Attributes As, invece di Save Attributes, è possibile
specificare per il set di attributi un nome diverso.
Una volta che si è creato un nuovo set di attributi e lo si è aggiunto al Data
Dictionary, è possibile poi associarlo ad altri componenti campo persistenti. Anche se
in seguito si rimuoverà l'associazione, il set di attributi resta definito nel Data
Dictionary.
3 Fare doppio clic sulla colonna dei valori del campo EditMask nell’Object
Inspector, oppure fare clic sul pulsante con i puntini di sospensione. Verrà
richiamato Input Mask editor.
La casella di testo Input Mask consente di creare e modificare un formato di
maschera. La griglia Sample Masks consente di selezionare una maschera
predefinita. Se si seleziona una maschera di esempio, il relativo formato appare nella
casella di testo Input Mask, in cui è possibile modificarlo o utilizzarlo senza
variazioni. Nella casella di testo Test Input è possibile collaudare le immissioni
consentite all’utente per le maschere.
Il pulsante Masks consente di caricare nella griglia Sample Masks un set di maschere
personalizzate—se ne sono state create—in modo da semplificare la selezione.
Gli eventi OnGetText e OnSetText sono utili principalmente per i programmatori che
desiderano eseguire formattazioni personalizzate che esulano dalle funzioni di
formattazione incorporate. OnChange è utile per eseguire operazioni specifiche
dell’applicazione associate alla modifica dei dati, quali l’abilitazione o la
disabilitazione di menu o di controlli visuali. OnValidate è utile per controllare
nell’applicazione la convalida dei dati immessi prima di restituire i valori a un server
di database.
Per scrivere un gestore di evento per un componente campo:
1 Selezionare il componente.
2 Selezionare nell’Object Inspector la pagina Events.
3 Fare doppio clic sul campo Value relativo al gestore di evento, per visualizzarne la
finestra del codice sorgente.
4 Creare o modificare il codice del gestore.
evento dovrebbe chiamare il metodo FocusControl del campo. Il codice che segue
illustra come chiamare il metodo FocusControl per il campo Company nella tabella
Customer:
CustomersCompany.FocusControl;
La tabella che segue elenca gli altri metodi del componente campo e il loro uso. Per
un elenco completo e per informazioni particolareggiate sull’uso di ciascun metodo,
consultare le voci relative a TField e ai suoi discendenti nella guida in linea VCL
Reference.
N Per accedere ai valori dei campi e modificarli, è possibile anche ricorrere ai Variant.
Per ulteriori informazioni sull’uso dei variant per accedere ai valori dei campi e
impostarli, vedere “Accesso ai valori dei campi con la proprietà predefinita del
dataset” a pagina 25-21.
AsFloat
AsCurrency AsDateTime
AsVariant AsString AsInteger AsBCD AsSQLTimeStamp AsBoolean
TStringField si ND si si si si
TWideStringField si si si si si si
TIntegerField si si ND si
TSmallIntField si si si si
TWordField si si si si
TLargeintField si si si si
TFloatField si si si si
TCurrencyField si si si si
TBCDField si si si si
TFMTBCDField si si si si
TDateTimeField si si si si
TDateField si si si si
TTimeField si si si si
TSQLTimeStampField si si si si
TBooleanField si si
TBytesField si si
TVarBytesField si si
TBlobField si si
TMemoField si si
TGraphicField si si
TVariantField ND si si si si si
TAggregateField si si
Si noti che alcune colonne nella tabella fanno riferimento a più proprietà di
conversione (come AsFloat, AsCurrency e AsBCD). Questo è il motivo per cui tutti i
tipi di dati di campo che supportano una di quelle proprietà supportano sempre
anche le altre.
Si noti che la proprietà AsVariant può anche tradurre di tutti i tipi di dati. Per tutti gli
altri tipi di dati non elencati in precedenza, è disponibile anche AsVariant (ed è,
infatti, l’unica opzione). In caso di dubbio, utilizzare AsVariant.
In alcuni casi, le conversioni non sono possibili. Per esempio, AsDateTime può essere
utilizzato per convertire una stringa in un formato date, time o datetime solo se il
valore della stringa è in un formato datetime riconoscibile. Un tentativo di
conversione non riuscito genera un’eccezione.
In alcuni altri casi, la conversione è possibile, ma i risultati non sono sempre intuitivi.
Per esempio, che cosa significa convertire un valore TDateTimeField nel formato in
virgola mobile? AsFloat converte la data riportata nel campo nel numero di giorni
trascorsi dal 31/12/1899 e converte l’ora riportata nel campo in una frazione di 24
ore. La Tabella 25.7 elenca le conversioni consentite che producono risultati speciali:
Negli altri casi le conversioni non sono affatto possibili. In questi casi un eventuale
tentativo di conversione solleva un’eccezione.
La conversione si verifica sempre prima che l’assegnazione venga eseguita. Per
esempio, la seguente istruzione converte il valore di CustomersCustNo in una stringa e
assegna quest’ultima al testo di un controllo di testo:
Edit1.Text := CustomersCustNo.AsString;
Per utilizzare FieldByName, è necessario conoscere il dataset e il nome del campo a cui
accedere. Il nome del campo viene passato come argomento del metodo. Per accedere
al valore del campo o modificarlo, il risultato deve essere convertito con la proprietà
appropriata per il componente campo, quale AsString o AsInteger. Per esempio, la
seguente istruzione assegna il valore del campo CustNo del dataset Customers a un
controllo di testo:
Edit2.Text := Customers.FieldByName('CustNo').AsString;
Viceversa, la seguente istruzione assegna un valore a un campo:
begin
Customers.Edit;
Customers.FieldByName('CustNo').AsString := Edit2.Text;
Customers.Post;
end;
N I vincoli custom sono solo disponibili solo nei dataset BDE e nei dataset client.
I vincoli custom vengono imposti, in aggiunta a tutti gli altri vincoli, al valore del
campo proveniente dal server. Per vedere i vincoli imposti dal server, consultare la
proprietà ImportedConstraint.
struttura del dataset. Quando si accede ai campi figli di ADT senza utilizzare campi
persistenti, è necessario impostare a True la proprietà ObjectView del dataset.
N A differenza di altri metodi di esecuzione per accedere ai valori dei campo figlio di
ADT, la proprietà FieldValues funziona anche se la proprietà ObjectView del dataset è
impostata a False.
begin
AddressQuery.SQL.Text := ‘SELECT REF(A) FROM AddressTable A WHERE A.City = ‘’San
Francisco’’’;
AddressQuery.Open;
CustomerAddressRef.Assign(AddressQuery.Fields[0]);
end;
Capitolo
L’architettura BDE
Le applicazioni che utilizzano BDE sfruttano una variante dell’architettura generale
di database descritta in “Architettura di un database” a pagina 19-6. Oltre agli
elementi dell’interfaccia utente, al datasource e ai dataset comuni a tutte le
applicazioni database Delphi, le applicazioni BDE possono comprendere
• Uno o più componenti database per il controllo delle transazioni e la gestione delle
connessioni con il database.
• Uno o più componenti session per isolare le operazioni di accesso ai dati come le
connessioni con il database e la gestione di gruppi di database.
Le relazioni tra i componenti di un’applicazione BDE sono illustrate in Figura 26.1:
LÊarchitettura BDE
database
Session
N Oltre ai tre tipi di dataset per BDE, esiste un dataset client basato su BDE
(TBDEClientDataSet) utilizzabile per la gestione degli aggiornamenti in cache. Per le
informazioni relative, consultare “Utilizzo di un dataset client per registrare in cache
gli aggiornamenti” a pagina 29-16.
LÊarchitettura BDE
LÊarchitettura BDE
LÊarchitettura BDE
Utilizzo di TTable
TTable incapsula la struttura completa e i dati in una tabella di database e
implementa tutte le funzionalità di base introdotte da TDataSet, come pure tutte le
funzioni speciali tipiche dei dataset di tipo tabella. Prima di analizzare le funzionalità
esclusive di TTable, conviene familiarizzare con le funzionalità comuni dei database
descritte in “I dataset”, compresa la sezione sui dataset tabellari che inizia a
pagina 24-26.
TTable è un dataset per BDE, e quindi deve essere associato a un database e a una
sessione. Il paragrafo “Associazione di un dataset a connessioni di database e di
sessione” a pagina 26-3 spiega come si formano queste associazioni. Una volta che il
dataset è associato a un database e a una sessione, è possibile legarlo a una
particolare tabella di database impostando la proprietà TableName e, se si utilizza una
tabella di testo ASCII Paradox, dBASE, FoxPro o comma-delimited, alla proprietà
TableType.
Tabella 26.1 Tipi di tabella riconosciuti da BDE in base allÊestensione del file
Estensione Tipo di tabella
No file extension Paradox
.DB Paradox
LÊarchitettura BDE
Tabella 26.1 Tipi di tabella riconosciuti da BDE in base allÊestensione del file (continua)
Estensione Tipo di tabella
.DBF dBASE
.TXT ASCII text
Se le tabelle di testo Paradox, dBASE e ASCII locali utilizzano le estensioni file come
descritto in Tabella 26.1, è possibile lasciare TableType impostato su ttDefault.
Altrimenti, l’applicazione deve impostare TableType in modo da indicare il tipo di
tabella corretto. In Tabella 26.2 sono indicati i valori che è possibile assegnare a
TableType:
LÊarchitettura BDE
Tuttavia, per le tabelle dBASE che utilizzano file indice aggiunti, oppure indici tipo
dBASE III PLUS (*.NDX), è necessario invece utilizzare le proprietà IndexFiles e
IndexName. Alla proprietà IndexFiles si assegna il nome del file indice aggiunto, o si
elencano i file.NDX. Poi si specifica un indice nella proprietà IndexName per fare in
modo che ordini attivamente il dataset.
In fase di progetto, si fa clic sul pulsante ellissi (...)nel valore della proprietà IndexFiles
di Object Inspector per richiamare l’editor Index Files. Per aggiungere un file indice
aggiunto o un file .NDX si fa clic sul pulsante Add nella finestra di dialogo Index
Files e si seleziona il file nella finestra di dialogo Open. La procedura va ripetuta per
ogni file indice non di produzione o .NDX. Dopo avere aggiunto tutti gli indici
desiderati si fa clic sul pulsante OK della finestra di dialogo Index Files.
La stessa operazione può essere eseguita da programma in fase di esecuzione. Allo
scopo, si accede alla proprietà IndexFiles utilizzando le proprietà e i metodi delle liste
di stringhe. Quando si aggiunge un nuovo gruppo di indici, prima si chiama il
metodo Clear della proprietà IndexFiles della tabella per rimuovere eventuali voci
inserite. Si chiama il metodo Add per aggiungere ogni file indice non di produzione o
file .NDX:
with Table2.IndexFiles do begin
Clear;
Add(qBystate.ndxq);
Add(qByzip.ndxq);
Add(qFullname.ndxq);
Add(qSt_name.ndxq);
end;
Dopo avere aggiunto gli eventuali file indice non di produzione o .NDX, diventano
disponibili i nomi dei singoli indici nel file indice ed è possibile assegnarli alla
proprietà IndexName. I tag indice vengono elencati anche quando si utilizza il metodo
GetIndexNames ed quando si esaminano le definizioni di indice attraverso gli oggetti
TIndexDef nella proprietà IndexDefs. I file .NDX elencati correttamente vengono
aggiornati automaticamente mano a mano che i dati vengono aggiunti, modificati o
cancellati nella tabella (indipendentemente dal fatto che la proprietà IndexName
utilizzi o meno un certo indice).
Nell’esempio qui riportato, il componente IndexFiles del componente tabella
AnimalsTable è impostato al file indice non di produzione ANIMALS.MDX e quindi
la sua proprietà IndexName è impostata al tag indice chiamato ”NAME”:
AnimalsTable.IndexFiles.Add(qANIMALS.MDXq);
AnimalsTable.IndexName := qNAMEq;
Una volta che si è specificato il file indice, l’utilizzo di indici non di produzione o
.NDX non differisce da quello di qualsiasi altro indice. Specificando un nome indice
si ordinano i dati nella tabella rendendoli disponibili per ricerche indicizzate, per
intervalli e (nel caso di indici non di produzione) per collegamenti master-detail. Per
i dettagli su questo modo di usare gli indici, consultare “Utilizzo dei dataset di tipo
tabella” a pagina 24-26.
Quando si utilizzano indici .NDX, in stile dBASE III, con componenti TTable vanno
tenute presenti due considerazioni particolari. La prima è che i file .NDX non si
possono usare come base per collegamenti master-detail. La seconda è che quando si
LÊarchitettura BDE
Ad esempio, con questo codice si aggiornano tutti i record della tabella attiva con
record della tabella Customer che hanno gli stessi valori per i campi dell’indice attivo:
Table1.BatchMove(qCUSTOMER.DBq, batUpdate);
BatchMove restituisce il numero di record importati con successo.
LÊarchitettura BDE
Utilizzo di TQuery
TQuery rappresenta una singola istruzione Data Definition Language (DDL) o Data
Manipulation Language (DML) (ad esempio, un comando SELECT, INSERT,
DELETE, UPDATE, CREATE INDEX o ALTER TABLE). Il linguaggio nei comandi
dipende dal server, ma di solito è conforme allo standard SQL-92 del linguaggio
SQL. TQuery implementa tutte le funzionalità di base introdotte da TDataSet, come
pure tutte le funzionalità speciali tipiche dei dataset di tipo query. Prima di
analizzare le funzionalità esclusive di cui TQuery dispone, è bene prendere
familiarità con le funzioni database fondamentali descritte in “I dataset”, tra cui la
sezione sui dataset di tipo query che inizia a pagina 24-44.
Siccome TQuery è un dataset per BDE, si deve di solito associarlo a un database e a
una sessione. (L’unica eccezione è quando si utilizza TQuery per una query
eterogenea). Il paragrafo “Associazione di un dataset a connessioni di database e di
sessione” a pagina 26-3 descrive come si formano queste associazioni. Si specifica
l’istruzione SQL della query impostando la proprietà SQL.
Un componente TQuery può accedere a dati in:
• Tabelle Paradox o dBASE, utilizzando Local SQL, che fa parte di BDE. Local SQL è
un sottoinsieme delle specifiche SQL-92. Supporta la maggior parte del DML e una
porzione di DDL sufficiente a funzionare con questi tipi di tabelle. Per i dettagli
sulla sintassi SQL supportata, consultare la guida SQL locale, LOCALSQL.HLP..
• Database locali InterBase Server, utilizzando il motore InterBase. Per informazioni
sul supporto della sintassi SQL standard e della sintassi estesa SQL-92 di
InterBase, consultare Language Reference di InterBase.
• Database su server di database remoti come Oracle, Sybase, MS-SQL Server,
Informix, DB2 e InterBase. Per accedere a un server remoto è necessario installare
il driver SQL Link e appropriato e il software client (fornito dal produttore)
specifico per il server di database. Viene accettata qualsiasi sintassi standard SQL
supportata da questi server. Per informazioni sulla sintassi SQL, sulle sue
limitazioni ed estensioni, fare riferimento alla documentazione del server in
questione.
LÊarchitettura BDE
LÊarchitettura BDE
LÊarchitettura BDE
Utilizzo di TStoredProc
TStoredProc rappresenta una procedura registrata e implementa tutte le funzionalità
di base introdotte da TDataSet, in aggiunta alla maggior parte delle funzioni speciali
tipiche dei dataset di tipo procedura registrata. Prima di studiare le funzioni
esclusive introdotte da TStoredProc, è bene impadronirsi delle funzionalità database
comuni descritte in “I dataset”,, compresa la sezione sui dataset di tipo procedura
registrata che inizia a pagina pagina 24-52.
TStoredProc è un dataset per BDE, per cui va associato a un database e a una sessione.
Il paragrafo “Associazione di un dataset a connessioni di database e di sessione” a
pagina 26-3 spiega come formare queste associazioni. Una volta associato il dataset è
a un database e a una sessione, è possibile collegarlo a una particolare procedura
registrata impostando la proprietà StoredProcName.
TStoredProc differisce dagli altri dataset di tipo procedura registrata per queste
ragioni:
• Consente di controllare meglio la connessione dei parametri.
• Supporta le procedure registrate ridefinite Oracle.
LÊarchitettura BDE
LÊarchitettura BDE
LÊarchitettura BDE
LÊarchitettura BDE
Uso di ODBC
Un’applicazione può utilizzare delle sorgenti dati ODBC (ad esempio, Btrieve). Una
connessione tramite un driver ODBC richiede
• Un driver ODBC acquistabile separatamente.
• Il Microsoft ODBC Driver Manager.
LÊarchitettura BDE
LÊarchitettura BDE
LÊarchitettura BDE
pagina 26-25. Per informazioni su ConfigMode, consultare “Operazioni con gli alias
BDE” a pagina 26-26.
Una volta attivata la sessione, è possibile aprire le sue connessioni con il database
chiamando il metodo OpenDatabase.
Nel caso di componenti session inseriti in un modulo dati o in una scheda,
impostando Active a False si chiudono i database o i dataset aperti. In fase di
esecuzione, la chiusura dei database e dei dataset attiva gli eventi associati.
LÊarchitettura BDE
LÊarchitettura BDE
Session.CloseDatabase(DBDemosDatabase);
Se il nome del database specificato è associato a a un componente database
temporaneo (implicito) e la proprietà KeepConnections della sessione è False, il
componente database viene liberato, e la connessione viene effettivamente chiusa.
LÊarchitettura BDE
var
DB: TDatabase;
begin
DB := Session.FindDatabase(qDBDEMOSq);
if (DB = nil) then{ database doesnqt exist for session so,}
DB := Session.OpenDatabase(qDBDEMOSq);{ create and open it}
if Assigned(DB) and DB.Connected then begin
DB.StartTransaction;
...
end;
end;
LÊarchitettura BDE
LÊarchitettura BDE
True. Il metodo AddPassword passa alla sessione una stringa da utilizzare come
password della tabella. Il parametro Continue indica a Delphi che non sono necessarie
ulteriori richieste di password per questo tentativo di aprire la tabella. Il valore
predefinito di Continue è False per cui bisogna dargli esplicitamente il valore True. Se
Continue è False, terminata l’esecuzione del gestore di evento, riparte un evento
OnPassword -anche se mediante AddPassword è stata passata la password valida. Se
Continue è True, dopo l’esecuzione del gestore di evento e se la stringa passata con
AddPassword non è la password valida, il tentativo di aprire la tabella non riesce e
viene sollevata un’eccezione.
OnPassword può essere innescato da due circostanze. Il primo è il tentativo di aprire
una tabella protetta da password (dBASE o Paradox) quando alla sessione non è stata
già fornita la password valida. (in caso contrario, l’evento OnPassword non si
verifica).
L’altra circostanza è una chiamata al metodo GetPassword. GetPassword genera un
evento OnPassword oppure, se la sessione non ha un gestore di evento OnPassword,
visualizza una finestra di dialogo Default password. Restituisce True se il gestore di
evento OnPassword o la finestra di dialogo predefinita hanno aggiunto una password
alla sessione, e False se non è stata indicata nessuna stringa.
Nel seguente esempio, il metodo Password è indicato come gestore di evento
OnPassword della sessione predefinita, assegnandolo alla proprietà OnPassword
dell’oggetto globale Session.
procedure TForm1.FormCreate(Sender: TObject);
begin
Session.OnPassword := Password;
end;
Nel metodo Password, la funzione InputBox chiede la password all’utente. Il metodo
AddPassword poi fornisce programmaticamente alla sessione la password immessa
nella finestra di dialogo.
procedure TForm1.Password(Sender: TObject; var Continue: Boolean);
var
Passwrd: String;
begin
Passwrd := InputBox(qEnter passwordq, qPassword:q, qq);
Continue := (Passwrd > qq);
Session.AddPassword(Passwrd);
end;
L’evento OnPassword (e dunque il gestore di evento Password) è innescato da un
tentativo di aprire una tabella protetta da password, come dimostrato qui di seguito.
Sebbene il gestore di evento OnPassword chieda all’utente di fornire la password, il
tentativo di aprire la tabella fallisce se si immette una password non valida o se
qualcos’altro non va a buon fine.
begin
try
Table1.Open; { this line triggers the OnPassword event }
except
on E:Exception do begin { exception if cannot open table
}
LÊarchitettura BDE
N NetFileDir può essere modificato solo quando in un’applicazione non ci sono file
Paradox aperti. Se si modifica NetFileDir in esecuzione, bisogna verificare che esso
punti una directory di rete valida che sia condivisa dagli utenti di rete.
PrivateDir specifica la directory dove vengono registrati i i file temporanei di
elaborazione delle tabelle, come quelli che BDE genera per gestire le istruzioni SQL
locali. Se non viene specificato il valore della proprietà PrivateDir, BDE nel momento
in cui viene inizializzato utilizza automaticamente la directory corrente. Se
l’applicazione viene eseguita direttamente da un file server di rete, è possibile
migliorare in esecuzione la performance dell’applicazione impostando PrivateDir su
un disco rigido locale di un utente prima di aprire il database.
N Non impostare PrivateDir in fase di progettazione per poi aprire la sessione nell’IDE.
Così facendo, viene generato l’errore Directory is busy quando l’applicazione viene
eseguita a partire è dall’IDE.
Il seguente codice modifica l’impostazione della proprietà PrivateDir della sessione
predefinita sulla directory C: \TEMP di un utente:
Session.PrivateDir := qC:\TEMPq;
LÊarchitettura BDE
LÊarchitettura BDE
alias in memoria sul file di configurazione BDE, dove altre applicazioni BDE capaci
di funzionare con BDE possono leggerli e utilizzarli.
Dopo avere creato un alias, per modificarne i parametri si ricorre a ModifyAlias.
ModifyAlias accetta due parametri: il nome dell’alias da modificare e una lista di
stringhe contenente i parametri da cambiare e i rispettivi valori. Ad esempio, con le
seguenti istruzioni ModifyAlias cambia in READ/WRITE il parametro OPEN MODE
dell’alias CATS facendolo diventare nella sessione predefinita:
var
List: TStringList;
begin
List := TStringList.Create;
with List do begin
Clear;
Add(qOPEN MODE=READ/WRITEq);
end;
Session.ModifyAlias('CATS', List);
List.Free;
...
Per cancellare un alias precedentemente creato nel corso di una sessione, si ricorre al
metodo DeleteAlias. DeleteAlias accetta un parametro, il nome dell’alias da cancellare
e rende inaccessibile l’alias alla sessione.
N DeleteAlias non rimuove un alias dal file di configurazione BDE se l’alias è stato
scritto sul file da una chiamata precedente a SaveConfigFile. Per togliere l’alias dal file
di configurazione dopo avere chiamato DeleteAlias, bisogna chiamare nuovamente
SaveConfigFile.
I componenti session forniscono cinque metodi per recuperare le informazioni
relative a un alias BDE, comprese le informazioni sul parametro e quelle sul driver.
Essi sono:
• GetAliasNames, per elencare gli alias ai quali una sessione ha accesso.
• GetAliasParams, per elencare i parametri di un alias specificato.
• GetAliasDriverName, per restituire il nome del driver BDE utilizzato dall’alias.
• GetDriverNames, per restituire una lista di tutti i driver BDE disponibili per la
sessione.
• GetDriverParams, per restituire parametri di driver relativi a un driver specificato.
Per ulteriori informazioni sull’utilizzo dei metodi per recuperare le informazioni di
una sessione, consultare “Reperimento di informazioni su una sessione” qui di
seguito. Per ulteriori informazioni sugli alias BDE e sui driver SQL Links con cui essi
funzionano, consultare la Guida BDE in linea, BDE32.HLP.
LÊarchitettura BDE
LÊarchitettura BDE
LÊarchitettura BDE
N Quando si colloca un componente session, è necessario anche dare alla sua proprietà
SessionName un valore univoco, per evitare conflitti con la proprietà SessionName
della sessione predefinita.
Il fatto di inserire in fase di progetto un componente session presuppone che il
numero di thread (e quindi di sessioni) richiesti dall’applicazione durante
l’esecuzione sia stabile. Tuttavia, è più probabile che un’applicazione debba creare
sessioni dinamicamente. Per creare delle sessioni dinamicamente, bisogna chiamare
in fase di esecuzione il metodo OpenSession dell’oggetto globale Sessions.
OpenSession richiede un singolo parametro, un nome di sessione univoco rispetto a
tutti i nomi di sessione dell’applicazione. Con questo codice si crea dinamicamente e
si attiva una nuova sessione con un nome generato univocamente:
Sessions.OpenSession(qRunTimeSessionq + IntToStr(Sessions.Count + 1));
Questa istruzione genera un nome univoco di una nuova sessione recuperando il
numero di sessioni corrente e aggiungendo uno al valore trovato. Notare che se si
creano e distruggono dinamicamente delle sessioni in fase di esecuzione, l’esempio
qui riportato non si comporta come previsto. Tuttavia, l’esempio mostra come
utilizzare le proprietà e i metodi di Sessions per gestire sessioni multiple.
Sessions è una variabile di tipo TSessionList che viene automaticamente istanziata nel
caso di applicazioni database BDE. Le proprietà e i metodi di Sessions si utilizzano
LÊarchitettura BDE
transazione SQL. BDE non elabora l’istruzione SQL. Usando passthrough SQL si
possono sfruttare direttamente i controlli di transazione offerti dal server, specialmente
quando sono di tipo non-standard.
Per per controllare una transazione mediante passthrough SQL, è necessario
• Installare i driver SQL Links corretti. Se installando Delphsi è scelta l’opzione
”Typical”, tutti i driver SQL Links sono già installati correttamente.
• Configurare il protocollo di rete. Consultare l’amministratore di rete per ulteriori
informazioni.
• Avere accesso a un database situato su un server remoto.
• Mediante SQL Explorer impostare SQLPASSTHRU MODE a NOT SHARED.
SQLPASSTHRU MODE specifica se le istruzioni BDE e passthrough SQL possono
condividere gli stessi collegamenti al database. Nella maggior parte dei casi,
l’impostazione di SQLPASSTHRU MODE è SHARED AUTOCOMMIT. Tuttavia, è
impossibile l’uso condiviso di connessioni con il database quando si utilizzano
istruzioni di controllo di transazione. Per ulteriori informazioni su modi
SQLPASSTHRU, consultare il file di guida del programma di utilità BDE
Administration.
• Per Paradox, le transazioni locali possono essere eseguite solo su tabelle che
abbiano indici validi. Non è possibile il rollback dei dati con tabelle Paradox prive
di indici.
• Si può blozzare e modificare solo un numero limitato di record. Con tabelle
Paradox, il limite è 255 record. Con tabelle dBASE il limite è 100.
• Le non si possono eseguire transazioni con il driver ASCII BDE.
• Se si chiude un cursore su una tabella durante una transazione se ne determina il
rollback a meno che:
• Non ci siano più tabelle aperte.
• Il cursore venga chiuso su una tabella che non ha subito modifiche.
N Per applicare gli aggiornamenti da una procedura registrata o da una query SQL che
non restituisce un set risultato ”live”, è necessario utilizzare TUpdateSQL per
specificare come eseguire gli aggiornamenti. Per aggiornamenti a concatenamenti
(query implicanti due o più tabelle), è necessario fornire un oggetto TUpdateSQL per
ogni tabella coinvolta, e utilizzare il gestore di evento OnUpdateRecord per richiamare
questi oggetti in modo da eseguire gli aggiornamenti. Consultare “Aggiornamento di
dataset mediante oggetti update” a pagina 26-42 per i dettagli.
begin
UpdateTable.Edit;
UpdateTable.Fields[1].AsString := VarToStr(DataSet.Fields[1].NewValue);
UpdateTable.Post;
end;
ukInsert:
begin
UpdateTable.Insert;
UpdateTable.Fields[1].AsString := VarToStr(DataSet.Fields[1].NewValue);
UpdateTable.Post;
end;
ukDelete: UpdateTable.Delete;
end;
UpdateAction := uaApplied;
end;
W Non chiamare metodi di dataset (come Next e Prior) che modificano il record attivo,
perché si farebbe entrare in un loop infinito il gestore di evento.
Di solito il parametro E è del tipo EDBEngineError. Da questo tipo di eccezione, si può
estrarre un messaggio di errore che è possibile mostrare agli utenti nel gestore di
errore. Ad esempio, si potrebbe usare questo codice per visualizzare un messaggio di
errore nell’intestazione di una finestra di dialogo:
ErrorLabel.Caption := E.Message;
Questo parametro è anche utile per stabilire la causa effettiva dell’errore di
aggiornamento. È possibile estrarre degli specifici codici di errore da EDBEngineError
e in base ad essi eseguire l’azione appropriata.
W Ricordare che le istruzioni SQL generate sono punti di partenza di creare le istruzioni
di aggiornamento. In certi casi, bisogna modificarle per farle eseguire correttamente.
Ad esempio, quando si gestiscono dati contenenti valori NULL, è necessario
modificare la clausola WHERE in modo che sia
WHERE field IS NULL
invece di usare la variabile di campo generata. Ognuna delle istruzioni va testata
personalmente prima di essere accettata.
Per commutare tra le istruzioni SQL generate e modificarle in base alle esigenze,
utilizzare i pulsanti di scelta Statement Type.
Per accettare le istruzioni e associarle alle proprietà SQL del componente update, fare
clic su OK.
N Se si creano istruzioni SQL contenenti parametri che non rimandano i valori del
campo modificati oppure originali, l’oggetto update non sa come collegare i loro
valori. Tuttavia, lo si può fare manualmente, mediante la proprietà Query
dell’oggetto update. Per i dettagli fare riferimento a “Utilizzo della proprietà Query
di un componente update” a pagina 26-50.
Alcuni tipi di tabella potrebbero non essere in grado di trovare il record nella tabella
base, quando i campi utilizzati per identificare il record contengono valori NULL. In
questi casi, l’aggiornamento per cancellazione non va a buon fine. Per ovviare a
questa situazione, bisogna aggiungere una condizione ai campi che potrebbero
contenere valori NULL utilizzando il predicato IS NULL (oltre a una condizione per i
valori non-NULL). Ad esempio, quando un campo FirstName può contenere un
valore NULL:
DELETE FROM Names
WHERE (LastName = :OLD_LastName) AND
((FirstName = :OLD_FirstName) OR (FirstName IS NULL))
L’istruzione InsertSQL deve contenere solo un’istruzione SQL con il comando
INSERT. La tabella base da aggiornare deve essere indicata nella clausola INTO.
Nella clausola VALUES, va fornita una lista di parametri separati da virgole. Se i
parametri hanno lo stesso nome del campo, ricevono automaticamente il valore del
record di aggiornamento memorizzato nella cache. Se i nomi sono diversi, bisogna
fornire i valori del parametro. La lista di parametri fornisce i valori dei campi del
record appena inserito. Il numero di parametri deve essere uguale a quello dei campi
elencati nell’istruzione.
INSERT INTO Inventory
(ItemNo, Amount)
VALUES (:ItemNo, 0)
Nell’istruzione ModifySQL ci deve essere solo un’istruzione SQL con il comando
UPDATE. La tabella base da aggiornare va chiamata nella clausola FROM. Nella
clausola SET si includono una o più assegnazioni di valore. Se i valori presenti nella
clausola SET sono parametri il cui nome è uguale a quello dei campi, i parametri
ricevono automaticamente i valori dei campi con lo stesso nome presenti nel record
aggiornato nella cache. Si possono assegnare ulteriori valori di campo mediante altri
parametri, purché i nomi siano diversi e i valori siano indicati manualmente. Come
con l’istruzione DeleteSQL, va fornita una clausola WHERE per verificare
univocamente il record da aggiornare utilizzando parametri con lo stesso nome dei
campi ma preceduti da ”OLD_”. Nell’istruzione di aggiornamento qui di seguito, il
parametro :ItemNo riceve automaticamente un valore mentre :Price non lo riceve.
UPDATE Inventory I
SET I.ItemNo = :ItemNo, Amount = :Price
WHERE (I.ItemNo = :OLD_ItemNo)
Considerando l’aggiornamento SQL precedente, ecco un esempio dove l’utente
modifica un record esistente. Il valore originale del campo ItemNo è 999. In una
griglia connessa al dataset memorizzato nella cache, l’utente fa diventare 123 il valore
del campo ItemNo 123 mentre Amount diventa 20. Quando si richiama il metodo
ApplyUpdates, questa istruzione SQL agisce su tutti i record della tabella base in cui
il campo ItemNo è 999, utilizzando il vecchio valore del campo nel parametro
:OLD_itemno. Nei record interessati, cambia il valore del campo ItemNo in 123
(utilizzando il parametro :ItemNo, il valore preso dalla griglia) mentre Amount
diventa 20.
N Se l’istruzione SQL utilizza parametri diverso dai tipi incorporati (sia per i valori del
campo originali che per quelli aggiornati), i valori del parametro vanno forniti
manualmente invece di basarsi sulla sostituzione di parametro fornita dal metodo
Apply. Per informazioni su come indicare manualmente i valori dei parametri, vedere
“Utilizzo della proprietà Query di un componente update” a pagina 26-50.
Per informazioni sulla sostituzione dei parametri predefiniti nelle istruzioni SQL di
un oggetto update, vedere “Sostituzione dei parametri nelle istruzioni di
aggiornamento SQL” a pagina 26-44.
W Se la proprietà UpdateObject del dataset viene usata per associare dataset e oggetto
update, ExecSQL viene chiamato automaticamente. In questo caso, non si deve
chiamare ExecSQL in un gestore di evento OnUpdateRecord o BeforeUpdateRecord, in
quanto si avrebbe un secondo tentativo di applicare l’aggiornamento al record attivo.
I gestori di evento OnUpdateRecord e BeforeUpdateRecord indicano il tipo di
aggiornamento da applicare con un parametro UpdateKind di tipo TUpdateKind. Il
parametro va passato al metodo ExecSQL per indicare quali istruzioni SQL utilizzare.
Il seguente codice lo illustra utilizzando un gestore di evento BeforeUpdateRecord:
procedure TForm1.BDEClientDataSet1BeforeUpdateRecord(Sender: TObject; SourceDS: TDataSet;
DeltaDS: TCustomClientDataSet; UpdateKind: TUpdateKind; var Applied: Boolean);
begin
with UpdateSQL1 do
begin
DatabaseName := (SourceDS as TDBDataSet).DatabaseName;
SessionName := (SourceDS as TDBDataSet).SessionName;
ExecSQL(UpdateKind);
Applied := True;
end;
end;
Se durante l’esecuzione del programma di aggiornamento viene sollevata
un’eccezione, l’esecuzione continua nell’evento OnUpdateError, se questo è definito.
Utilizzo di TBatchMove
Utilizzo di TBatchMove
TBatchMove incorpora alcune funzioni del Borland Database Engine (BDE) che
consentono di duplicare un dataset, di aggiungere a un dataset record presi da un
altro, di aggiornare i record di un dataset con record presi da un altro dataset e di
cancellare da un dataset record corrispondenti a record di un altro dataset.
TBatchMove viene usato principalmente per:
• Trasferire dati da un server a un datasource locale per analizzarli o per svolgere
altre operazioni.
Utilizzo di TBatchMove
Utilizzo di TBatchMove
Aggiunta di record
Per l’aggiunta di dati, il dataset di destinazione deve rappresentare una tabella
esistente. Durante l’operazione di aggiunta, BDE converte i dati per adeguarli ai tipi e
alle dimensioni del dataset di destinazione, se necessario. Se la conversione non è
possibile, viene sollevata un’eccezione e i dati non vengono aggiunti.
Aggiornamento di record
Per l’aggiornamento dei dati, il dataset di destinazione deve rappresentare una
tabella esistente e deve avere un indice definito che consenta il confronto dei record.
Se per il confronto sono usati i campi indice primari, i record che nel dataset di
destinazione hanno campi indice corrispondenti ai campi indice dei record nel
dataset di origine vengono riscritti con i dati del dataset di origine. Durante
l’operazione di aggiornamento, BDE converte i dati per adeguarli ai tipi e alle
dimensioni del dataset di destinazione, se necessario.
Utilizzo di TBatchMove
Copia di dataset
Per copiare un dataset sorgente, il dataset di destinazione non deve rappresentare
una tabella esistente. In caso contrario, l’operazione di spostamento batch sovrascrive
la tabella esistente con una copia del dataset di origine.
Se i dataset di origine e di destinazione sono gestiti da motori di database di tipo
diverso, (per esempio, Paradox e InterBase), BDE crea a destinazione un dataset la cui
struttura è quanto più possibile simile a quella del dataset sorgente ed esegue
automaticamente le conversioni di tipo e di dimensione dei dati, secondo quanto
necessario.
Cancellazione di record
Per cancellare dati nel dataset di destinazione, questo deve rappresentare una tabella
esistente e deve avere un indice definito che consenta il confronto dei record. Se per il
confronto si usano i campi indice principali, i record i cui campi indice nel dataset
destinazione corrispondono ai campi indice dei record nel dataset sorgente vengono
cancellati nella tabella di destinazione.
Utilizzo di TBatchMove
Per fare corrispondere una colonna chiamata SourceColName nella tabella sorgente
con una colonna chiamata DestColName nella tabella di destinazione, la sintassi è :
DestColName = SourceColName
Se i tipi di dati della colonna sorgente e di destinazione non sono uguali, l’operazione
di spostamento batch prova ad applicare la ”migliore delle corrispondenze”. Tronca i
dati di tipo carattere, se necessario, e tenta un po’ di conversione, se possibile. (Ad
esempio, mappando una colonna CHAR(10) verso una colonna CHAR(5) troncherà
gli ultimi cinque caratteri della colonna sorgente.
Come esempio di conversione, se una colonna sorgente di dati di tipo carattere viene
fatta corrispondere con una colonna di destinazione di tipo integer, l’operazione di
spostamento batch converte il carattere ’5 ’ nel corrispondente valore integer. Valori
che non possono essere convertiti generano errori. Per ulteriori informazioni sugli
errori, consultare “Gestione degli errori di spostamento batch” a pagina 26-55.
Quando sposta dati fra tabelle di tipo diverso, un componente batch move traduce
opportunamente i tipi di dati in base al tipo di server del dataset. Per conoscere le più
recenti tabelle di mappatura tra i vati tipi server, consultare la guida BDE in linea.
N Per gli spostamenti batch verso server di database SQL, bisogna avere il server di
database in questione e una versione di Delphi sulla quale sia installato lo SQL Link
appropriato, oppure si può usare ODBC, se si dispone degli opportuni driver ODBC.
Il Data Dictionary
N Non specificando ProblemTableName, i dati nel record vengono troncati e inseriti nella
tabella di destinazione.
Il Data Dictionary
Quando si utilizza BDE per accedere ai dati, l’applicazione ha accesso al Data
Dictionary. Il Data Dictionary mette a disposizione un’area di memoria
personalizzabile, indipendente dalle applicazioni, dove è possibile creare set di
attributi di campi estesi che descrivono il contenuto e l’aspetto dei dati.
Il Data Dictionary
Capitolo
(come Microsoft SQL Server), oltre ad un driver OLE DB o un driver ODBC specifico
per quel particolare sistema di database.
La maggior parte dei componenti dbGo hanno delle controparti dirette nei
componenti disponibili per altri meccanismi di accesso ai dati: un componente
connection di database (TADOConnection) e diversi tipi di dataset. Inoltre, dbGo
include TADOCommand, un componente semplice che non è un dataset ma che
rappresenta un comando SQL da eseguire sul datastore ADO.
In tabella sono elencati i componenti ADO.
Se la connessione, non viene portata a termine con successo prima della scadenza del
periodo di tempo specificato in ConnectionTimeout, il tentativo di connessione viene
annullato.
with ADOConnection1 do begin
ConnectionTimeout := 10 {seconds};
Open;
end;
CommandTimeout specifica il periodo di tempo, in secondi, che deve trascorrere prima
che un tentativo di comando sia considerato come non riuscito. Se il comando,
iniziato da una chiamata al metodo Execute non è stato portato a termine con successo
prima della scadenza del periodo di tempo specificato in CommandTimeout, il
comando viene annullato e ADO genera un’eccezione:
with ADOConnection1 do begin
CommandTimeout := 10 {seconds};
Execute(qDROP TABLE Employee1997q, cmdText, []);
end;
Altri eventi
I componenti connection ADO introducono altri due eventi utilizzabili per
rispondere alle notifiche provenienti dall’oggetto di connessione ADO sottostante:
• L’evento OnExecuteComplete si verifica dopo che il componente connection ha
eseguito un comando sul datastore (ad esempio, dopo avere chiamato il metodo
Execute). OnExecuteComplete indica se l’esecuzione ha avuto successo.
• L’evento OnInfoMessage entra in azione quando l’oggetto connection sottostante
fornisce informazioni dettagliate, dopo il completamento di un’operazione. Il
gestore di evento OnInfoMessage riceve l’interfaccia verso un oggetto ADO Error
contenente le informazioni dettagliate e un codice di stato che segnala se
l’operazione è andata a buon fine.
Tabella 27.5 Confronto tra gli aggiornamenti in cache di ADO e gli aggiornamenti nel dataset client
Dataset ADO TClientDataSet Descrizione
LockType Non utilizzato: i dataset Specifica se il dataset è aperto in modo
client memorizzano sempre aggiornamento batch.
gli aggiornamenti nella cache
CursorType Non utilizzato: i dataset Specifica in che misura il dataset ADO è isolato
client funzionano sempre con dalle modifiche sul server.
un’”istantanea” in memoria
dei dati
RecordStatus UpdateStatus Indica l’eventuale tipo di aggiornamento che si è
verificato sulla riga corrente. RecordStatus fornisce
più informazioni di UpdateStatus.
FilterGroup StatusFilter Specifica quali tipi di record sono disponibili.
FilterGroup fornisce una gamma più ampia di
informazioni.
UpdateBatch ApplyUpdates Applica al server di database gli aggiornamenti
nella cache. A differenza di ApplyUpdates,
UpdateBatch permette di limitare i tipi di
aggiornamenti da applicare.
CancelBatch CancelUpdates Elimina gli aggiornamenti in sospeso e torna ai
valori originari. A differenza di CancelUpdates,
CancelBatch permette di limitare i tipi di
aggiornamenti da annullare.
L’utilizzo delle funzionalità degli aggiornamenti batch dei componenti dataset ADO
può essere schematizzata come segue:
• Apertura del dataset in modalità aggiornamento batch
• Ispezione dello stato di aggiornamento delle singole righe
• Filtraggio di più righe in base allo stato di aggiornamento
• Applicazione degli aggiornamenti batch alle tabelle di base
• Annullamento degli aggiornamenti batch
Utilizzo di TADODataSet
TADODataSet è un dataset di uso comune usato per lavorare con i dati di un
datastore ADO. A differenza degli altri componenti dataset ADO, TADODataSet non
è di tipo tabellare, di tipo query o di tipo procedura registrata, ma funziona
indifferentemente come uno qualsiasi di questi tre tipi:
• Come un dataset di tipo tabella, TADODataSet permette di rappresentare tutte le
righe e le colonne di una singola tabella di database. Per utilizzarlo in questo
modo, si imposta la proprietà CommandType a cmdTable e la proprietà
CommandText al nome della tabella. TADODataSet supporta attività di tipo
tabellare come
• Assegnazione di indici per ordinare i record o per costituire la base di ricerche
basate su record. Oltre alle proprietà e i metodi di indicizzazione standard
descritti in “Ordinamento dei record con indici” a pagina 24-27, TADODataSet
Annullamento di comandi
Se si esegue il comando in modo asincrono, allora dopo avere chiamato Execute è
possibile interrompere l’esecuzione chiamando il metodo Cancel:
procedure TDataForm.ExecuteButtonClick(Sender: TObject);
begin
ADOCommand1.Execute;
end;
procedure TDataForm.CancelButtonClick(Sender: TObject);
begin
ADOCommand1.Cancel;
end;
Il metodo Cancel sortisce un effetto solo se c’è un comando in sospeso e il comando
era stato eseguito in modo asincrono (il parametro ExecuteOptions del metodo Execute
contiene eoAsynchExecute). Un comando viene definito ”in sospeso” se è stato
chiamato il metodo Execute ma il comando non è stato ancora completato oppure è
andato in time-out.
Se un comando non viene annullato o completato entro il numero di secondi
specificato nella proprietà CommandTimeout, il comando va in time-out. Per
impostazione predefinita, i comandi vanno in time-out dopo 30 secondi.
Capitolo
Configurazione di TSQLConnection
Per descrivere una connessione al database in modo sufficientemente dettagliato
affinché TSQLConnection sia in grado di aprire una connessione, è necessario
identificare sia il driver da utilizzare sia un insieme di parametri di connessione che
vengono passati a quel driver.
La relazione tra questi due file oggetto condivisi e il nome del database viene
memorizzata in un file di nome dbxdrivers.ini che viene aggiornato quando si
installa un driver dbExpress. Di solito, non è necessario occuparsi di questi file perché
il componente connection SQL li ricercherà in dbxdrivers.ini non appena si imposterà
il valore della proprietà DriverName. Quando si imposta la proprietà DriverName,
TSQLConnectionimposta automaticamente le proprietà LibraryName e VendorLib
l’applicazione non ha più bisogno di appoggiarsi al file dbxdrivers.ini. (Ciò significa
che non è necessario distribuire il file dbxdrivers.ini con l’applicazione, a meno che
non si imposti la proprietà DriverNameal momento dell’esecuzione.)
N È possibile anche riempire il dataset unidirezionale con i metadati relativi a tutto ciò
che è disponibile sul server. Per informazioni sull’operazione, vedere “Prelievo di
metadati in un dataset unidirezionale” a pagina 28-13.
SQL definisce query che eseguono azioni sul server ma che non restituiscono record,
come query di tipo UPDATE. Queste query sono trattate in “Esecuzione di comandi
che non restituiscono record” a pagina 28-10.
alla tabella una nuova colonna e DROP CONSTRAINT per cancellare dalla tabella un
vincolo esistente.
Ad esempio, la seguente istruzione crea una procedura registrata di nome
GET_EMP_PROJ in un database InterBase:
CREATE PROCEDURE GET_EMP_PROJ (EMP_NO SMALLINT)
RETURNS (PROJ_ID CHAR(5))
AS
BEGIN
FOR SELECT PROJ_ID
FROM EMPLOYEE_PROJECT
WHERE EMP_NO = :EMP_NO
INTO :PROJ_ID
DO
SUSPEND;
END
Il codice seguente utilizza un TSQLDataSet per creare questa procedura registrata. Si
noti dell’utilizzo della proprietà ParamCheck per impedire al dataset di confondere i
parametri nella definizione della procedura registrata (:EMP_NO e :PROJ_ID) con un
parametro della query che crea la procedura registrata.
with SQLDataSet1 do
begin
ParamCheck := False;
CommandType := ctQuery;
CommandText := 'CREATE PROCEDURE GET_EMP_PROJ (EMP_NO SMALLINT) ' +
'RETURNS (PROJ_ID CHAR(5)) AS ' +
'BEGIN ' +
'FOR SELECT PROJ_ID FROM EMPLOYEE_PROJECT ' +
'WHERE EMP_NO = :EMP_NO ' +
'INTO :PROJ_ID ' +
'DO SUSPEND; ' +
END';
ExecSQL;
end;
Tabella 28.2 Colonne nelle tabelle di metadati che elencano procedure registrate
Tipo di
Nome della colonna campo Contenuto
RECNO ftInteger Un numero di record che identifica in modo univocamente
ciascun record.
CATALOG_NAME ftString Il nome del catalogo (database) che contiene la procedura
registrata. È analogo al parametro Database di un componente
connection SQL.
SCHEMA_NAME ftString Il nome dello schema che identifica il proprietario della
procedura registrata.
PROC_NAME ftString Il nome della procedura registrata. Questo campo determina
la sequenza di ordinamento del dataset.
PROC_TYPE ftInteger Identifica il tipo di procedura registrata. È la somma di uno o
più dei seguenti valori:
1: Procedura
2: Funzione
4: Package
8: Procedura di sistema
Tabella 28.2 Colonne nelle tabelle di metadati che elencano procedure registrate (continua)
Tipo di
Nome della colonna campo Contenuto
IN_PARAMS ftSmallint Il numero di parametri di input
OUT_PARAMS ftSmallint Il numero di parametri di output.
Tabella 28.5 Colonne nelle tabelle di metadati che elencano parametri (continua)
Tipo di
Nome della colonna campo Contenuto
PARAM_NAME ftString Il nome del parametro. Questo campo determina la
sequenza di ordinamento del dataset.
PARAM_TYPE ftSmallint Identifica il tipo di parametro. È analogo alla proprietà
ParamType di un oggetto TParam.
PARAM_DATATYPE ftSmallint Il tipo di dati del parametro. Questa è una delle costanti
logiche di tipo field definite in sqllinks.pas.
PARAM_SUBTYPE ftSmallint Un sottotipo per il tipo di dati del parametro. Questa è una
delle costanti logiche di sottotipo definite in sqllinks.pas.
PARAM_TYPENAME ftString Una stringa che descrive il tipo di dati. Queste sono le stesse
informazioni contenute in PARAM_DATATYPE e in
PARAM_SUBTYPE, ma in un formato utilizzato in alcune
istruzioni DDL.
PARAM_PRECISION ftInteger Il numero massimo di cifre nei valori a virgola mobile o di
byte (per stringhe e campi Bytes).
PARAM_SCALE ftSmallint Il numero di cifre alla destra della virgola in valori a virgola
mobile.
PARAM_LENGTH ftInteger Il numero di byte richiesti per memorizzare i valori del
parametro.
PARAM_NULLABLE ftSmallint Un Boolean che indica se il parametro può essere lasciato in
bianco (0 significa che il parametro richiede un valore).
Man mano che i comandi SQL vengono inviati al server, la proprietà TraceList di SQL
monitor viene aggiornata automaticamente elencando tutti i comandi SQL
intercettati.
È possibile salvare questa lista in un file specificando un valore per la proprietà
FileName e quindi impostando la proprietà AutoSave a True. AutoSave fa in modo che
SQL monitor salvi in un file il contenuto della proprietà TraceList ogni volta che
intercetta un nuovo messaggio.
Se non si desidera l’appesantimento dovuto al salvataggio del file ogni volta che
viene intercettato un messaggio, è possibile utilizzare il gestore di evento OnLogTrace
per salvare il file solo dopo l’intercettazione di vari messaggi. Ad esempio, il
seguente gestore di evento salva il contenuto di TraceList ogni 10 messaggi,
cancellando il file di registrazione dopo averlo salvato in modo che la lista non
divenga mai troppo lunga:
procedure TForm1.SQLMonitor1LogTrace(Sender: TObject; CBInfo: Pointer);
var
LogFileName: string;
begin
with Sender as TSQLMonitor do
begin
if TraceCount = 10 then
begin
LogFileName := 'c:\log' + IntToStr(Tag) + '.txt';
Tag := Tag + 1; {ensure next log file has a different name }
SaveToFile(LogFileName);
TraceList.Clear; { clear list }
end;
end;
end;
Il driver dbExpress chiama la callback ogni volta che il componente SQL connection
passa un comando al server o il server restituisce un messaggio di errore.
Capitolo
nella sua memoria cache. Mostra, invece, solo i dati che soddisfano le condizioni
dell’intervallo o del filtro. Per ulteriori informazioni sull’utilizzo di filtri, consultare
“Visualizzazione e modifica di un sottoinsieme di dati usando i filtri” a pagina 24-13.
Per ulteriori informazioni sugli intervalli, consultare “Limitazione dei record con gli
intervalli” a pagina 24-32.
Con la maggior parte dei dataset le stringhe del filtro vengono suddivise in comandi
SQL che vengono poi implementati nel database server. Ne deriva che il dialetto SQL
del server limita le operazioni che possono essere utilizzate nelle stringhe del filtro. I
dataset client implementano un proprio supporto per i filtri, che include un maggior
numero di operazioni rispetto agli altri dataset. Per esempio, quando si utilizza un
dataset client, le espressioni filtro possono includere operatori stringa che
restituiscono sottostringhe, operatori che suddividono i valori data/ora, ed altro
ancora. I dataset client consentono, inoltre, l’uso di filtri sui campi BLOB o su tipi di
campi complessi come i campi ADT e i campi array.
Nella tabella seguente sono elencati gli operatori e le funzioni che i dataset client
possono utilizzare nei filtri, oltre a un confronto con altri dataset che supportano
filtri:
Quando si applicano intervalli o filtri, il dataset client memorizza anche tutti i suoi
record in memoria. L’intervallo o il filtro determina semplicemente quali record sono
disponibili per i controlli che servono per visualizzare o per spostarsi tra i dati del
dataset client.
Editing di dati
I dataset client rappresentano i propri dati come un pacchetto dati in memoria.
Questo pacchetto è il valore della proprietà Data. I dataset client rappresentano i
propri dati come un pacchetto dati in memoria. Per impostazione predefinita,
tuttavia, le modifiche non vengono memorizzate nella proprietà Data. Invece, gli
inserimenti, le cancellazioni e le modifiche (apportate dagli utenti o da programma)
vengono memorizzati in un registro interno delle modifiche, rappresentato dalla
proprietà Delta. L’uso di un registro delle modifiche serve a due scopi:
• Il registro delle modifiche è necessario per applicare gli aggiornamenti a un server
di database o a un componente provider esterno.
• Il registro delle modifiche fornisce un supporto sofisticato per l’annullamento
delle modifiche.
La proprietà LogChanges consente di disattivare temporaneamente la registrazione.
Quando LogChanges è True, le modifiche vengono memorizzate nel registro. Quando
è False, le modifiche vengono apportate direttamente alla proprietà Data. È possibile
disattivare il registro delle modifiche nelle applicazioni basate su file se il supporto
per l’annullamento non è necessario.
Le modifiche rimangono nel registro finché non vengono rimosse dall’applicazione.
Le applicazioni rimuovono le modifiche quando si effettua un:
• Annullamento delle modifiche
• Salvataggio delle modifiche
N Il salvataggio del dataset client in un file non rimuove le modiche dal registro delle
modifiche. Quando si ricarica il dataset, le proprietà Data e Delta rimangono
identiche a com’erano quando i dati sono stati salvati.
Ordinamento e indicizzazione
L’uso degli indici fornisce diversi vantaggi alle applicazioni:
• Consente ai dataset client di individuare rapidamente i dati.
• Permettono di applicare gli intervalli per limitare i record disponibili.
• Permettono alle applicazioni di impostare relazioni con altri dataset come tabelle
di consultazione o schede master/detail.
• Consente di specificare l’ordine in cui devono apparire i record.
Se un dataset client rappresenta i dati di un server o utilizza un provider esterno,
eredita un indice e un criterio di ordinamento predefinito in base ai dati che riceve.
L’indice predefinito si chiama DEFAULT_ORDER. Si può utilizzare questo
ordinamento, ma non è possibile cambiare o cancellare l’indice.
Oltre all’indice predefinito, il dataset client mantiene un secondo indice, denominato
CHANGEINDEX, sui record modificati nel registro delle modifiche (proprietà Delta).
CHANGEINDEX ordina tutti i record del dataset client come apparirebbero se
venissero applicate le modifiche specificate in Delta. CHANGEINDEX si basa
sull’ordinamento ereditato da DEFAULT_ORDER. Come avviene con
DEFAULT_ORDER, non è possibile cambiare o cancellare l’indice CHANGEINDEX.
È possibile utilizzare altri indici esistenti o crearne di propri. Nelle sezioni seguenti
viene descritta la procedura per la creazione e l’uso degli indici con i dataset client.
N Potrebbe essere opportuno riesaminare gli argomenti relativi agli indici nei dataset di
tipo tabella, validi anche nel caso dei dataset client. Gli argomenti sono trattati nelle
sezioni “Ordinamento dei record con indici” a pagina 24-27 e “Limitazione dei
record con gli intervalli” a pagina 24-32.
Dato questo ordinamento, i valori adiacenti nella colonna SalesRep sono duplicati. Lo
stesso avviene all’interno dei record di SalesRep 1, i cui valori adiacenti della colonna
Customer sono duplicati. Cioè, i dati sono raggruppati per SalesRep e all’interno del
gruppo SalesRep sono raggruppati per Customer. Ogni raggruppamento ha un
livello associato. In questo caso il gruppo SalesRep ha il livello 1 (in quanto non è
annidato in nessun altro gruppo), mentre il gruppo Customer ha come livello 2 (in
quanto è annidato nel gruppo con il livello 1). Il livello di raggruppamento
corrisponde all’ordine dei campi nell’indice.
I dataset client consentono di determinare dove sta il record attivo all’interno di un
determinato livello di raggruppamento. Ciò consente all’applicazione di visualizzare
i record in modo differente, a seconda che si tratti del primo record del gruppo, della
parte centrale di un gruppo o dell’ultimo record di un gruppo. Per esempio, si
potrebbe voler visualizzare il valore di un campo solo se è il primo record del
gruppo, eliminando i valori duplicati. Questa operazione con la tabella precedente
produce il seguente risultato:
Per determinare dove cade il record attivo all’interno di un gruppo, si deve ricorrere
al metodo GetGroupState. GetGroupState accetta un integer che corrisponde al livello
del gruppo e restituisce un valore che indica la posizione del record corrente
all’interno del gruppo (primo record, secondo record o nessuno dei due).
Quando si crea un indice, è possibile specificare il livello di raggruppamento che esso
supporta (fino al numero di campi nell’indice). GetGroupState non è in grado di
fornire informazioni sui gruppi oltre quel livello, anche se l’indice ordina i record
utilizzando campi aggiuntivi.
N Altri tipi di dataset utilizzano campi calcolati internamente. Tuttavia, con gli altri
dataset questi valori non vengono calcolati in un gestore di evento OnCalcFields.
N Quando si creano campi di aggregazione, alla proprietà Aggregates del dataset client
vengono aggiunti automaticamente gli oggetti appropriati di aggregazione. Non
occorre aggiungerli in modo esplicito durante la creazione dei campi persistenti di
aggregazione. Per ulteriori dettagli sulla creazione dei campi persistenti di
aggregazione, consultare “Definizione di un campo di aggregazione” a pagina 25-10.
Per ciascuna aggregazione la proprietà Expression indica il calcolo di riepilogo che
rappresenta. Expression può contenere una semplice espressione di riepilogo come
Sum(Field1)
o un’espressione completa che abbina informazioni di campi diversi, come
Sum(Qty * Price) - Sum(AmountPaid)
Le espressioni di aggregazione includono uno o più operatori di riepilogo, riportati
nella Tabella 29.2
Gli operatori di riepilogo agiscono sui valori dei campi o sulle espressioni costruite
dai valori dei campi utilizzando gli stessi operatori usati per creare i filtri. (In ogni
caso non si possono annidare operatori di riepilogo). È possibile creare espressioni
utilizzando operatori su valori di riepilogo con altri valori di riepilogo, o su valori di
riepilogo e costanti. Tuttavia, non è consentito combinare valori di riepilogo e valori
di campo, in quanto tali espressioni sono ambigue (non ci sono indicazioni su quale
record deve fornire il valore del campo). Queste regole vengono illustrate nelle
espressioni seguenti:
l’elenco di tutti i dataset disponibili nel progetto. Selezionare quello di cui si vogliono
copiare dati e struttura e scegliere OK. Quando si copia il dataset sorgente, viene
attivato automaticamente il dataset client.
Per copiare da un altro dataset in fase di esecuzione, è possibile assegnargli
direttamente i suoi dati o, nel caso la sorgente dati sia un altro dataset client, è
possibile clonare il cursor.
N Quando si copia la proprietà Data di un altro dataset client, si copia anche il registro
delle modifiche, ma la copia non riflette i filtri o gli intervalli che sono stati applicati.
Per includere i filtri o gli intervalli, occorre clonare il cursor del dataset sorgente.
Se si effettua la copia da un dataset alternativo rispetto ad un dataset client, si può
creare un componente provider del dataset, collegarlo al dataset sorgente e poi
copiarne i dati:
TempProvider := TDataSetProvider.Create(Form1);
TempProvider.DataSet := SourceDataSet;
ClientDataSet1.Data := TempProvider.Data;
TempProvider.Free;
N Quando si assegnano direttamente i dati alla proprietà Data, il nuovo pacchetto dati
viene fuso nei dati esistenti. Tutti i dati precedenti vengono, invece, sostituiti.
Se si intendono fondere le modifiche ricavandole da un altro dataset, anziché
copiarne i dati, si deve utilizzare un componente provider. Creare un provider di
dataset come nell’esempio precedente, ma associarlo al dataset di destinazione e,
anziché copiare la proprietà Data, utilizzare il metodo ApplyUpdates:
TempProvider := TDataSetProvider.Create(Form1);
TempProvider.DataSet := ClientDataSet1;
TempProvider.ApplyUpdates(SourceDataSet.Delta, -1, ErrCount);
TempProvider.Free;
client di condividere i dati del dataset client originale. Ciò è meno oneroso della copia
di tutti i dati originali, ma, dal momento che i dati sono condivisi, il secondo dataset
client non può modificare i dati senza influenzare il dataset client originale.
CloneCursor richiede tre parametri: Source specifica il dataset client da clonare. Gli
ultimi due parametri (Reset e KeepSettings) indicano se copiare informazioni diverse
dai dati. Queste informazioni comprendono tutti i filtri, l’indice attivo, i collegamenti
a una tabella master (quando il dataset sorgente è un set di dettaglio), la proprietà
ReadOnly e tutti i collegamenti a un componente connessione o a un interfaccia
provider.
Quando Reset e KeepSettings sono False, viene aperto un dataset client clonato e
vengono utilizzate le impostazioni del dataset sorgente per definire le proprietà della
destinazione. Quando Reset è True, alle proprietà del dataset di destinazione vengono
attribuiti i valori predefiniti (non viene specificato nessun indice o filtro, nessuna
tabella master, nessun componente connessione o provider, e ReadOnly è False).
Quando KeepSettings è True, le proprietà del dataset di destinazione non vengono
modificate.
attenuare questo problema, è possibile aggiornare i record che non sono stati
ancora modificati. Per i dettagli, vedere “Rinnovo dei record” a pagina 29-32.
5 Applicare i record nella cache locale al database o annullare gli aggiornamenti.
Per ogni record scritto nel database, viene innescato un evento BeforeUpdateRecord.
Se si verifica un errore nel momento in cui viene scritto nel database un singolo
record, un evento OnUpdateError permette all’applicazione di correggere l’errore,
se possibile, e di continuare l’aggiornamento. Una volta completati gli
aggiornamenti, tutti gli aggiornamenti applicati con successo vengono rimossi
dalla cache locale. Per ulteriori informazioni sull’applicazione degli aggiornamenti
al database, vedere “Aggiornamento dei record” a pagina 29-21.
Invece di applicare aggiornamenti, un’applicazione può annullare gli
aggiornamenti, svuotando il registro delle modifiche senza scrivere le modifiche
nel database. È possibile annullare gli aggiornamenti chiamando il metodo
CancelUpdates. Tutti i record cancellati presenti nella cache vengono ripristinati, i
record modificati assumono i valori originali e i record appena inseriti spariscono.
dei due dataset sorgente collegati con una relazione master/detail. Il dataset client
vede il dataset di dettaglio come un campo di dataset annidato. Questa modalità
operativa è necessaria per poter applicare gli aggiornamenti alle tabelle master e
detail nell’ordine corretto.
• Se si vogliono creare gestori di evento che rispondono alla comunicazione fra il
dataset client e il provider (ad esempio, prima e dopo che il dataset client ha
prelevato i record dal provider), è necessario utilizzare TClientDataSet con un
componente provider esterno. I dataset client specializzati pubblicano gli eventi
più importanti per l’applicazione degli aggiornamenti (OnReconcileError,
BeforeUpdateRecord e OnGetTableName), ma non pubblicano gli eventi inerenti alla
comunicazione fra il dataset client e il suo provider, in quanto sono destinati
principalmente alle applicazioni multi-tier.
• Se si utilizza BDE, potrebbe essere opportuno utilizzare un provider e un dataset
sorgente esterni perché potrebbe essere necessario utilizzare un oggetto update.
Benché sia possibile codificare un oggetto update a partire dal gestore di evento
BeforeUpdateRecord di TBDEClientDataSet, è molto più semplice assegnare
semplicemente la proprietà UpdateObject del dataset sorgente. Per informazioni
sull’utilizzo di oggetti update, vedere “Aggiornamento di dataset mediante
oggetti update” a pagina 26-42.
Specifica di un provider
A differenza dei dataset client che sono associati a un meccanismo di accesso ai dati,
TClientDataSet non ha alcun componente provider interno per assemblare i dati o
applicare gli aggiornamenti. Se lo si vuole utilizzare per rappresentare i dati da un
dataset sorgente o da un documento XML, sarà perciò necessario associare il dataset
client a un componente provider esterno.
TIBClientDataSet), sia nel caso che siano componenti separati che forniscono i dati a
TClientDataSet.
Recupero incrementale
Modificando la proprietà PacketRecords, è possibile specificare che il dataset client
preleva i dati in lotti più piccoli. PacketRecords specifica quanti record per volta
devono essere recuperati, oppure il tipo di record da restituire. Per impostazione
predefinita, PacketRecords ha come valore -1, che indica che tutti i record disponibili
vengono recuperati contemporaneamente quando il dataset client viene aperto per la
prima volta, o quando l’applicazione chiama in modo esplicito GetNextPacket.
Quando PacketRecords è -1, dopo che i dati sono stati recuperati la prima volta, non è
mai necessario che un dataset client li recuperi ulterioriormente, in quanto ha già
tutti i record disponibili.
Per recuperare i record in piccoli blocchi, basta impostare PacketRecords al numero di
record da recuperare. Per esempio, l’istruzione seguente imposta le dimensioni di
ciascun pacchetto dati a dieci record:
ClientDataSet1.PacketRecords := 10;
Questa procedura di recupero dei record a blocchi viene denominato “recupero
incrementale”. I dataset client utilizzano il recupero incrementare quando
PacketRecords è maggiore di zero.
Per recuperare ogni lotto di record, il dataset client chiama GetNextPacket. I pacchetti
appena recuperati vengono aggiunti alla fine dei dati già presenti nel dataset client.
GetNextPacket restituisce il numero di record che recupera. Se il valore restituito è
uguale a quello di PacketRecords, non viene incontrata la fine dei record disponibili.
Se il valore restituito è maggiore di 0 ma minore di PacketRecords, durante
l’operazione di recupero è stato raggiunto l’ultimo record. Se GetNextPacket
restituisce 0, non ci sono più record da recuperare.
Recupero in automatico
Il recupero automatico dei record viene controllato dalla proprietà FetchOnDemand.
Se FetchOnDemand è True (impostazione predefinita), il dataset client recupera
automaticamente i record man mano che occorrono. Per prevenire il recupero
automatico dei record, impostare FetchOnDemanda False. Quando FetchOnDemand è
False, per recuperare i record l’applicazione deve chiamare in modo esplicito
GetNextPacket.
N Non è quasi mai necessario chiamare FetchParams quando il dataset client utilizza un
provider interno e un dataset sorgente perché la proprietà Params rispecchia sempre i
parametri del dataset sorgente interno. Con TClientDataSet, il metodo FetchParams (o
il comando Fetch Params) funziona solo se il dataset client è connesso a un provider
il cui dataset associato è in grado di fornire parametri. Ad esempio, se il dataset
sorgente è dataset di tipo tabella non vi sono parametri da ottenere.
Se il provider è su un sistema separato, come facente parte di un Application server
senza stato, non è possibile utilizzare FetchParams per acquisire i parametri di output.
In un Application Server senza stato, altri client potrebbero modificare o rieseguire la
query o la procedura registrata, modificando pertanto i parametri di output prima
che avvenga la chiamata a FetchParams. Per recuperare i parametri di output da un
N I nomi dei parametri devono coincidere con quelli utilizzati nel dataset sorgente.
N Solo i dataset che utilizzano BDE possono importare i vincoli dal server. Ciò significa
che i vincoli del server sono inclusi nei pacchetti dati solo se si utilizza
TBDEClientDataSet o TClientDataSet con un provider che rappresenta un dataset
basato su BDE. Per ulteriori informazioni su come importare i vincoli del server e su
come impedire a un provider di includerli nei pacchetti dati, vedere “Gestione dei
vincoli del server” a pagina 31-13.
N Per maggiori informazioni sulle operazioni con i vincoli, una volta che sono stati
importati, consultare la sezione “Uso dei vincoli del server” a pagina 25-23.
Anche se l’importazione dei vincoli e delle espressioni del server è una funzionalità
estremamente preziosa che consente a un’applicazione di salvaguardare l’integrità
dei dati, a volte potrebbe essere necessario disattivare temporaneamente i vincoli. Ad
esempio, se un vincolo del server si basa sul valore massimo corrente di un campo,
ma il dataset client utilizza il recupero incrementale, potrebbe accadere che il valore
massimo corrente di quel campo nel dataset client sia diverso dal valore massimo sul
server di database, e i vincoli potrebbero essere richiamati diversamente. Per fare un
altro esempio, nel caso un dataset client applichi ai record un filtro mentre i vincoli
sono abilitati, il filtro potrebbe interferire in modo involontario con le condizioni di
vincolo. In ognuno di questi casi, un’applicazione potrebbe disattivare il controllo dei
vincoli.
Per disattivare temporaneamente i vincoli, chiamare il metodo DisableConstraints.
Ogni volta che si chiama DisableConstraints, viene incrementato un contatore dei
riferimenti. Finché il contatore dei riferimenti è maggiore di zero, i vincoli non
vengono imposti sul dataset client.
Per riattivare i vincoli sul dataset client, chiamare il metodo EnableConstraints del
dataset. Ogni chiamata a EnableConstraints decrementa il contatore dei riferimenti.
Quando il contatore dei riferimenti è zero, i vincoli risaltano nuovamente abilitati.
Refresh, RefreshRecord rinnova solo il record corrente del dataset client. RefreshRecord
modifica il valore del record ottenuto originariamente dal provider, ma lascia le
modifiche nel registro delle modifiche.
Tutte le altre chiamate ai metodi di IAppServer sono abbinate a set analoghi di eventi
BeforeXXX e AfterXXX che consentono di personalizzare la comunicazione tra il
dataset client e il provider.
Inoltre, il dataset client possiede uno speciale metodo, DataRequest, il cui unico scopo
è quello di consentire una comunicazione con il provider, specifica da applicazione
ad applicazione. Quando il dataset client chiama DataRequest, passa come parametro
un OleVariant che contiene una qualsiasi informazione. A sua volta, ciò genera sul
provider un evento OnDataRequest in cui è possibile rispondere in uno dei modi
previsti dall’applicazione e restituire un valore al dataset client.
T Tutti i dataset client sono utilizzabili nelle applicazioni che seguono il modello
briefcase, ma per un’applicazione MyBase pura (un’applicazione che non utilizza un
provider), è preferibile utilizzare TClientDataSet, in quanto implica un minor costo
gestionale.
In un’applicazione MyBase, l’applicazione client non può ottenere le definizioni di
tabella e i dati dal server, e non esiste alcun server a cui può applicare gli
aggiornamenti. Invece, in modo del tutto indipendente, il dataset client deve
• Definire e creare le tabelle
• Caricare i dati salvati
• Fondere le modifiche nei dati
• Salvare i dati
caricano sempre i dati del dataset client dallo stesso file, si può invece utilizzare la
proprietà FileName. Se FileName contiene un file esistente, i dati vengono caricati
automaticamente quando il dataset client viene aperto.
Per caricare i dati da uno stream, si deve chiamare il metodo LoadFromStream del
dataset client. LoadFromStream richiede un solo parametro, un oggetto stream che
fornisce i dati.
I dati caricati tramite LoadFromFile (LoadFromStream) devono essere stati
precedentemente salvati utilizzando un formato dati del dataset client da questo o da
un altro dataset client con il metodo SaveToFile (SaveToStream), opppure generati a
parire da un documento XML. Per ulteriori informazioni sul salvataggio dei dati in
un file o in uno stream, consultare il paragrafo “Salvataggio dei dati in un file o in
uno stream” a pagina 29-37. Per informazioni sulla creazione di dati di dataset client
a partire da un documento XML, vedere il Capitolo 32, “Uso di XML nelle
applicazioni database”.
Quando si chiama LoadFromFile o LoadFromStream, tutti i dati del file vengono letti
nella proprietà Data. Tutte le modifiche che erano presenti nel relativo registro
quando i dati sono stati salvati vengono letti nella proprietà Delta. Tuttavia, gli unici
indici che vengono letti dal file sono quelli che sono stati creati con il dataset.
N È anche possibile fondere le modifiche nei dati di un dataset client diverso se questo
originariamente ha fornito i dati nella proprietà Data. Per ottenere questo risultato,
occorre utilizzare un dataset provider. Per un esempio su come farlo, consultare
“Assegnazione diretta dei dati” a pagina 29-15.
Se non si vogliono utilizzare le funzionalità estese di annullamento del registro delle
modifiche, è possibile impostare la proprietà LogChanges del dataset client a False.
N Se si salva un dataset client mentre ci sono ancora modifiche nel relativo registro,
queste non vengono fuse con i dati. Quando si ricaricano i dati, utilizzando il metodo
LoadFromFile o LoadFromStream, il registro delle modifiche conterrà ancora le
modifiche che non sono state fuse. Ciò è importante per le applicazioni che
sopportano il modello briefcase, nel quale quelle modifiche devono magari essere
applicate a un componente provider nell’application server.
Capitolo
come una Active Library (.DLL) installata con MTS o con COM+. È possibile usare
i moduli dati remoti MTS con DCOM, HTTP, Socket o OLE.
• TSoapDataModule: Questo è un modulo dati che implementa un interfaccia
IAppServer in un’applicazione Web Service. Utilizzare questo tipo di modulo dati
per fornire i dati ai client che accedono ai dati come un Web Service.
W Gli application server contenenti moduli dati transazionali non dovrebbero aprire le
connessioni ai database finché non viene attivato il modulo dati. In fase di
progettazione bisogna accertarsi che tutti i dataset non siano attivi e che il database
non sia collegato prima di eseguire l’applicazione. Nell’applicazione stessa
aggiungere il codice, per aprire le connessioni al database quando il modulo dati
viene attivato, e chiuderlo quando viene disattivato.
Le connessioni web possono trarre vantaggio dalla centralizzazione degli oggetti. Ciò
consente il server di creare un sistema centralizzato limitato di istanze del modulo
dati remoto, disponibili per le richieste dei client. Centralizzando i moduli dati
remoti, il server non utilizza risorse per il modulo dati e per la connessione al
database se non quando sono necessarie. Per maggiori informazioni sulla
centralizzazione di oggetti, consultare la sezione “Centralizzazione di moduli dati
remoti” a pagina 30-8.
A differenza di altri componenti connection, se la connessione viene stabilita via
HTTP non è possibile utilizzare callback.
N Se non si sta creando l’applicazione client sullo stesso sistema del server e non si sta
utilizzando una connessione DCOM o socket, può essere necessario registrare o
installare l’application server sul sistema client. Ciò associa il componente connection
all’application server in fase di progettazione, consentendo così di scegliere i nomi
del server e del provider da un elenco a discesa nell’Object Inspector. (Se si sta
N I moduli dati remoti sono più che dei semplici moduli dati. Il modulo dati SOAP
implementa un’interfaccia richiamabile in un’applicazione Web Service. Gli altri
moduli dati sono oggetti COM Automation.
3 Collocare gli appositi componenti dataset nel modulo dati e impostarli per
accedere al database server.
4 Per ciascun dataset che si vuole esporre nei client, collocare un componente
TDataSetProvider sul modulo dati. Questo provider è necessario per eseguire il
brokering delle richieste dei client e la creazione di pacchetti dati. Impostare la
proprietà DataSet per ogni provider al nome del dataset a cui accedere. È possibile
Configurazione di TRemoteDataModule
Per aggiungere all’applicazione un componente TRemoteDataModule, scegliere File|
New|Other e selezionare dalla pagina Multitier della finestra di dialogo New Items
l’opzione Remote Data Module. Verrà visualizzato Remote Data Module wizard.
Bisogna fornire un nome di classe per il modulo dati remoto. Questo è il nome base
di un discendente di TRemoteDataModule che viene creato dall’applicazione. È anche
il nome base dell’interfaccia per quella classe. Per esempio, se si usa come nome di
classe MyDataServer, il wizard crea una nuova unit che dichiara TMyDataServer, un
discendente di TRemoteDataModule, che implementa IMyDataServer, un discendente
di IAppServer.
N Alla nuova interfaccia si possono aggiungere proprietà e metodi propri. Per ulteriori
informazioni, consultare “Estensione dell’interfaccia dell’application server” a
pagina 30-16.
Se si crea una DLL (Active Library), occorre specificare il modello di threading nel
Remote Data Module wizard. È possibile scegliere Single-threaded, Apartment-
threaded, Free-threaded o Both.
• Se si sceglie Single-threaded, COM assicura che viene soddisfatta solo una
richiesta del client alla volta. Non ci si deve preoccupare delle richieste dei client
che interferiscono tra loro.
• Se si sceglie Apartment-threaded, COM assicura che qualsiasi istanza del modulo
dati remoto soddisferà una richiesta alla volta. Quando si scrive del codice in una
libreria Apartment-threaded, occorre prestare attenzione al rischio di conflitti tra
thread se si usano variabili o oggetti globali non contenuti nel modulo dati remoto.
Questo è il modello consigliato se si stanno utilizzando dataset BDE. (Si noti che,
per gestire tutti gli aspetti relativi al threading sui dataset BDE, sarà necessario un
componente session con la proprietà AutoSessionName impostata a True).
• Se si sceglie Free-threaded, l’applicazione può ricevere richieste simultanee di
client su diversi thread. Bisogna accertarsi che l’applicazione sia thread-safe. Dal
momento che più client possono accedere contemporaneamente al modulo dati
remoto, occorre prestare attenzione ai dati dell’istanza (proprietà , oggetti
contenuti, e così via) e alle variabili globali. Questo modello è consigliabile se si sta
utilizzando un dataset ADO.
• Se si sceglie Both, la libreria funziona esattamente come quando si sceglie
Free-threaded, ma con un’eccezione: tutte le callback (le chiamate alle interfacce
client) vengono serializzate automaticamente.
• Se si sceglie Neutral, il modulo dati remoto può ricevere chiamate simultanee su
thread separati, come nel modello Free-threaded, ma COM garantisce che non vi
saranno mai due thread che accederanno contemporaneamente allo stesso
metodo.
Se si sta creando un EXE, occorre specificare anche che tipo di istanziazione usare. È
possibile scegliere Single instance o Multiple instance (l’istanziazione di tipo Internal
è utilizzabile solo se il codice del client fa parte dello stesso spazio del processo).
N Alla nuova interfaccia si possono aggiungere proprietà e metodi propri. Per ulteriori
informazioni, consultare “Estensione dell’interfaccia dell’application server” a
pagina 30-16.
Occorre specificare il modello di threading nel wizardTransactional Data Module.
Scegliere tra Single, Apartment o Both.
• Se si sceglie Single, le richieste dei client vengono serializzate in modo che
l’applicazione ne soddisfi una alla volta. Non ci si deve preoccupare delle richieste
dei client che interferiscono tra loro.
• Se si sceglie Apartment, il sistema assicura che qualsiasi istanza del modulo dati
remoto soddisfi una richiesta alla volta e che le chiamate usino sempre lo stesso
thread. Occorre prestare attenzione al rischio di conflitti tra thread se si usano
variabili o oggetti globali non contenuti nel modulo dati remoto. Anziché usare
variabili globali, si può ricorrere allo Shared Property manager. Per maggiori
informazioni sullo Shared Property manager, consultare il paragrafo “Shared
property manager” a pagina 46-6.
• Se si sceglie Both, MTS chiama l’interfaccia del modulo dati remoto esattamente
come quando si sceglie Apartment. Tuttavia, tutte le callback dirette alle
applicazioni client vengono serializzate, cosicché non ci si deve preoccupare di
quelle che interferiscono l’una con l’altra.
N Il modello Apartment sotto MTS o COM+ è diverso dal modello corrispondente sotto
DCOM.
Bisogna anche specificare gli attributi di transazione del modulo dati remoto. È
possibile scegliere una delle seguenti opzioni:
• Requires a transaction. Quando si seleziona questa opzione, ogni volta che un
client usa l’interfaccia del modulo dati remoto, quella chiamata viene eseguita nel
Configurazione di TSoapDataModule
Per aggiungere all’applicazione un componente TSoapDataModule, scegliere File|
New|Other e selezionare dalla pagina WebServices della finestra di dialogo New
Items l’opzione SOAP Server Data Module. Viene visualizzato il wizard SOAP data
module.
Bisogna fornire un nome di classe per il modulo dati SOAP. Questo è il nome di base
di un discendente di TSoapDataModule che viene creato dall’applicazione. È anche il
nome base dell’interfaccia per quella classe. Per esempio, se si specifica il nome di
classe MyDataServer, il wizard crea una nuova unit che dichiara TMyDataServer, un
discendente di TSoapDataModule, che implementa IMyDataServer, un discendente di
IAppServerSOAP.
• Scegliere il comando Add to Interface dal menu Edit nell’ IDE. Indicare se si
intende aggiungere una procedura, una funzione o una proprietà , ed immetterne
la sintassi. Non appena si fa clic su OK, verrà aperto il Code editor e il cursore sarà
posizionato nell’implementazione del nuovo membro dell’interfaccia.
• Usare il Type Library editor. Selezionare l’interfaccia per l’application server nel
Type Library editor, e fare clic negli strumenti sul pulsante relativo al tipo di
membro dell’interfaccia (metodo o proprietà ) che si vuole aggiungere. Nella
pagina Attributes, assegnare al membro dell’interfaccia un nome, nella pagina
Parameters specificare i parametri e il tipo, e quindi fare l’aggiornamento della
libreria di tipi. Per ulteriori informazioni sull’utilizzo del Type Library editor,
consultare il Capitolo 41, “Operazioni con le librerie di tipi”.
N È necessario salvare esplicitamente il file .TLB scegliendo Refresh nel Type Library
editor e salvando poi le modifiche dall’IDE.
Una volta effettuate le aggiunte all’interfaccia del modulo dati remoto, si devono
individuare le proprietà e i metodi che sono stati aggiunti all’implementazione del
modulo dati remoto. Quindi, si deve aggiungere il codice per portare a termine
questa implementazione completando i corpi dei nuovi metodi.
Se non si sta scrivendo un modulo dati SOAP, le applicazioni client chiamano le
estensioni dell’interfaccia usando la proprietà AppServer del loro componente
connection. Con i moduli dati SOAP, essi chiamano il compontente connection del
metodo GetSOAPServer. Per ulteriori informazioni su come eseguire questa
operazione, consultare la sezione “Chiamata delle interfacce del server” a
pagina 30-29.
W Quando si utilizza BDE, l’invio in due fasi viene implementato completamente solo
sui database Oracle7 e MS-SQL. Se la transazione riguarda più database, alcuni dei
quali sono server remoti diversi da Oracle7 o MS-SQL, la transazione corre il rischio
di una riuscita solo parziale. All’interno di un qualsiasi database, tuttavia, ci sarà
sempre un supporto transazionale.
Per impostazione predefinita, tutte le chiamate di IAppServer a un modulo dati
transazionale sono transazionali. È necessario solamente impostare l’attributo della
transazione del modulo dati per indicare che deve partecipare alle transazioni.
Inoltre, è possibile estendere l’interfaccia dell’application server in modo da
includere le chiamate ai metodi che incapsulano le transazioni definite dal
programmatore
Se l’attributo della transazione indica che il modulo dati remoto necessita di una
transazione, ogni volta che un client chiama un metodo della propria interfaccia,
viene inglobato automaticamente in una transazione. Tutte le chiamate del client
N Non si devono abbinare le transazioni COM+ (oMTS) alle transazioni esplicite create
da un componente di connessione al database o mediante un comando SQL esplicito.
Quando il modulo dati transazionale viene elencato in una transazione, elenca
automaticamente anche tutte le chiamate al database contenute nella transazione.
Per ulteriori informazioni sull’uso delle transazioni COM+ (o MTS), consultare
il“Supporto delle transazioni MTS e COM+” a pagina 46-10.
client. Questa qualità di essere senza stato risulta utile se si vogliono centralizzare le
connessioni al database in un modulo dati transazionale, in quanto l’application
server non ha la necessità di riconoscere distintamente le informazioni persistenti,
come, ad esempio, il record corrente, tra una connessioni al database e la successiva.
Analogamente, questa qualità di essere senza stato diventa importante quando si
condividono istanze di moduli dati remoti tra diversi client, come accade con
l’attivazione just-in-time o con la centralizzazione degli oggetti. I moduli dati SOAP
devono essere senza stato.
A volte, tuttavia, potrebbe essere necessario conservare le informazioni di stato tra
una chiamata all’application server e l’altra. Per esempio, quando si richiedono dati
utilizzando il recupero incrementale, il provider sull’application server deve
“ricordare“ le informazioni delle chiamate precedenti (qual è il record corrente).
Prima e dopo ogni chiamata all’interfaccia IAppServereffettuata dal dataset client
(AS_ApplyUpdates, AS_Execute, AS_GetParams, AS_GetRecordso AS_RowRequest),
l’application server riceve un evento in cui può trasmettere o recuperare
informazioni di stato personalizzate. Analogamente, i provider, prima e dopo ogni
risposta a queste chiamate generate dal client, ricevono eventi in cui possono reperire
o trasmettere informazioni di stato personalizzate. Utilizzando questo meccanismo, è
possibile comunicare informazioni di stato persistenti tra le applicazioni client e
l’application server, anche se l’application server è senza stato.
Ad esempio, si consideri un dataset che rappresenta la seguente query
parametrizzata:
SELECT * from CUSTOMER WHERE CUST_NO > :MinVal ORDER BY CUST_NO
Per consentire il prelievo incrementale in un application server senza stato si può fare
quanto segue:
• Quando il provider assembla un set di record in un pacchetto dati, annota il valore
di CUST_NO sull’ultimo record nel pacchetto:
TRemoteDataModule1.DataSetProvider1GetData(Sender: TObject; DataSet: TCustomClientDataSet);
begin
DataSet.Last; { move to the last record }
with Sender as TDataSetProvider do
Tag := DataSet.FieldValues['CUST_NO']; {save the value of CUST_NO }
end;
• Il provider invia questo ultimo valore CUST_NO al client dopo avere mandato il
pacchetto dati:
TRemoteDataModule1.DataSetProvider1AfterGetRecords(Sender: TObject;
var OwnerData: OleVariant);
begin
with Sender as TDataSetProvider do
OwnerData := Tag; {send the last value of CUST_NO }
end;
• Sul client, il dataset client salva questo ultimo valore di CUST_NO:
TDataModule1.ClientDataSet1AfterGetRecords(Sender: TObject; var OwnerData: OleVariant);
begin
with Sender as TClientDataSet do
ChildRDMFactory :=
TComponentFactory.Create(ComServer, TChildRDM, Class_ChildRDM,
ciInternal, tmApartment);
Result := ChildRDMFactory.CreateCOMObject(nil) as IChildRDM;
Result.MainRDM := Self;
end;
Per ulteriori informazioni sull’estensione dell’interfaccia del modulo dati remoto
genitore, consultare “Estensione dell’interfaccia dell’application server” a
pagina 30-16.
T Potrebbe anche esere necessario ampliare l’interfaccia di ogni modulo dati figlio,
esponendo l’interfaccia del modulo dati genitore o le interfacce degli altri moduli dati
figlio. Ciò permette ai diversi moduli dati nell’application server di comunicare l’uno
l’altro più liberamente.
Una volta aggiunte al modulo dati remoto principale le proprietà che rappresentano i
moduli dati remoti figlio, le applicazioni client devono più stabilire connessioni
separate con ogni modulo dati remoto sull’application server. Esse condividono
invece una singola connessione al modulo dati remoto genitore, il quale al sua volta
indirizza messaggi ai moduli dati ”figlio”. Poiché ogni applicazione client utilizza la
stessa connessione per ogni modulo dati remoto, i moduli dati remoti possono
condividere una singola connessione database, risparmiando risorse. Per
informazioni sulle modalità di condivisione di una singola connessione da parte
delle applicazioni figlio, vedere “Connessione a un application server che utilizza più
moduli dati” a pagina 30-31.
elemento del registro di sistema per l’application server sul client, e il server risiede
su una macchina diversa dal client, bisogna indicare ComputerName.
N Anche quando c’è un elemento nel registro di sistema per l’application server, si può
specificare ComputerName per ridefinirlo. Ciò può essere particolarmente utile
durante lo sviluppo, la verifica e il debug..
Se ci sono più server da cui l’applicazione client può scegliere, è possibile usare la
proprietà ObjectBroker anziché specificare un valore per ComputerName. Per maggiori
informazioni, consultare la sezione “Brokering delle connessioni” a pagina 30-27.
Se si fornisce il nome di un computer host o di un server inesistente, quando si cerca
di aprire la connessione, il componente connection DCOM solleva un’eccezione.
Connessione al server
Per individuare e collegarsi all’application server, prima è necessario impostare le
proprietà del componente connection per identificare l’application server. Questo
processo è descritto nella sezione “Connessione all’application server” a
pagina 30-24. Prima di aprire la connessione, tutti i dataset client che usano il
componente connection per comunicare con l’ application server dovranno indicare
questo fatto impostando la loro proprietà RemoteServer per specificare il componente
connection.
La connessione viene aperta automaticamente quando i dataset client tentano di
accedere all’ application server. Per esempio, l’impostazione della proprietà Active
del dataset client a True apre la connessione, sempre che la proprietà RemoteServer sia
stata impostata.
Se non si collegano i dataset client al componente connection, è possibile aprire la
connessione impostando la proprietà Connected del componente connection a True.
Prima di stabilire una connessione a un application server, il componente connection
genera un evento BeforeConnect. È possibile eseguire delle azione specifiche per
collegare un gestore BeforeConnect tramite programma. Dopo aver stabilito la
connessione, il componente connection genera un evento AfterConnect per tutte le
azioni speciali.
N Per usare la dispinterface, occorre aggiungere la unit _TLB, generata quando si salva
la libreria di tipi, alla clausola uses del modulo client.
Web-based
Client
Application Application
Server
Remote Database
possibile usare un server già pronto come Personal Web server di Microsoft o
scriverne uno proprio usando i componenti socket descritti nel Capitolo 39,
“Operazioni con i socket”.
2 Creare l’applicazione client seguendo le operazioni descritte nel paragrafo
“Creazione dell’applicazione client” a pagina 30-23, iniziando, però, con la
selezione del comando File|New|Active X|Active Form, invece di iniziare il
progetto del client come un normale progetto.
3 Se l’applicazione client usa un modulo dati, aggiungere una chiamata per crearlo
esplicitamente nell’inizializzazione della scheda attiva.
4 Quando l’applicazione client ha terminato, compilare il progetto e selezionare
Project|Web Deployment Options. Nella finestra di dialogo Web Deployment
Options, occorre eseguire le seguenti operazioni:
a Nella pagina Project specificare la directory di destinazione, l’URL per la
directory di destinazione e la directory HTML. Normalmente, la directory di
destinazione e la directory HTML coincideranno con quella dei progetti per il
server Web. L’URL di destinazione è solitamente il nome della macchina server.
b Nella pagina Additional Files includere midas.dll con l’applicazione client.
5 Infine, selezionare Project|WebDeploy per distribuire l’applicazione client come
una scheda Active.
Qualsiasi browser Web che può eseguire schede Active può eseguire l’applicazione
client specificando il file .HTM che è stato creato quando è stata distribuita
l’applicazione client. Questo file .HTM ha lo stesso nome del progetto
dell’applicazione client, e appare nella directory specificata come directory di
destinazione.
T È possibile creare applicazioni InternetExpress per fornire ai Web browsers dati "dal
vivo"anche se non si possiede un application server. È sufficiente aggiungere al
modulo web il provider e il dataset associato.
N Poiché l’application server viene eseguito in questo account guest, non può essere
disattivato dagli altri account.
Per accordare all’applicazione Web i permessi di accesso e di avvio, eseguire
DCOMCnfg.exe, ubicato nella directory System32 della macchina che esegue
l’application server. Le istruzioni seguenti descrivono come configurare l’application
server:
1 Quando si esegue DCOMCnfg, selezionare l’application server nell’elenco delle
applicazioni sulla pagina Applications.
2 Fare clic sul pulsante Properties. Non appena la finestra di dialogo cambia,
selezionare la pagina Security.
3 Selezionare Use Custom Access Permissions, e premere il pulsante Edit.
Aggiungere il nome IUSR_computername all’elenco degli account con permesso
di accesso, dove computername è il nome della macchina che esegue
l’applicazione Web.
4 Selezionare Use Custom Launch Permissions, e premere il pulsante Edit.
Aggiungere IUSR_computername anche a questo elenco.
5 Fare clic sul pulsante Apply.
N Anche quando si utilizza SOAP, nel caso in cui l’application server supporti
IAppServerSOAP, il broker XML utilizza IAppServer poiché il componente
connessione agisce come un adapter tra le due interfacce.
Per fare in modo che il produttore XML possa utilizzare l’interfaccia IAppServer
dell’application server, si devono impostare le seguenti proprietà:
• Impostare la proprietà RemoteServer al componente connessione che istituisce la
connessione con l’application server e ottiene la sua interfaccia IAppServer. In fase
di progettazione, si può selezionare questo valore da un elenco a discesa
nell’Object Inspector.
• Impostare la proprietà ProviderName al nome del componente provider
sull’application server che rappresenta il dataset da cui si vogliono i pacchetti dati
XML. Questo provider provvede a fornire i pacchetti dati XML e ad applicare gli
aggiornamenti dai pacchetti delta XML. In fase di progettazione, se la proprietà
RemoteServer è impostata e il componente connessione ha una connessione attiva,
l’Object Inspector visualizza un elenco di provider disponibili. (Se si sta
utilizzando una connessione DCOM l’application server deve essere registrato
anche sulla macchina client).
Due proprietà consentono di indicare ciò che si desidera includere nei pacchetti dati:
• È possibile limitare il numero di record che vengono aggiunti al pacchetto dati
impostando la proprietà MaxRecords. Ciò risulta particolarmente importante per
important dataset estesi in quanto le applicazioni InternetExpress inviano l’intero
pacchetto dati ai browser client. Se il pacchetto dati è troppo grande, il tempo
necessario per scaricare i dati potrebbe diventare proibitivamente lungo.
• Se il provider sull’application server rappresenta una query o una procedura
registrata, si potrebbero fornire valori di parametro prima di ottenere un pacchetto
dati XML. Questi valori di parametro possono essere forniti mediante la proprietà
Params.
I componenti che generano HTML e javascript per l’applicazione di InternetExpress,
una volta impostata la loro proprietà XMLBroker, usano automaticamente il
pacchetto dati XML del broker XML. Per ottenere direttamente il pacchetto dati XML
nel codice, utilizzare il metodo RequestRecords.
non è necessario creare un elemento di azione per il broker XML per far sì che sia in
grado di rispondere ai messaggi di aggiornamento provenienti da un browser Web.
Questi messaggi contengono pacchetti delta XML che dovrebbero essere applicati
all’application server. Tipicamente, sono generati da un pulsante appositamente
creato in una delle pagine HTML prodotte dall’applicazione client Web.
Affinché il dispatcher sia in grado di riconoscere i messaggi per il broker XML, è
necessario descriverli utilizzando la proprietà WebDispatch. Impostare la proprietà
PathInfo alla sezione "percorso" dell’URL a cui vengono trasmessi i messaggi per il
broker XML. Impostare MethodType al valore dell’header del metodo dei messaggi di
aggiornamento indirizzati a quell’URL (di solito mtPost). Se si vuole rispondere a
tutti i messaggi aventi il percorso specificato, impostare MethodType a mtAny. Se non
si vuole che il broker XML risponda direttamente ai messaggi di aggiornamento (per
esempio, nel caso li si voglia gestire esplicitamente utilizzando un elemento di
azione), impostare la proprietà Enabled a False. Per maggiori informazioni sul modo
in cui il dispatcher Web determina quel è il componente che gestisce i messaggi
provenienti dal browser Web, consultare la sezione “Dispatch dei messaggi di
richiesta” a pagina 34-5.
Quando il dispatcher passa un messaggio di aggiornamento al broker XML, passa gli
aggiornamenti all’application server e, se si verificano errori di aggiornamento,
riceve un pacchetto delta XML che descrive tutti gli errori di aggiornamento. Infine,
ritrasmette al browser un messaggio di risposta che può sia indirizzare di nuovo il
browser alla stessa pagina che aveva generato il pacchetto delta XML, sia
trasmettergli nuovi contenuti.
Esistono diversi eventi che consentono di inserire elaborazione personalizzate in
tutte queste fasi del processo di aggiornamento:
1 Quando il dispatcher passa per la prima volta il messaggio di aggiornamento al
broker XML, riceve un evento BeforeDispatch, in cui è possibile preelaborare la
richiesta o anche gestirla completamente. Questo evento consente al broker XML
di gestire messaggi diversi da quelli di aggiornamento.
2 Se il gestore di evento BeforeDispatch non gestisce il messaggio, il broker XML
riceve un evento OnRequestUpdate, in cui è possibile applicare gli aggiornamenti
personalmente invece di utilizzare l’elaborazione predefinita.
3 Se il gestore di evento OnRequestUpdate non gestisce la richiesta, il broker XML
applica gli aggiornamenti e riceve un pacchetto delta che contiene tutti gli errori di
aggiornamento.
4 Se non si verificano errori di aggiornamento, il broker XML riceve un evento
OnGetResponse, in cui è possibile creare un messaggio di risposta che indica che gli
aggiornamenti sono stati applicati con successo oppure trasmettere al browser i
dati aggiornati. Se il gestore di evento OnGetResponse non completa la risposta
(non imposta il parametro Handled a True), il broker XML trasmette una risposta
che dirige di nuovo il browser al documento che aveva generato il pacchetto delta.
5 Se si verificano errori di aggiornamento, il broker XML riceve invece un evento
OnGetErrorResponse. È possibile utilizzare questo evento per tentare di risolvere gli
errori di aggiornamento oppure per generare una pagina Web che li descriva
all’utente. Se il gestore di evento OnGetErrorResponse non completa la risposta
(non imposta il parametro di dled a True), il broker XML chiama uno speciale
produttore di contenuti, di nome ReconcileProducer, per generare il contenuto del
messaggio di risposta.
6 Infine, il broker XML riceve un evento AfterDispatch, in cui è possibile compiere
eventuali operazioni finali prima di ritrasmettere una risposta al browser Web.
N Per utilizzare il Web page editor, è necessario installare Internet Explorer 4 o una
versione successiva.
La zona superiore del Web page editor visualizza gli elementi Web che generano il
documento HTML. Questi elementi Web sono annidati, e in particolare ogni tipo di
elemento Web assembla il codice HTML generato dai propri sottoelementi. Tipi
diversi di elementi possono contenere sottoelementi differenti. Sulla sinistra, una
struttura ad albero visualizza tutti degli elementi Web, indicando come sono
annidati. Sulla destra, si possono vedere gli elementi Web inclusi dall’elemento al
momento selezionato. Se si seleziona un componente nella parte superiore del Web
page editor, è possibile impostarne le proprietà utilizzando l’Object Inspector.
Fare clic sul pulsante New Item per aggiungere un sottoelemento all’elemento
attualmente selezionato. La finestra di dialogo Add Web Component elenca solo
quegli elementi che possono essere aggiunti all’elemento attualmente selezionato.
Il produttore di pagine InternetExpress può contenere un solo tipo di elemento, dei
due possibili, ognuno dei quali genera una scheda HTML:
• TDataForm, che genera una scheda HTML per visualizzare dati e i controlli che
trattano tali dati o che trasmettono gli aggiornamenti.
Gli elementi che si aggiungono a TDataForm visualizzano i dati in una griglia
multi-record (TDataGrid) o in una serie di controlli, ognuno dei quali rappresenta
un singolo campo di un singolo record (TFieldGroup). Inoltre, è possibile
aggiungere una serie di pulsanti per spostarsi tra i dati o per trasmette gli
aggiornamenti, (TDataNavigator), o un pulsante per applicare gli aggiornamenti al
client Web (TApplyUpdatesButton). Ognuno di questi elementi contiene dei
sottoelementi per rappresentare singoli campi o pulsanti. Infine, come con la
maggior parte degli elementi Web, è possibile aggiungere una griglia di layout,
(TLayoutGroup), che permette di personalizzare il layout di tutti gli elementi in
essa contenuti.
• TQueryForm, che genera una scheda HTML per visualizzare o leggere i valori
definiti dall’applicazione. Per esempio, si può utilizzare questa scheda per
visualizzare e trasmettere i valori dei parametri.
Gli elementi che si aggiungono a TQueryForm visualizzano i valori definiti
dall’applicazione (TQueryFieldGroup) o una serie di pulsanti per trasmettere o
azzerare quei valori (TQueryButtons). Ognuno di questi elementi contiene dei
sottoelementi per rappresentare singoli valori o pulsanti. Anche ad una scheda di
interrogazione, è possibile aggiungere una griglia di layout, esattamente come per
le schede per dati.
La parte inferiore del Web page editor visualizza il codice HTML generato e permette
di vederne l’aspetto finale come in un browser (Internet Explorer).
l’elemento Web col broker XML che gestisce il pacchetto dati. Usando la proprietà
XMLDataSetField si può anche specificare un dataset, che è contenuto in un campo
del dataset di quel pacchetto dati. Se l’elemento Web rappresenta un certo campo o
un valore di parametro, l’elemento Web ha una proprietà FieldName o ParamName.
È possibile applicare un attributo di stile a qualsiasi elemento Web, influenzando in
questo modo l’aspetto complessivo di tutto l’ HTML generato. Stili e fogli di stile
fanno parte dello standard HTML 4. Essi consentono a un documento HTML 4 di
definire una serie di attributi di visualizzazione che vengono applicati a un
marcatore e a tutto ciò che è incluso nel suo campo d’azione. Gli elementi Web ne
consentono un uso molto flessibile:
• Il modo più semplice per utilizzare gli stili è quello di definire direttamente un
attributo di stile sull’elemento Web. A questo scopo, si utilizza la proprietà Style. Il
valore di Style è semplicemente la porzione di definizione dell’attributo di una
definizione standard di stile HTML, come, ad esempio
color: red.
• È possibile anche definire un foglio di stile, che definisce una serie di definizioni di
stile. Ogni definizione include sia un selettore di stile (il nome di un marcatore a
cui viene sempre applicato lo stile oppure un nome di stile definito dall’utente) sia
la definizione dell’attributo racchiusa tra parentesi graffe:
H2 B {color: red}
.MyStyle {font-family: arial; font-weight: bold; font-size: 18px }
L’intero set di definizioni è conservata dal produttore di pagine InternetExpress
nella sua proprietà Styles. Ogni elemento Web può referenziare quindi gli stili con
nomi definiti dall’utente impostando la sua proprietà StyleRule.
• Se si sta condividendo un foglio di stile con altre applicazioni, è possibile fornire le
definizioni di stile come valore della proprietà StylesFile del produttore di pagine
InternetExpress invece che della proprietà Style. I singoli elementi Web faranno
riferimento agli stili utilizzando sempre la proprietà StyleRule.
Un’altra proprietà comune degli elementi Web è la proprietà Custom. Custom include
una serie di opzioni che è possibile aggiungere al marcatore HTML generato. HTML
definisce una diversa serie di opzioni per ogni tipo di marcatore. Il manuale Visual
Component Library Reference riporta per la proprietà Custom di vari elementi Web
un esempio delle possibili opzioni. Per maggiori informazioni sulle possibili opzioni,
utilizzare un manuale di riferimento alla sintassi HTML.
</HTML>
I marcatori trasparenti per HTML inclusi nel modello predefinito vengono tradotti
nel seguente modo:
<#INCLUDES> genera le istruzioni che includono le librerie javascript. Queste istruzioni
assumono il seguente aspetto:
<SCRIPT language=Javascript type="text/javascript" SRC="IncludePathURL/xmldom.js"> </SCRIPT>
<SCRIPT language=Javascript type="text/javascript" SRC="IncludePathURL/xmldb.js"> </SCRIPT>
<SCRIPT language=Javascript type="text/javascript" SRC="IncludePathURL/xmlbind.js"> </
SCRIPT>
<#STYLES> genera le istruzioni che definiscono un foglio di stile a partire dalle
definizioni elencate nella proprietà Style o nella proprietà StylesFile del produttore di
pagine InternetExpress.
<#WARNINGS> non genera nulla in fase di esecuzione. In fase di progettazione, aggiunge
messaggi di avvertimento per problemi rilevati durante la generazione del
documento HTML. È possibile visualizzare questi messaggi nel Web page editor.
<#FORMS> genera il codice HTML prodotto dai componenti aggiunti nel Web page
editor. Il codice HTML prodotto da ogni componente è generato in base alla
posizione che occupa nella sequenza di WebPageItems.
<#SCRIPT> genera un blocco di dichiarazioni javascript che sono utilizzate nel codice
HTML generato dai componenti aggiunti nel Web page editor.
È possibile sostituire il modello predefinito modificando il valore di HTMLDoc
oppure impostando la proprietà HTMLFile. Il modello HTML personalizzato può
includere tutti i marcatori trasparenti per HTML che costituiscono il modello
predefinito. Il produttore di pagine InternetExpress tradurrà automaticamente questi
marcatori nel momento in cui si chiama il metodo Content. Inoltre, il produttore di
pagine InternetExpress è in grado di tradurre automaticamente altri tre marcatori:
<#BODYELEMENTS> viene sostituito dallo stesso codice HTML prodotto dai 5 marcatori
inclusi nel modello predefinito. Risulta utile quando si genera un modello in un
editor HTML e si desidera utilizzare il layout predefinito aggiungendo però altri
elementi con l’editor.
<#COMPONENT Name=WebComponentName> viene sostituito dal codice HTML generato dal
componente con nome WebComponentName. Questo componente può essere uno dei
componenti aggiunti nel Web page editor, o un qualsiasi altro componente purché
supporti l’interfaccia IWebContent e abbia lo stesso Owner del produttore di pagine
InternetExpress.
<#DATAPACKET XMLBroker=BrokerName> viene sostituito col pacchetto dati XML ottenuto
dal broker XML specificato con BrokerName. Quando si osserva nel Web page editor il
codice HTML generato dal produttore di pagine InternetExpress, si vedrà questo
marcatore invece dell’effettivo pacchetto dati XML.
Inoltre, il modello personalizzato può includere qualsiasi altro marcatore trasparente
per HTML definito dall’utente. Quando il produttore di pagine InternetExpress
incontra un marcatore che non appartiene a nessuno dei sette tipi che è in grado di
tradurre automaticamente, genera un evento OnHTMLTag in cui si potrà inserire del
codice che esegua traduzioni ad hoc. Per maggiori informazioni sui modelli HTML,
consultare la sezione “Modelli HTML” a pagina 34-14.
T I componenti che appaiono nel Web page editor generano codice statico. ciò significa
che, a meno che l’application server modifichi i metadati inclusi nei pacchetti dati, il
codice HTML è sempre lo stesso, indipendentemente da quando viene generato. È
possibile evitare il sovraccarico di lavoro derivante dalla generazione dinamica in
fase di esecuzione di questo codice, in risposta ad ogni messaggio di richiesta, se si
copia il codice HTML generato nel Web page editor e lo si utilizza come modello.
Poiché il Web page editor visualizza un marcatore <#DATAPACKET> invece dell’effettivo
XML, l’utilizzo di questo codice come modello continua a consentire all’applicazione
di recuperare dinamicamente i pacchetti dati dall’application server.
Capitolo
N Queste tecniche per il controllo del contenuto di pacchetti dati sono disponibili solo
per i provider di dataset. Quando si utilizza TXMLTransformProvider, è possibile
controllare il contenuto dei pacchetti dati solo controllando il file di trasformazione
utilizzato dal provider.
Gli errori di aggiornamento possono essere elaborati dal provider di dataset o dal
dataset client. Se il provider fa parte di un’applicazione multi-tier dovrebbe gestire
tutti gli errori di aggiornamento che non richiedono un’interazione con l’utente per la
loro risoluzione. Se il provider non riesce a risolvere una condizione di errore,
memorizza temporaneamente una copia del record che ha problemi. Completata
l’elaborazione del record il provider restituisce al dataset client il numero di errori
incontrati e copia i record non risolti in un pacchetto risultato che viene restituito al
dataset client per un’ulteriore riconciliazione.
I gestori di evento di tutti gli eventi dei provider passano il set di aggiornamenti
come un dataset client. Se il gestore di evento si occupa solo di alcuni tipi di
aggiornamenti, è possibile filtrare il dataset in base allo stato di aggiornamento dei
record. Filtrando i record, il gestore di evento non deve riordinare i record che non
utilizzerà. Per filtrare il dataset client in base allo stato di aggiornamento dei suoi
record, impostare la sua proprietà StatusFilter.
N Le applicazioni devono fornire un supporto più efficace nel caso in cui gli
aggiornamenti siano indirizzati su un dataset che non rappresenta una singola
tabella. Per i dettagli sulle operazioni da compiere, consultare la sezione
“Applicazione di aggiornamenti a dataset che non rappresentano una singole
tabella” a pagina 31-12.
certo campo, si deve usare la proprietà ProviderFlags. ProviderFlags è un set che può
includere uno dei valori elencati nella Tabella 31.5
(che non può essere aggiornata automaticamente) un meccanismo per applicare gli
aggiornamenti, consentendo al provider di saltare qualsiasi elaborazione automatica
dal momento che il record viene aggiornato dall’interno del gestore di evento.
• FOREIGN KEY, per designare una o più colonne di una tabella che fanno
riferimento a un’altra tabella.
N Questo elenco non è esclusivo. Il server di database può supportare alcuni o tutti
questi vincoli, in parte o completamente, nonché ulteriori vincoli. Per ulteriori
informazioni sui vincoli supportati, consultare la documentazione del server.
I vincoli del database server duplicano ovviamente molti tipi di controlli sui dati
normalmente gestiti dalle tradizionali applicazioni database desktop. Nelle
applicazioni database multi-tier è possibile sfruttare i vantaggi dei vincoli del server
senza doverli duplicare nel codice dell’application server o dell’applicazione client.
Se il provider opera con un dataset BDE, la proprietà Constraints consente di replicare
e applicare i vincoli del server ai dati passati e ricevuti dai dataset client. Se
Constraints è True (impostazione predefinita), i vincoli del server menìmorizzati nel
dataset sorgente vengono inclusi nei pacchetti dati e hanno effetto sui tentativi del
client di aggiornare i dati.
N Prima che il provider server possa trasferire ai dataset client le informazioni sui
vincoli, deve recuperare i vincoli dal server di database. Per ottenere dal server i
vincoli sul database, utilizzare SQL Explorer per importare nel Data Dictionary i
vincoli del server di database e le espressioni predefinite. I vincoli e le espressioni
predefinite inclusi nel Data Dictionary sono resi automaticamente disponibili ai
dataset BDE.
A volte si potrebbe non voler applicare i vincoli del server ai dati inviati a un dataset
client. Per esempio, un dataset client che riceve dati in pacchetti e consente
l’aggiornamento in locale dei record prima di prelevare altri record, potrebbe aver
bisogno di disattivare alcuni vincoli del server che potrebbero essere attivati per la
presenza di un set di dati momentaneamente incompleto. Per impedire la replica dei
vincoli dal provider al dataset client, impostare Constraints a False. Si noti, inoltre, che
i dataset client possono disattivare e attivare i vincoli usando i metodi
DisableConstraints e EnableConstraints. Per ulteriori informazioni sull’attivazione e
sulla disattivazione dei vincoli da parte del dataset client, consultare “Gestione dei
vincoli dal server” a pagina 29-31.
Capitolo
Un modo naturale per una mappatura tra il documento e un dataset è quello di far
corrispondere un unico record a ciascun messaggio di posta elettronica. Il record
conterrà i campi del nome e dell’indirizzo del mittente. Siccome i destinatari del
messaggio potrebbero essere più di uno, il destinatario (<to>) dovrebbe essere
mappato a un dataset annidato. Analogamente, la lista cc dovrebbe essere mappata a
un dataset annidato. La riga <subject> potrebbe essere mappata a un campo stringa,
mentre probabilmente il messaggio stesso (<content>) potrebbe essere un campo
memo. I nomi dei file allegati potrebbero essere mappati a un dataset annidato
perché un messaggio può avere numerosi allegati. Pertanto, il messaggio precedente
potrebbe essere mappato a un dataset simile al seguente:
Nome Indirizzo
Joe Engineer jengineer@MyCo.Com
Nome Indirizzo
Robin Smith rsmith@MyCo.Com
Leonard Devon ldevon@MyCo.Com
Attachfile
XMLSpec.txt
Schedule.txt
Definire questa mappatura significa identificare i nodi del documento XML che
possono essere ripetuti e farli corrispondere con dataset annidati. Gli elementi
provvisti di tag e che hanno un valore vengono visualizzati solo una volta (come
<content>...</content>) corrispondono a campi il cui tipo di dato riflette il tipo di
dati che può venire visualizzato come valore. Gli attributi di un tag (come l’attributo
AttachFile del tag degli allegati) sono in grado di mapparsi anche con dei campi.
Va notato che non tutti i tag nel documento XML appaiono nel dataset
corrispondente. Ad esempio, all’elemento <head>...<head/> non corrisponde alcun
elemento nel dataset risultante. Di solito, solo elementi che hanno valori, elementi
che possono essere ripetuti o gli attributi di un tag corrispondono a campi (compresi
i campi di dataset annidati) di un dataset. L’eccezione a questa regola si ha quando
un nodo genitore del documento XML corrisponde a un campo il cui valore è dato
dai valori dei nodi figlio. Ad esempio, un documento XML potrebbe contenere un
insieme di tag come
<FullName>
<Title> Mr. </Title>
<FirstName> John </FirstName>
<LastName> Smith </LastName>
</FullName>
che potrebbe corrispondere a un singolo campo dataset con il valore
Mr. John Smith
Utilizzo di XMLMapper
Il programma di utilità di mappatura XML, xmlmapper.exe, permette di definire le
mappature in tre modi:
• Da uno schema XML (o documento) esistente a un dataset client che si definisce.
Serve per creare un’applicazione di database che funzioni con dati di cui già si ha
uno schema XML.
• Da un pacchetto dati esistente a un nuovo schema XML da definire. È utile quando
si desidera esporre informazioni di database esistenti in XML, ad esempio per
creare un nuovo sistema di comunicazione business-to-business.
• Tra uno schema XML esistente e un pacchetto dati esistente. È utile quando si
desidera fare funzionare insieme uno schema XML e un database che descrivono
le stesse informazioni.
Una volta definita la mappatura, è possibile generare i file di trasformazione che
servono a convertire i documenti XML in pacchetti dati e, inversamente, a convertire
i pacchetti dati in documenti XML. Notare che solo il file di trasformazione è
direzionale: una singola mappatura serve per generare sia la trasformazione da XML
a pacchetto dati, sia quella da pacchetto dati a XML.
N XML mapper si appoggia a due file .DLL (midas.dll e msxml.dll) per funzionare
correttamente. Accertarsi che ambedue i file siano stati installati prima di usare
xmlmapper.exe. Inoltre, msxml.dll deve essere registrato come COM server. Per
registrarlo si utilizza Regsvr32.exe.
È possibile caricare solo un documento o uno schema XML, solo un pacchetto dati,
oppure caricarli entrambi. Se si carica solo un lato della mappatura, XML mapper
può generare una mappatura naturale dell’altro lato.
Una volta che si è caricato o generato sia il documento XML che il pacchetto dati e
che si sono selezionati i nodi visualizzati nella mappatura, la tabella all’inizio della
pagina Mapping riflette la mappatura che si è definita.
III
Creazione di applicazioni Internet
Part III
un’applicazione Web browser, che visualizza le pagine in una forma appropriata per
il particolare sistema dell’utente nel suo stato attuale.
Il primo passo nella costruzione di un’applicazione per Web server consiste nello
scegliere quale architettura si vuole utilizzare, Web Broker o WebSnap. Entrambi gli
approcci forniscono molte funzioni simili, tra cui
• Il supporto per applicazioni di tipo CGI e Apache DSO Web server. Questi tipi
sono descritti in “Tipi di applicazioni per server Web” a pagina 33-6.
• Supporto per il multithreading per far sì che le richieste in arrivo dei client
vengano gestite su thread separati.
• Cache dei moduli Web per risposte più rapide.
• Sviluppo multipiattaforma. L’applicazione per Web server è facilmente portabile
tra i sistemi operativi Windows e Linux. Il codice sorgente sarà compilato sull’una
o l’altra piattaforma.
Sia i componenti Web Broker che WebSnap gestiscono tutti i meccanismi di
trasferimento delle pagine. WebSnap utilizza Web Broker come cardine e pertanto
incorpora tutte le funzionalità dell’architettura Web Broker. Tuttavia WebSnap offre
un set di strumenti molto più potente per la generazione delle pagine. Inoltre, in fase
di esecuzione, le applicazioni WebSnap permettono di utilizzare script lato server
come ausilio nella generazione delle pagine. Web Broker non ha questa possibilità di
scripting. Gli strumenti offerti in Web Broker non sono affatto completi come quelli
in WebSnap e sono molto meno intuitivi. Se si sta sviluppando una nuova
applicazione per Web server, probabilmente WebSnap rappresenta una scelta
architetturale migliore rispetto a Web Broker.
Le differenze principali fra questi due approcci sono descritte nella seguente tabella:
Per ulteriori informazioni su Web Broker, vedere il Capitolo 34, “Utilizzo di Web
Broker”. Per ulteriori informazioni su WebSnap, consultare il Capitolo 35,
“Creazione di applicazioni Web Server con WebSnap”.
Terminologia e standard
La maggior parte dei protocolli che controllano le attività in Internet è definita nei
documenti Request for Comment (RFC) che vengono creati e mantenuti
costantemente aggiornati dall’Internet Engineering Task Force (IETF), l’esercito di
progetto e sviluppo di protocolli per Internet. Esistono molti RFC importanti
risulteranno molto utili durante la scrittura di applicazioni per Internet:
• RFC822, “Standard for the format of ARPA Internet text messages,” descrive la
struttura e contenuto degli header dei messaggi.
• RFC1521, “MIME (Multipurpose Internet Mail Extensions) Part One: Mechanisms
for Specifying and Describing the Format of Internet Message Bodies,” descrive il
metodo usato per incapsulare e trasportare messaggi multiparte e multiformato
messages.
• RFC1945, “Hypertext Transfer Protocol — HTTP/1.0,” descrive un meccanismo di
trasferimento usato per distribuire documenti ipermediali in gruppi di lavoro.
Lo IETF conserva una libreria di documenti RFC nel proprio sito Web,
www.ietf.cnri.reston.va.us
http://www.Tsite.com/art/gallery.dll/mammals?animal=dog&color=black
URI e URL
Lo URL è un sottoinsieme dello Uniform Resource Identifier (URI) definito nel
documento relativo agli standard di HTTP, RFC1945. Le applicazioni per server Web
spesso producono documenti a partire da varie sorgenti; il risultato finale non risiede
in una particolare ubicazione ma è creato all’occorrenza. Gli URI possono descrivere
risorse che non hanno una ubicazione specifica.
integra il server Web nell’applicazione in modo che sia possibile eseguire il debug
della logica dell’applicazione. L’eseguibile Web Application Debugger è destinato
solo al debug. Quando si distribuisce l’applicazione, si dovrebbe convertirla in uno
degli altri cinque tipi.
ISAPI e NSAPI
Un’applicazione ISAPI o NSAPI per server Web è una DLL che viene caricata dal
server Web. Le informazioni della richiesta del client vengono passate alla DLL come
una struttura e vengono valutate dall’applicazione ISAPI/NSAPI, che crea gli oggetti
richiesta e risposta appropriati. Ogni messaggio di richiesta viene gestito
automaticamente in un thread di esecuzione separato.
CGI indipendente
Un’applicazione CGI indipendente per server Web è un’applicazione per console che
riceve le informazioni della richiesta del client sullo standard input e restituisce i
risultati al server sullo standard output. Questi dati vengono valutati
dall’applicazione CGI, che crea gli oggetti richiesta e risposta appropriati. Ogni
messaggio di richiesta viene gestito da un’istanza differente dell’applicazione.
Apache
Un’applicazione Apache per server Web è una DLL che viene caricata dal server
Web. Le informazioni della richiesta del client vengono passate alla DLL come una
struttura e vengono valutate dall’applicazione Apache del Web server, che crea la
richiesta appropriata e gli oggetti di risposta. Ogni messaggio di richiesta viene
gestito automaticamente in un thread di esecuzione separato. È possibile generare
applicazioni per Web server Apache usando come tipo di destinazione Apache 1 o 2.
Quando si distribuisce l’applicazione per Web server Apache, sarà necessario
specificare nei file di configurazione di Apache alcune informazioni specifiche per
l’applicazione. Ad esempio, in progetti per Apache 1, il nome del modulo predefinito
è il nome del progetto a cui viene aggiunto il suffisso _module. Ad esempio, il nome
del modulo di un progetto di nome Project1 dovrebbe essere Project1_module.
Analogamente, il tipo di contenuto predefinito è il nome del progetto a cui viene
aggiunto –content, e il tipo di gestore predefinito è il nome del progetto a cui viene
aggiunto -handler.
Se occorre, queste definizioni possono essere modificate nel file di progetto (.dpr). Ad
esempio, quando si crea il progetto nel file di progetto viene memorizzato un nome
di modulo predefinito. Ecco un tipico esempio:
exports
apache_module name ’Project1_module’;
N Quando si crea un progetto Web App Debugger, sarà necessario fornire al progetto
un CoClass Name. Questo è semplicemente un nome utilizzato da Web App
Debugger per fare riferimento all’applicazione. Quasi tutti gli sviluppatori utilizzano
come CoClass Name il nome dell’applicazione.
l’applicazione. In questo modo viene creata un’applicazione per Web server che è
anche un server COM.
Per informazioni su come scrivere questa applicazione per Web server utilizzando
Web Broker, vedere il Capitolo 34, “Utilizzo di Web Broker”. Per ulteriori
informazioni sull’utilizzo di WebSnap, vedere il Capitolo 35, “Creazione di
applicazioni Web Server con WebSnap”.
N Per alcuni Web Servers è necessario apportare ulteriori modifiche prima che si abbia
il diritto di avviare l’Host Application in questo modo. Per i dettagli, consultare la
documentazione fornita dal produttore del Web Server.
T Se si utilizza Windows 2000 con IIS 5, i dettagli su tutte le modifiche che è necessario
apportare per configurare correttamente i diritti sono descritte sul sito Web seguente:
http://community.borland.com/article/0,1410,23024,00.html
Una volta configurate le opzioni Host Application e Run Parameters, è possibile
configurare i breakpoint in modo che, non appena il server passa un messaggio di
richiesta alla DLL, uno di questi breakpoint venga intercettato e si possa eseguire il
debug normalmente.
Capitolo
34
Utilizzo di Web Broker
Capitolo34
I componenti di Web Broker (situati sulla pagina Internet della Component palette)
permettono di creare gestori di evento che sono associati a uno specifico Uniform
Resource Identifier (URI). A elaborazione conclusa, è possibile impostare da
programma documenti HTML o XML e trasferirli al client. I componenti WEb Broker
si possono utilizzare per lo sviluppo di applicazioni per più piattaforme.
Spesso, il contenuto delle pagine web è tratto da dei database. È possibile utilizzare
dei componenti Internet per gestire automaticamente le connessioni ai database, il
che consente a un singolo DLL di gestire numerose connessioni database thread-safe.
Le prossime sezioni di questo capitolo spiegano come usare i i componenti Web
Broker per creare un’applicazione per Web server.
• Apache: Selezionando uno dei due tipi di applicazione disponibili (1.x e 2.x) si
configura il progetto come un DLL, con i metodi esportati previsti dal Web server
di destinazione. Al file di progetto viene aggiunto un header di libreria e le voci
richieste alle clausole uses ed exports del file di progetto.
• Web Application Debugger stand-alone executable: La selezione di questo tipo di
applicazione configura un ambiente per sviluppare e provare applicazioni per
Web server. Questo tipo di applicazione non è destinato all’impiego.
Scegliere il tipo di Web Server Application capace di comunicare con il tipo di Web
Server che l’applicazione utilizzerà . In questo modo, si crea un nuovo progetto
configurato per utilizzare i componenti Internet e contenente un modulo Web vuoto.
Il modulo Web
Il modulo Web (TWebModule) è un discendente di TDataModule e può essere
utilizzato nello stesso modo: fornire il controllo centralizzato delle regole di gestione
e dei componenti non visuali nell’applicazione Web.
Si aggiunge poi qualsiasi produttore di contenuti che l’applicazione utilizza per
generare messaggi di risposta. Questi possono essere i produttori di contenuti
incorporati, come TPageProducer, TDataSetPageProducer, TDataSetTableProducer,
TQueryTableProducer e TInetXPageProducer oppure discendenti realizzati ad hoc di
TCustomContentProducer. Se l’applicazione genera messaggi di risposta comprendenti
materiale tratto da database, si possono aggiungere componenti di accesso ai dati o
componenti speciali per scrivere un Web server che si comporti da cliente in
un’applicazione per database multi-tier.
Oltre registrare i componenti non visuali e le regole di gestione, il modulo Web
agisce anche come dispatcher, e fa corrispondere i messaggi di richiesta HTTP in
arrivo a elementi di azione che generano le risposte alle richieste.
A volte, si dispone già di un modulo dati contenente molti dei componenti e delle
regole di gestione non visuali che si intendono usare nell’applicazione Web. In questi
casi, si può sostituire il modulo Web con il modulo dati esistente: basta cancellare il
modulo Web generato automaticamente e sostituirlo con quello esistente. Quindi, si
aggiunge al modulo dati un componente TWebDispatcher, in modo che possa eseguire
il dispatch di messaggi di richiesta a elementi di azione, secondo le modalità previste
per i moduli Web. Se si desidera modificare il modo in cui gli elementi di azione sono
selezionati per rispondere a messaggi di richiesta HTTP in arrivo, far derivare un
nuovo componente dispatcher da TCustomWebDispatcher e aggiungerlo al modulo
dati al posto dell’altro.
Il progetto può contenere solo un dispatcher che può essere il modulo Web generato
automaticamente quando si crea il progetto, oppure il componente TWebDispatcher
aggiunto al modulo dati che sostituisce il modulo Web. Se in fase di l’esecuzione si
crea un secondo modulo dati contenente un dispatcher, l’applicazione per Web
server genera un errore di esecuzione.
per ogni thread vengono create dinamicamente ricorrenze distinte del modulo Web e
del suo contenuto.
W Il modulo Web di un’applicazione per Web server basata su DLL viene messo in
cache per migliorare il tempo di risposta quando viene riutilizzato. Lo stato del
dispatcher e della sua lista di azioni non viene reinizializzato tra due richieste
successive. L’attivazione o la disattivazione di elementi di azione in fase di
esecuzione può produrre risultati inattesi, quando il modulo è utilizzato per
successive richieste client.
W Non includere le unit Forms o QForms alla clausola uses del progetto dopo la unit
CGIApp, ApacheApp, ApacheTwoApp o ISAPIApp. Forms dichiara anche una
variabile globale chiamata Application, e se appare dopo la unit CGIApp,
ApacheApp, ApacheTwoApp o ISAPIApp, Application sarà inizializzata a un oggetto
di tipo errato.
Il dispatcher Web
Il dispatcher Web
Se si utilizza un modulo Web, questo agisce come un dispatcher Web. Se si utilizza
un modulo dati esistente, bisogna aggiungervi un singolo componente dispatcher
(TWebDispatcher). Il dispatcher gestisce un assortimento di elementi di azione in
grado di gestire certi tipi di messaggi di richiesta. Quando l’applicazione Web passa
un oggetto di richiesta e un oggetto di risposta al dispatcher, seleziona anche uno o
più elementi di azione per rispondere alla richiesta.
Il dispatcher Web
Elementi di azione
Quando il dispatcher ha raggiunto la fine della lista di azioni (tra cui l’azione
predefinita, se prevista) e nessuna azione è stata attivata, al server non viene inviato
nulla. Il server si limita a interrompere la connessione con il client.
Se la richiesta è gestita dagli elementi di azione, il dispatcher genera un evento
AfterDispatch. Questo offre all’applicazione l’ultima opportunità di verificare la
risposta fornita e di applicare modifiche all’ultimo minuto.
Elementi di azione
Ogni elemento di azione (TWebActionItem) esegue un’operazione specifica in risposta
a un certo tipo di messaggio di richiesta.
Gli elementi di azione possono rispondere completamente a una richiesta, o eseguire
parte della risposta lasciando poi che siano altri elementi di azione a completare il
lavoro. Gli elementi di azione possono inviare il messaggio HTTP di risposta alla
richiesta, o semplicemente impostare una parte della risposta che viene poi
completata da altri elementi di azione. Se una risposta è completata dagli elementi di
azione ma non viene inviata, l’applicazione per Web server invia il messaggio di
risposta.
L’URL di destinazione
Il dispatcher confronta la proprietà PathInfo di un elemento di azione con il PathInfo
del messaggio di richiesta. Il valore di questa proprietà dovrebbe essere la parte
riguardante le informazioni di percorso dell’URL per tutte le richieste che l’elemento
di azione è preparato a gestire. Ad esempio, dato questo URL,
http://www.TSite.com/art/gallery.dll/mammals?animal=dog&color=black
e supponendo che la parte /gallery.dll indichi l’applicazione per Web server, la parte
riguardante le informazioni di percorso è
/mammals
Le informazioni di percorso sono utili per indicare dove l’applicazione Web deve
cercare le informazioni quando esegue le richieste o per dividere l’applicazione Web
in sottoinsiemi logici.
Elementi di azione
Elementi di azione
l’elemento di azione predefinito viene chiamato solo alla fine impostando la sua
proprietà Enabled a False.
L’elemento di azione predefinito dovrebbe essere preparato a gestire qualsiasi
richiesta che incontra, anche se è solo per restituire un codice di errore indicante una
URI o un MethodType non validi. Se l’elemento di azione predefinito non gestisce la
richiesta, nessuna risposta è inviata al client Web.
La proprietà Method può indicare qualsiasi altro metodo che il client Web richiede al
server.
L’applicazione per Web server non deve fornire una risposta a ogni possibile valore
di Method. Lo standard HTTP vuole però che esso tratti sia le richieste GET che quelle
HEAD.
La proprietà MethodType indica se il valore di Method è GET (mtGet), HEAD
(mtHead), POST (mtPost), PUT (mtPut) o un’altra stringa (mtAny). Il dispatcher fa
corrispondere il valore della proprietà MethodType al MethodType di ogni elemento di
azione.
Modelli HTML
Un modello HTML è una sequenza di comandi HTML e di tag HTML trasparenti. Un
tag HTML trasparente ha la forma
<#TagName Param1=Value1 Param2=Value2 ...>
Le parentesi angolari (< e >) definiscono l’intero campo d’azione del tag. Il simbolo
(# ) segue immediatamente la parentesi angolare aperta (<) senza spazi vuoti tra l’una
e l’altra. Il simbolo # segnala al produttore di pagine che si tratta di un tag HTML
trasparente. Il nome del tag segue immediatamente il simbolo # . Il nome del tag può
essere qualsiasi identificativo valido e individua il tipo di conversione che il tag
rappresenta.
Dopo il nome del tag, il tag HTML trasparente può includere facoltativamente
parametri che specificano i dettagli della conversione da effettuare. Ogni parametro
ha il formato ParamName=Value, senza spazi vuoti tra il nome del parametro, il
simbolo (=) e il valore. I parametri sono separati da spazi vuoti.
Le parentesi angolari (< e >) rendono il tag trasparente ai browser HTML che non
riconoscono il costrutto # TagName.
Mentre è possibile creare dei tag HTML trasparenti ad hoc per rappresentare
qualsiasi genere di informazione elaborata dal produttore di pagine, esistono
numerosi nomi di tag predefiniti associati a valori che hanno TTag come tipo di dati.
Questi nomi del tag predefiniti corrispondono a comandi HTML che facilmente
variano in relazione ai messaggi di risposta e che sono riportati nella seguente
tabella:
Valore di
Nome del tag TTag In che cosa va convertito il tag
Link tgLink Collegamento ipertestuale. Il risultato è una sequenza HTML
che inizia con il tag <A> e finisce con il tag </A>.
Image tgImage Immagine grafica. Il risultato è il tag HTML <IMG>.
Table tgTable Tabella HTML. Il risultato è una sequenza HTML che inizia
con il tag <TABLE> e finisce con il tag </TABLE>.
ImageMap tgImageMap Immagine grafica con zone calde associate. Il risultato è una
sequenza HTML che inizia con il tag <MAP> e finisce con il
tag </MAP>.
Object tgObject Un oggetto incorporato ActiveX. Il risultato è una sequenza
HTML che inizia con il tag <OBJECT> e finisce con il tag </
OBJECT>.
Embed tgEmbed DLL di add-in conforme a Netscape -. Il risultato è una
sequenza HTML che inizia con il tag <EMBED> e finisce con
il tag </EMBED>.
Ogni altro nome di tag è associato a tgCustom. Il produttore di pagine non elabora in
alcun modo i nomi di tag predefiniti, che servono solo per aiutare le applicazioni a
organizzare il processo di conversione in molte delle attività più comuni.
Questo consente a ogni singolo thread di richiesta di interagire con il database senza
interferire con gli altri messaggi di richiesta. Per ulteriori informazioni sule sessioni,
consultare “Gestione delle sessioni di database” a pagina 26-17.
spessore dei separatori e così via. Per impostare in fase di progetto le proprietà di un
produttore di tabelle, fare doppio clic sul componente produttore di tabelle in modo
da visualizzare la finestra di dialogo Response Editor.
Moduli Web
I moduli Web sono il componente di base delle applicazioni WebSnap. Ogni
applicazione server WebSnap deve avere almeno un modulo Web. Se necessario, è
possibile aggiungerne altri. Esistono quattro tipi di moduli Web:
• Moduli pagina Web application (oggetti TWebAppPageModule)
• Moduli dati Web application (oggetti TWebAppDataModule)
• Moduli pagina Web (oggetti TWebPageModule)
• Moduli dati Web (oggetti TWebDataModule)
I moduli pagina web e i moduli pagina Web application forniscono i contenuti per le
pagine web. I moduli dati Web e i moduli dati Web application agiscono come
contenitori per i componenti condivisi all’interno dell’applicazione; nelle
applicazioni WebSnap svolgono la stessa funzione svolta dai comuni moduli dati
nelle normali applicazioni. Nell’applicazione server è possibile includere un qualsiasi
numero di moduli pagina Web o moduli dati. Ci si potrebbe chiedere di quanti
moduli ha bisogno l’applicazione Web. Ogni applicazione WebSnap ha bisogno di un
modulo (e solo uno) Web application di qualche tipo. Oltre a quello, è possibile
aggiungere tutti i moduli pagina Web o dati che sono necessari.
Nel caso dei moduli pagina Web, una buona regola empirica è quella di avere un
modulo per ogni stile di pagina. Se si prevede di implementare una pagina che può
utilizzare il formato di una pagina esistente, è possibile che non sia necessario un
nuovo modulo pagina Web. Le modifiche a un modulo pagina esistente possono
essere sufficienti. Se la pagina è molto diversa dai moduli esistenti, probabilmente si
vorrà creare un nuovo modulo. Ad esempio, si supponga che si stia provando a
costruire un server per gestire online le vendite per catalogo. Le pagine che
descrivono i prodotti disponibili potrebbero condividere tutte lo stesso modulo
pagina Web, poiché le pagine possono contenere tutte gli stessi tipi di informazioni
di base utilizzando la stessa disposizione. Un modulo d’ordine, tuttavia,
probabilmente richiederà un modulo pagina Web differente, poiché il formato e la
funzione di un modulo d’ordine sono diversi rispetto a quelli di una pagina per la
descrizione di un prodotto.
Le regole sono diverse nel caso dei moduli dati Web. I componenti che possono
essere condivisi da molti moduli Web dovrebbero essere messi in un unico modulo
dati Web in modo da semplificare l’accesso condiviso. Sarà opportuno anche mettere
i componenti che possono essere utilizzati da molte applicazioni web nel rispettivo
modulo dati Web. In questo modo è possibile condividere facilmente quegli elementi
tra le applicazioni. Naturalmente, se nessuna di queste considerazioni è applicabile al
proprio caso, si potrebbe anche decidere di non utilizzare affatto i moduli dati Web. Il
loro utilizzo è analogo a quello dei normali moduli dati, e deve essere supportato del
proprio giudizio e dalla propria esperienza.
I moduli Web application agiscono come contenitori per i componenti che eseguono
funzioni per l’applicazione in generale — come la distribuzione delle richieste, la
gestione delle sessioni e la manutenzione delle liste di utenti. Se si ha già una certa
familiarità con l’architettura Web Broker, è possibile pensare ai moduli Web
application come se fossero simili a oggetti TWebApplication. I moduli Web
invece che HTML. I modelli XSL non supportano marcatori trasparenti o script lato
server.)
Ai moduli pagina Web potrebbe essere associato un file di modello, gestito come
parte della unit. Un file di modello gestito viene visualizzato nel Project Manager e
ha gli stessi nome file e ubicazione di base del file di servizio della unit. Se il modulo
pagina Web non ha un file di modello associato, le proprietà del componente
produttore di pagine specificano il modello.
Adattatori
Gli adattatori definiscono un’interfaccia di script per l’applicazione server. Essi
permettono di inserire linguaggi di scripting all’interno della pagina e di reperire
informazioni effettuando chiamate dal codice dello script agli adattatori. Ad
esempio, è possibile utilizzare un adapter per definire i campi di dati da visualizzare
in una pagina HTML. Una pagina HTML con script può quindi contenere dei
contenuti HTML e istruzioni script che acquisiscono i valori di quei campi dati. Il
comportamento è simile a quello dei marcatori trasparenti utilizzati nelle
applicazioni Web Broker. Gli adattatori supportano anche le azioni che eseguono
Campi
I campi sono componenti che il produttore di pagine utilizza per ottenere i dati
dall’applicazione e visualizzare il contenuto in una pagina web. I campi possono
essere utilizzati anche per acquisire un’immagine. In questo caso, il campo restituisce
l’indirizzo dell’immagine scritta sulla pagina web. Quando una pagina visualizza il
proprio contenuto, viene inviata una richiesta all’applicazione per Web server, la
quale richiama il dispatcher dell’adapter per ottenere l’immagine effettiva dal
componente campo.
Azioni
Le azioni sono componenti che eseguono comandi per conto dell’adapter. Quando
un produttore di pagine genera la propria pagina, il linguaggio di scripting chiama i
componenti azione dell’adapter per restituire il nome dell’azione insieme agli
eventuali parametri necessari per eseguire il comando. Ad esempio, si immagini di
fare clic su un pulsante in una pagina HTML per cancellare una riga da una tabella.
L’operazione restituisce, nella richiesta HTTP, il nome dell’azione associata al
pulsante e un parametro che indica il numero di riga. Il dispatcher dell’adapter
individua il componente azione chiamato e passa all’azione il numero di riga sotto
forma di parametro.
Errori
Gli adattatori mantengono un elenco degli errori che si verificano durante
l’esecuzione di un’azione. I produttori di pagina possono accedere a questo elenco di
errori e visualizzarli nella pagina web che l’applicazione restituisce all’utente finale.
Record
Alcuni componenti adapter, come TDataSetAdapter, rappresentano più record.
L’adapter fornisce un’interfaccia di scripting che consente l’iterazione fra i record.
Alcuni adattatori supportano la paginazione e iterare solo attraverso i record alla
pagina corrente.
Produttori di pagina
I produttori di pagina sono utilizzati per generare i contenuti per conto di un modulo
pagina Web. I produttori di pagina forniscono le seguenti funzionalità:
• Generano un contenuto HTML.
• Possono referenziare un file esterno utilizzando la proprietà HTMLFile, oppure la
stringa interna utilizzando la proprietà HTMLDoc.
• Quando i produttori sono utilizzati con un modulo pagina Web, il modello può
essere un file associato a una unit.
• I produttori generano dinamicamente il codice HTML che può essere inserito nel
modello utilizzando i marcatori trasparenti o lo scripting attivo. I marcatori
trasparenti possono essere utilizzati nello stesso modo delle applicazioni
WebBroker. Per maggiori informazioni sull’utilizzo dei marcatori trasparenti,
vedere “Conversione dei tag HTML trasparenti” a pagina 34-15. Il supporto per
l’Active scripting permette di incorporare n ela pagina HTML JScript o VBScript.
Il metodo standard WebSnap per l’utilizzo dei produttori di pagina è il seguente.
Quando si crea un modulo pagina Web, è necessario scegliere nel Web page module
wizard un tipo di produttore di pagine. Vi sono molte possibilità, ma la maggior
parte degli sviluppatori WebSnap crea il prototipo delle proprie pagine utilizzando
un adapter produttore di pagine, TAdapterPageProducer. L’adapter produttore di
pagine permette di creare un prototipo di pagina web utilizzando un processo
analogo al modello a componenti standard. All’adapter produttore di pagine si
aggiunge un tipo di scheda, una scheda di adapter. Poiché sono necessari, è possibile
aggiungere alla scheda adapter componenti adapter (come griglie adapter).
Utilizzando adattatori produttori di pagine, è possibile creare pagine web usando
una tecnica simile a quella standard per la costruzione delle interfacce utente.
Vi sono alcuni casi in cui è più opportuno passare da un adapter produttore di
pagine a un normale produttore di pagine. Ad esempio, uno dei compiti di un
adapter produttore di pagine è quello di generare dinamicamente in fase di
esecuzione script in un modello di pagina. Si potrebbe decidere che uno script statico
potrebbe ottimizzare il server. Inoltre, gli utenti esperti con il linguaggio di scripting
potrebbero volere apportare modifiche direttamente nello script. In questo caso, si
deve utilizzare un normale produttore di pagina per evitare conflitti tra script
dinamico e statico. Per apprendere come passare a un normale produttore di pagine,
vedere .
È possibile anche utilizzare i produttori di pagina nello stesso modo in cui li si
utilizzerebbe nelle applicazioni Web Broker, associando il produttore a un elemento
di azione Web dispatcher. I vantaggi derivanti dall’utilizzo del modulo pagina Web
sono
• la capacità di vedere in anteprima il layout della pagina senza dover eseguire
l’applicazione, e
• la capacità di associare al modulo un nome di pagina, in modo che il dispatcher
delle pagine possa chiamare automaticamente il produttore di pagine.
Per ognuno dei precedenti componenti, i tipi di componenti elencati sono i tipi
predefiniti forniti con l’IDE. Gli utenti possono creare i propri tipi di componenti o
utilizzare tipi di componenti forniti da terze parti.
Figura 35.3 Finestra di dialogo Web App Components con le opzioni per supporto del login selezionate
Nel servizio per le sessioni ci sono due proprietà importanti che è possibile utilizzare
per modificare il comportamento predefinito del server. La proprietà MaxSessions
specifica quanti utenti possono essere registrati nel sistema in un dato momento. Il
valore predefinito per MaxSessions è -1, che non pone alcuna limitazione software al
numero di utenti consentiti. Naturalmente, l’hardware del server potrebbe disporre
di poca memoria o servire gli utenti in modo ciclico, il che può influire
negativamente sulle prestazioni del sistema. Se si pensa che il numero eccessivo di
utenti potrebbe sovraccaricare il server, accertarsi di impostare MaxSessions a un
valore appropriato.
La proprietà DefaultTimeout specifica il periodo di timeout predefinito in minuti.
Dopo che sono trascorsi DefaultTimeout minuti senza alcuna attività da parte
dell’utente, la sessione viene terminata automaticamente. Se l’utente aveva eseguito
il login, tutte le informazioni di login vanno perdute. Il valore predefinito è 20. È
possibile ridefinire il valore predefinito in qualsiasi sessione modificandone la
proprietà TimeoutMinutes.
Pagine di login
Naturalmente, l’applicazione ha bisogno anche di una pagina di login. Gli utenti
immettono il loro nome utente e la loro password per l’autenticazione, o mentre
tentano di accedere a una pagina con accesso limitato o prima di tale tentativo.
L’utente può anche specificare quale pagina ricevere una volta completata
l’autenticazione. Se il nome utente e la password sono uguali a quelli di un utente
nell’elenco Web user, l’utente acquisisce i diritti di accesso appropriati e viene
indirizzato alla pagina specificata nella pagina di login. Se l’utente non è autenticato,
è possibile visualizzare di nuovo la pagina di login (azione predefinita) oppure fare
eseguire un’altra azione.
Fortunatamente, WebSnap semplifica la creazione di una semplice pagina di login
utilizzando un modulo pagina Web e l’adapter produttore di pagine. Per creare una
pagina di login, iniziare creando un nuovo modulo pagina Web. Selezionare File|
New|Other per visualizzare la finestra di dialogo New Items, quindi selezionare
dalla pagina WebSnap l’opzione Page Module. Selezionare AdapterPageProducer
come tipo di produttore di pagina. Compilare le altre opzioni nel modo desiderato.
Come nome della pagina di login si può usare Login.
A questo punto si dovrebbero aggiungere i classici campi presenti in una pagina di
login: un campo per il nome utente, uno per la password, una casella di selezione per
selezionare la pagina da ricevere dopo aver effettuato il login e un pulsante Login che
trasmette la pagina ed esegue l’autenticazione dell’utente. Per aggiungere questi
campi:
1 Aggiungere al modulo pagina Web appena creato un componente
LoginFormAdapter (che è possibile trovare sulla pagina WebSnap della
Component palette).
2 Fare doppio clic sul componente AdapterPageProducer per visualizzare una finestra
per l’editing della pagina web.
• È possibile nascondere determinati campi agli utenti che non hanno i necessari
diritti di accesso in visualizzazione.
• È possibile impedire agli utenti non autorizzati di ricevere determinate pagine.
In questa sezione viene spiegato come implementare questi comportamenti.
pagina HTML i dati dell’applicazione. Infatti, quasi tutte le proprietà esposte dagli
adattatori e altri oggetti abilitati allo script sono a sola lettura. Lo script lato server
non viene utilizzato per modificare i dati dell’applicazione, che vengono gestiti da
componenti e da gestori di evento scritti nel codice sorgente dell’applicazione.
Esistono altri modi per inserire i dati dell’applicazione in una pagina HTML. Se si
preferisce, è possibile utilizzare i marcatori trasparenti di Web Broker o qualche altra
soluzione basata su marcatori. Ad esempio, diversi progetti nella cartella degli
esempi di WebSnap utilizzano XML e XSL invece dello scripting. Senza scripting,
tuttavia, si sarà costretti a scrivere la maggior parte della logica della generazione
HTML in codice sorgenete, il che allungherà i tempi di sviluppo.
Lo scripting utilizzato in WebSnap è orientato agli oggetti e supporta la logica
condizionale e i cicli, il che può semplificare notevolmente l’attività di generazione
delle pagine. Ad esempio, le pagine possono includere un campo dati che può essere
modificato da alcuni utenti ma non da altri. Con lo scripting, la logica condizionale
può essere inclusa nelle pagine modello che visualizzeranno una casella di modifica
per gli utenti autorizzati e del semplice testo per altri. Con un approccio basato su
marcatori, è necessario programmare tale processo decisionale nel codice sorgente
che genera il codice HTML.
Active scripting
Per implementare lo script lato server, WebSnap si basa su active scripting. Active
scripting è una tecnologia creata da Microsoft per consentire l’uso di un linguaggio di
scripting con gli oggetti dell’applicazione attaraverso interfacce COM. Microsoft
prevede due linguaggi di active scripting, VBScript e JScript. Il supporto per altri
linguaggi è disponibile tramite produttori terzi.
Motore di script
La proprietà ScriptEngine del produttore di pagine identifica il motore di active
scripting che valuta lo script all’interno di un modello. L’impostazione predefinita è
quella di supportare JScript, ma può anche supportare altri linguaggi di scripting
(come VBScript).
N Gli adattatori di WebSnap sono progettati per produrre JScript. Per altri linguaggi di
scripting sarà necessario fornire allo script la logica di generazione.
Blocchi di script
I blocchi di script, che appaiono nei modelli HTML, sono delimitati da <% e da %>. Il
motore di script valuta qualsiasi testo interno al blocco di script. Il risultato diventa
parte dei contenuti del produttore di pagine. Il produttore di pagine scrive il testo
esterno a un blocco di script dopo avere tradotto gli eventuali marcatori trasparenti
incorporati. I blocchi di script possono anche includere testo, consentendo alla logica
Creazione di script
Gli sviluppatori possono sfruttare le funzionalità di WebSnap per generare
automaticamente script.
Modelli di wizard
Quando si crea un nuovo modulo WebSnap application o pagina, i wizard di
WebSnap presentano un campo Template che viene utilizzato per selezionare il
contenuto iniziale del modello del modulo pagina. Ad esempio, il modello Default
genera JScript che, a sua volta, visualizza il titolo dell’applicazione, il nome della
pagina e i link alle pagine pubblicate.
TAdapterPageProducer
TAdapterPageProducer crea schede e tabelle mediante la generazione di HTML e
JScript. Lo JScript generato chiama gli oggetti adapter per acquisire i valori dei
campi, parametri dei campi immagine e i parametri delle azioni.
Se il modello include script di un’altra pagina, lo script viene valutato dalla pagina
che effettua l’inclusione. Per includere il contenuto non valutato di page1, utilizzare
la seguente istruzione.
<!-- #include page="page1" -- >
Oggetti script
Gli oggetti script sono oggetti che i comandi dello script possono referenziare. È
possibile rendere gli oggetti disponibili allo scripting registrando un’interfaccia
IDispatch verso l’oggetto con il motore di active scripting. I seguenti oggetti sono
disponibili per lo scripting:
Gli oggetti script sulla pagina corrente, che utilizzano tutti lo stesso adapter, possono
essere referenziati senza qualifica. Gli oggetti script su altre pagine fanno parte di un
altro modulo pagina e hanno un oggetto adapter diverso. È possibile accedervi
anteponendo al riferimento dell’oggetto script il nome dell’oggetto adapter. Ad
esempio,
<%= FirstName %>
visualizza il contenuto della proprietà FirstName dell’adapter della pagina corrente.
La seguente riga di script visualizza la proprietà FirstName di Adapter1, che è in un
altro modulo di pagina:
<%= Adapter1.FirstName %>
Per una descrizione esaustiva degli oggetti script, vedere l’argomento “WebSnap
server-side scripting reference” della Guida in linea.
Componenti dispatcher
I componenti dispatcher nel modulo Web application controllano il flusso
dell’applicazione. I dispatcher determinano come gestire alcuni tipi di messaggi di
richiesta HTTP esaminando la richiesta HTTP.
Il componente adapter dispatcher (TAdapterDispatcher) cerca un campo di contenuti o
un campo query, che identifica un componente adapter action o un componente
adapter image field. Se l’adapter dispatcher trova un componente, passa controllo a
quel componente.
Il componente Web dispatcher (TWebDispatcher) gestisce una raccolta di elementi di
azione (di tipo TWebActionItem) che sanno come gestire alcuni tipi di messaggi di
richiesta HTTP. Il Web dispatcher cerca un elemento di azione che soddisfi la
richiesta. Se ne trova uno, passa il controllo a quell’elemento di azione. Il Web
dispatcher cerca anche componenti auto-dispatching che possano gestire la richiesta.
Il componente page dispatcher (TPageDispatcher) esamina la proprietà PathInfo
dell’oggetto TWebRequest , cercando il nome di un modulo pagina Web registrato. Se
il dispatcher trova un nome di modulo pagina Web, passa il controllo a quel modulo.
Richieste di azioni
Gli oggetti di richiesta di azioni sono responsabili di suddividere la richiesta HTTP in
informazioni necessarie per eseguire un’azione dell’adapter. I tipi di informazioni
necessarie per l’esecuzione di un’azione dell’adapter possono includere le seguenti
informazioni di richiesta:
La Figura 35.8 illustra il modo in cui gli oggetti action request and action response
gestiscono una richiesta.
Figura 35.6 Action request e response
Richiesta di immagine
informazioni richieste dal campo immagine dell’adapter per generare un’immagine.
I tipi di informazioni rappresentate da Image Request includono:
• Component name - Identifica il componente campo dell’adapter.
• Image request parameters - Identifica i parametri necessari per l’adapter image.
Ad esempio, all’oggetto TDataSetAdapterImageField sono necessari dei valori
chiave per identificare il record che contiene l’immagine.
Risposta di immagine
L’oggetto image response contiene l’oggetto TWebResponse. I campi dell’adapter
rispondono a una richiesta dell’adapter scrivendo un’immagine nell’oggetto Web
response.
La Figura 35.7 illustra illustra il modo in cui i campi immagine dell’adapter
rispondono a una richiesta.
Introduzione a IntraWeb
Se si ha esperienza nello scrivere applicazioni GUI utilizzando gli strumenti per lo
sviluppo rapido di applicazioni di Borland, allora si hanno già le basi necessarie per
iniziare a costruire applicazioni tramite IntraWeb. Il metodo di progettazione di base
per l’interfaccia utente è lo stesso, sia per IntraWeb sia per una normale applicazione
GUI: trovare i componenti necessari sulla component palette e rilasciarli su una
scheda. A differenza dei moduli pagina di WebSnap, l’aspetto della scheda rispecchia
quello della pagina. Le schede e i componenti di IntraWeb sono distinte rispetto alle
proprie corrispondentii VCL e CLX, ma sono chiamate e disposte in maniera molto
simile.
Ad esempio, si vuole aggiungere un pulsante in una scheda. In una qualsiasi
applicazione VCL o CLX si troverebbe il componente Button sulla pagina Standard
component palette e lo si rilascerebbe sulla scheda nella locazione appropriata.
Nell’applicazione compilata, il pulsante si trova dove lo si è posizionato. L’unica
differenza in un’applicazione IntraWeb, è che si utilizza il componente IWButton
sulla pagina IWStandard. Anche le icone per i due differenti componenti button sono
quasi identiche. L’unica differenza sono le lettere “IW” nell’angolo in alto a destra
dell’icona del pulsante IntraWeb.
Di seguito vi è una breve esercitazione per mostrare quanto sia semplice costruire
un’applicazione IntraWevb. L’applicazione che verrà sviluppata in questa
esercitazione, chiede all’utente di fornire alcuni input e visualizzerà questi input in
una finestra popup. L’esercitazione utilizza il modo standalone di IntraWeb, in
questo modo l’applicazione creata potrà essere eseguita senza Web Server
commerciale.
L’esercitazione comprende i seguenti passi:
1 Creazione di una nuova applicazione IntraWeb
2 Modifica della scheda principale
3 Scrittura di un gestore di evento per il pulsante
4 Esecuzione dell’applicazione completata
end;
2 Utilizzando l’editor, aggiungere il codice al gestore di evento, in modo che
assomigli al seguente:
procedure TformMain.IWButton1Click(Sender: TObject);
var s: string;
begin
s := editName.Text;
if Length(s) = 0 then
WebApplication.ShowMessage('Please enter your name.')
else
begin
WebApplication.ShowMessage('Hello, ' + s +'!');
editName.Text := '';
end;
end;
3 Assumendo che il proprio nome sia World. Immettere World nell’ edit box e fare
clic sul pulsante OK. Apparirà una finestra di dialogo modale:
codifica UTF-8 e che si basa su un file esterno per la dichiarazione del tipo di
documento (DTD)).
La seconda riga, che inizia con il marcatore <!DOCType>, è una dichiarazione del
tipo di documento (DTD). Il DTD è il modo in cui XML definisce la struttura del
documento. Essa impone regole sintattiche relative agli elementi (marcatori)
contenuto nel documento. Il DTD in questo esempio referenzia un altro file (sth.dtd).
In questo caso, la struttura è definita in un file esterno, invece che all’interno dello
stesso documento XML. Altri tipi di file che descrivono la struttura di un documento
XML includono XDR (Reduced XML Data) e XDR (XML schema).
Le restanti righe sono organizzate gerarchicamente con un singolo nodo radice (il
marcatore <StockHoldings>). Ogni nodo in questa gerarchia contiene o un insieme di
nodi figlio, o un valore di testo. Alcuni marcatori (i marcatori <Stock> e <shares>)
includono attributi, che sono coppie Name=Value che forniscono dettagli su come
interpretare il marcatore.
Benché sia possibile operare direttamente con il testo in un documento XML, di solito
le applicazioni utilizzano particolari strumenti aggiuntivi per l’analisi sintattica e la
modifica dei dati. W3C definisce un insieme di interfacce standard per rappresentare
un documento analizzato XML di nome DOM (Document Object Model). Molti
fornitori forniscono parser XML che implementano le interfacce DOM per
semplificare l’interprezione e la modifica di documenti XML.
Delphi fornisce molti strumenti aggiuntivi per operare con i documenti XML. Questi
strumenti utilizzano un parser DOM, fornito da un altro produttore, e facilitano
notevolmente le operazioni sui documenti XML. Questo capitolo descrive questi
strumenti.
• Per utilizzare uno dei fornitori DOM il cui supporto è già previsto da Delphi,
individuare la unit che rappresenta l’implementazione DOM. Queste unit
terminano con la stringa ‘xmldom.’ Ad esempio, la unit per l’implementazione di
Microsoft si chiama MSXMLDOM, la unit per l’implementazione IMB si chiama
IBMXMLDOM e la unit per l’implementazione Open XML si chiama OXMLDOM.
Se si aggiunge al proprio progetto la unit per l’implementazione desiderata,
l’implementazione DOM viene registrata automaticamente in modo da renderla
disponibile al codice sorgente.
• Per utilizzare un’altra implementazione DOM, è necessario creare una unit che
definisca un derivato della classe TDOMVendor. Questa unit potrà quindi
funzionare come una delle implementazioni DOM incluse, rendendo disponibile
l’implementazione DOM appena si include la unit nel progetto.
• Nella classe discendente, è necessario ridefinire due metodi: il metodo
Description, che restituisce una stringa che identifica il fornitore e il metodo
DOMImplementation, che restituisce l’interfaccia di alto livello
(IDOMImplementation).
• La nuova unit deve registrare il fornitore chiamando la procedura globale
RegisterDOMVendor. Questa chiamata di solito viene inclusa nella sezione di
inizializzazione della unit.
• Quando la unit viene scaricata, è necessario che essa annulli la propria
registrazione in modo da indicare che l’implementazione DOM non è più
disponibile. Annullare la registrazione del fornitore chiamando la procedura
globale UnRegisterDOMVendor. Questa chiamata di solito viene inclusa nella
sezione di finalizzazione della unit.
Alcuni produttori forniscono estensioni alle interfacce DOM standard. Per consentire
l’utilizzo di queste estensioni, la unit XMLDOM definisce anche un’interfaccia
IDOMNodeEx. IDOMNodeEx è un discendente della IDOMNode standard che include
la più utile di queste estensioni.
È possibile operare direttamente con interfacce DOM per analizzare e modificare
documenti XML. È sufficiente chiamare la funzione GetDOM per ottenere
un’interfaccia IDOMImplementation, che è possibile utilizzare come punto di
partenza.
N Per una descrizione dettagliata delle interfacce DOM, vedere le dichiarazioni nello
header della unit XMLDOM, la documentazione fornita dal produttore DOM o le
specifiche fornite sul sito Web di W3C (www.w3.org).
Potrebbe però risultare più conveniente utilizzare le classi XML invece di operare
direttamente con le interfacce DOM. Queste classi sono descritte di seguito.
Utilizzo di TXMLDocument
Il punto di partenza per operare con un documento XML è il componente
TXMLDocument. I seguenti punti descrivono come utilizzare TXMLDocument per
operare direttamente con un documento XML:
1 Aggiungere un componente TXMLDocument alla scheda o al modulo dati.
TXMLDocument è presente sulla pagina Internet della Component palette.
2 Impostare la proprietà DOMVendor per specificare l’implementazione DOM che si
vuole venga utilizzata dal componente per l’analisi sintattica e la modifica di un
documento XML. L’Object Inspector elenca tutti i produttori DOM attualmente
registrati. Per informazioni sulle implementazioni DOM, consultare “Utilizzo del
Document Object Model” a pagina 37-2.
3 A seconda dell’implementazione, si potrebbe voler impostare la proprietà
ParseOptions in modo da configurare in che modo l’implementazione DOM
sottostante analizza il documento XML.
4 Se si sta operando con un documento XML esistente, specificare il documento:
• Se il documento XML è memorizzato in un file, impostare la proprietà FileName
al nome di quel file.
• Utilizzando invece la proprietà XML è possibile specificare il documento XML
come una stringa.
5 Impostate la proprietà Active a True.
Una volta che si ha un oggetto TXMLDocument attivo, è possibile esaminare la
gerarchia dei suoi nodi oltre che leggere o impostare i rispettivi valori. Il nodo radice
di questa gerarchia è disponibile come proprietà DocumentElement.
<symbol>BORL</symbol>
<shares>100</shares>
</Stock>
<Stock exchange="NYSE">
<name>Pfizer</name>
<price>42.75</price>
<symbol>PFE</symbol>
<shares type="preferred">25</shares>
</Stock>
</StockHoldings>
TXMLDocument genererebbe una gerarchia di nodi di questo tipo: La radice della
gerarchia sarebbe il nodo StockHoldings. StockHoldings avrebbe due nodi figlio, che
corrispondono alle due marcatori Stock. Ognuno di questi due nodi figlio avrebbe
quattro nodi figlio propri (name, price, symbol e shares). Quei quattro nodi figlio
agirebbero come nodi foglia. Il testo che essi contengono verrebbe visualizzato come
il valore di ognuno dei nodi foglia.
<phone>(831) 431-1000</phone>
</customer>
Data Binding wizard genera la seguente interfaccia (oltre a una classe per
implementarla):
ICustomer = interface(IXMLNode)
property id: Integer read Getid write Setid;
property name: DOMString read Getname write Setname;
property phone: DOMString read Getphone write Setphone;
function Getid: Integer;
function Getname: DOMString;
function Getphone: DOMString;
procedure Setid(Value: Integer);
procedure Setname(Value: DOMString);
procedure Setphone(Value: DOMString);
end;
Ogni nodo figlio viene fatto corrispondere a una proprietà, il cui nome corrisponde al
nome del marcatore del nodo figlio e il cui valore è l’interfaccia del nodo figlio (nel
caso il nodo figlio sia un nodo interno) o con il valore del nodo figlio (nel caso di nodi
foglia). Anche ogni attributo di nodo viene fatto corrispondere con una proprietà, in
cui il nome della proprietà è il nome dell’attributo e il valore della proprietà è il
valore dell’attributo.
Oltre alla creazione di interfacce (e delle classi di implementazione discendenti) per
ogni elemento contrassegnato incluso nel documento XML, il wizard crea una
funzione globale per ottenere l’interfaccia verso il nodo radice. Ad esempio, se lo
XML di cui sopra provenisse da un documento al cui nodo radice era associato il
marcatore <Customers>, Data Binding wizard creerebbe le seguente routine globali:
function GetCustomers(XMLDoc: IXMLDocument): ICustomers;
function LoadCustomers(const FileName: WideString): ICustomers;
function NewCustomers: ICustomers;
La funzione Get... accetta il wrapper dell’interfaccia di un’istanza TXMLDocument (o
di un puntatore a quell’istanza di TXMLDocument). La funzione Load... crea
dinamicamente un’istanza di TXMLDocument e carica il file XML specificato come
suo valore prima di restituire un puntatore all’interfaccia. La funzione New... crea
una nuova istanza (vuota) di TXMLDocument e restituisce l’interfaccia al nodo radice.
L’utilizzo delle interfacce generate semplifica il codice, perché riflettono la struttura
del documento XML in modo più diretto. Ad esempio, invece di scrivere del codice
simile al seguente:
CustIntf := XMLDocument1.DocumentElement;
CustName := CustIntf.ChildNodes[0].ChildNodes['name'].Value;
Il codice sarebbe invece:
CustIntf := GetCustomers(XMLDocument1);
CustName := CustIntf[0].Name;
Si noti che le interfacce generate da Data Binding wizard discendono tutte da
IXMLNode. Ciò significa che è sempre possibile aggiungere e cancellare i nodi figlio
secondo le stesse modalità di quando non si utilizza Data Binding wizard. (Vedere
“Aggiunta e cancellazione di nodi figlio” a pagina 37-6). Inoltre, quando i nodi figlio
rappresentano elementi ripetitivi (quando tutti i figli di un nodo sono dello stesso
tipo), al nodo genitore vengono assegnati due metodi, Add e Insert, per l’aggiunta di
ulteriori ripetizioni. Questi metodi sono più semplici rispetto all’utilizzo di AddChild,
perché non è necessario specificare il tipo di nodo da creare.
XMLDocument1.FileName := 'Stocks.xml';
StockList := GetStockListType(XMLDocument1);
• Chiamare la funzione generata Load... per creare e collegare l’istanza di
TXMLDocument e ottenere la sua interfaccia in un solo passaggio. Ad esempio,
utilizzando lo stesso documento XML descritto in precedenza:
var
StockList: IStockListType;
begin
StockList := LoadStockListType('Stocks.xml');
• Chiamare la funzione New... generata per creare l’istanza di TXMLDocument di
un documento vuoto quando si vogliono creare tutti i dati nell’applicazione:
var
StockList: IStockListType;
begin
StockList := NewStockListType;
2 Questa interfaccia ha proprietà che corrispondono ai sottonodi dell’elemento
radice del documento, oltre a proprietà che corrispondono agli attributi di
quell’elemento radice. È possibile utilizzare queste proprietà per percorrere la
gerarchia del documento XML, modificare i dati nel documento, e così via.
3 Per salvare tutte le modifiche apportate utilizzando le interfacce generate dal
wizard, chiamare il metodo SaveToFile del componente TXMLDocument o leggerne
la proprietà XML.
38
Utilizzo dei Web Services
Capitolo 38
N Benché i componenti che supportano i Web Services siano stati concepiti per
utilizzare SOAP e HTTP, il framework è sufficientemente generico da poter essere
ampliato in modo da utilizzare altri protocolli di codifica e di comunicazione.
Oltre a consentire la costruzione di applicazioni Web Service basate su SOAP
(server), speciali componenti e wizard consentono di generare client di Web Services
che utilizzano una codifica SOAP o uno stile Document Literal. Lo stile Document
Literal è utilizzato nei Web Services .Net.
I componenti che supportano i Web Services sono disponibili sia in Windows che in
Linux, e pertanto è possibile utilizzarli come elementi base per applicazioni
distribuite multipiattaforma. Non occorre installare alcun particolare software client
runtime, come quando si distribuiscono le applicazioni che utilizzano CORBA.
Poiché questa tecnologia si basa sui messaggi HTTP, presenta il vantaggio che è
ampiamente disponibile su una vasta gamma di macchine. Il supporto per i Web
Services si fonda sull’architettura di applicazioni per Web server (Web Broker).
Le applicazioni Web Service pubblicano mediante un documento WSDL (Web
Service Definition Language) informazioni sulle interfacce disponibili e su come
chiamarle. Sul lato server, l’applicazione può pubblicare un documento WSDL che
descrive il Web Service. Sul lato client, un wizard o programma di utilità a riga di
comando può importare un documento WSDL pubblicato, fornendo le definizioni
delle interfacce e le informazioni di connessione necessarie. Se già si possiede un
documento WSDL che descrive il servizio Web che si desidera implementare, è
possibile generare il codice lato server anche quando si importa il documento WSDL.
Le interfacce richiamabili
I server che supportano i Web Services sono costruiti utilizzando interfacce
richiamabili. Le interfacce richiamabili sono interfacce che vengono compilate in
modo da includere informazioni di tipo in esecuzione (RTTI). Sul server, queste RTTI
vengono utilizzate durante l’interpretazione delle chiamate ai metodo in arrivo dai
client in modo che possano essere smistate correttamente. Sui client, queste RTTI
vengono utilizzate per generare dinamicamente una tabella dei metodi per effettuare
chiamate ai metodi dell’interfaccia.
Per creare un’interfaccia richiamabile, è necessario solo compilare un’interfaccia con
l’opzione {$M+} del compilatore. Anche il discendente di qualsiasi interfaccia
richiamabile è a sua volta richiamabile. Tuttavia, se un’interfaccia richiamabile
discende da un’altra classe di interfaccia che non è richiamabile, il Web Service può
solo utilizzare i metodi definiti nell’interfaccia richiamabile e nei suoi discendenti. I
metodi ereditati da antenati non richiamabili non vengono compilati con le
informazioni di tipo e non possono essere così utilizzati come parte del Web Service.
Quando si definisce un Web service, si può derivare un’interfaccia richiamabile
dall’interfaccia richiamabile di base, IInvokable. IInvokable è definita nella unit System.
IInvokable è identica all’interfaccia di base (IInterface), tranne per il fatto che è
compilata utilizzando l’opzione {$M+} del compilatore. L’opzione {$M+} del
compilatore garantisce che l’interfaccia e tuti i suoi discentendi includano le RTTI.
Ad esempio, il seguente codice definisce un’interfaccia richiamabile che contiene due
metodi per codificare e decodificare valori numerici:
IEncodeDecode = interface(IInvokable)
['{C527B88F-3F8E-1134-80e0-01A04F57B270}']
function EncodeValue(Value: Integer): Double; stdcall;
function DecodeValue(Value: Double): Integer; stdcall;
end;
• Boolean • LongInt
• ByteBool • Int64
• WordBool • Single
• LongBool • Double
• Char • Extended
• Byte • string
• ShortInt • WideString
• SmallInt • Currency
• Word • TDateTime
• Integer • Variant
• Cardinal
Non sono necessarie operazioni particolari quando si utilizzano questi tipi scalari in
un’interfaccia richiamabile. Tuttavia, se l’interfaccia include qualche proprietà o
metodo che utilizza altri tipi, l’applicazione deve registrare quei tipi con il registro
dei tipi remotable. Per ulteriori informazioni sul registro dei tipi remotable, vedere
“Registrazione di tipi non scalari” a pagina 38-5.
Gli array dinamici possono essere utilizzati nelle interfacce richiamabili. Essi devono
essere registrati con il registro dei tipi remotable, ma questa registrazione avviene
automaticamente quando si registra l’interfaccia. Il registro dei tipi remotable estrae
tutte le informazioni necessarie dalle informazioni di tipo generate dal compilatore.
N Si dovrebbe evitare di definire più tipi di array dinamici con lo stesso tipo di
elemento. Poiché il compilatore tratta questi tipi come tipi trasparenti che possono
essere convertiti implicitamente l’uno nell’altro, non è in grado di distinguere le
rispettive informazioni di tipo in esecuzione. Di conseguenza, il registro dei tipi
remotable non può distinguere i tipi. Questo non è un problema per i server, ma può
far sì che i client utilizzino la definizione di tipo errata. Come approccio alternativo, è
possibile utilizzare le classi remotable per rappresentare i tipi array.
N I tipi dynamic array definiti nella unit Types vengono registrati automaticamente, e
pertanto l’applicazione non deve aggiungere alcun codice di registrazione
particolare. Uno di questi in particolare, TByteDynArray, merita una menzione
speciale poiché mappa un blocco di dati binari ’base64’, invece di mappare
separatamente ogni elemento dell’array come fanno gli altri tipi di dynamic array.
In un’interfaccia richiamabile possono essere utilizzati anche i tipi enumerati e i tipi
mappati direttamente a uno dei tipi scalari di cui viene eseguito il marshaling
automatico. Come nel caso dei tipi array dinamici, essi vengono registrati
automaticamente con il registro dei tipi remotable.
Per tutti gli altro tipi, come static array, struct o record, set, interfacce e classi è
necessario mappare il tipo con una classe remotable. Una classe remotable è una
classe che include informazioni di tipo in esecuzione (RTTI). L’interfaccia deve
utilizzare quindi la classe remotable invece dello static array, struct o record, set,
N Sui client, il codice per registrare i tipi con il registro di tipi remotable viene generato
automaticamente quando si importa un documento WSDL. Per i server, i tipi
remotable vengono registrati automaticamente quando si registra un’interfaccia che
li utilizza. È necessario aggiungere esplicitamente il codice per registrare tipi solo se
si desidera specificare il namespace o il nome del tipo invece di utilizzare i valori
generati in automatico.
Il registro dei tipi remotable ha due metodi che è possibile utilizzare per registrare i
tipi: RegisterXSInfo e RegisterXSClass. Il primo (RegisterXSInfo) permette di registrare
un array dinamico o un’altra definizione di tipo. Il secondo (RegisterXSClass) serve
per la registrazione di classi remotable che vengono definite per rappresentare altri
tipi.
Se si utilizzano array dinamici o tipi eneumerati, il registro delle chiamate può
ottenere le informazioni di cui ha bisogno dalle informazioni di tipo generate dal
compilatore. Così, ad esempio, l’interfaccia può utilizzare un tipo come quello
seguente:
type
TDateTimeArray = array of TXSDateTime;
Questo tipo viene registrato automaticamente quando si registra l’interfaccia
richiamabile. Tuttavia, se si desidera specificare il namespace in cui il tipo è definito o
il nome del tipo, è necessario aggiungere del codice per registrare il tipo
esplicitamente utilizzando il metodo RegisterXSInfo del registro dei tipi remotable.
La registrazione va nella sezione initialization della unit in cui viene dichiarato
l’array dinamico:
RemTypeRegistry.RegisterXSInfo(TypeInfo(TDateTimeArray), MyNameSpace, 'DTarray', 'DTarray');
Il primo parametro di RegisterXSInfo è l’informazione di tipo per il tipo che si sta
registrando. Il secondo parametro è l’URI del namespace per il namespace in cui il
tipo è definito. Se si omette questo parametro o si fornisce una stringa vuota, il
registro genera automaticamente un namespace. Il terzo parametro è il nome del tipo
come appare nel codice nativo. Se si omette questo parametro o si fornisce una
stringa vuota, il registry utilizza il nome del tipo prelevandolo dalle informazioni di
tipo fornite come primo parametro. L’ultimo parametro è il nome del tipo come
appare nei documenti WSDL. Se si omette questo parametro o si fornisce una stringa
vuota, il registro utilizza il nome del tipo nativo (il terzo parametro).
La registrazione di una classe remotable è simile, tranne per il fatto che si fornisce un
riferimento di classe invece che un puntatore alle informazioni di tipo. Ad esempio,
la riga seguente deriva dalla unit XSBuiltIns. Essa registra TXSDateTime, un
discendente di TRemotable che rappresenta valori di tipo TDateTime:
RemClassRegistry.RegisterXSClass(TXSDateTime, XMLSchemaNameSpace, 'dateTime', '',True);
Il primo parametro è il riferimento di classe per la classe remotable che rappresenta il
tipo. Il secondo è un identificativo uniforme di risorse (URI) che identifica in modo
univoco il namespace della nuova classe. Se si fornisce una stringa vuota, il registro
genera automaticamente un URI. Il terzo e il quarto parametro specificano i nomi
nativi ed esterni del tipo di dati che la classe rappresenta. Se si omette il quarto
parametro, il registro dei tipi utilizza il terzo parametro per entrambi i valori. Se si
fornisce una stringa vuota per entrambi i parametri, il registro utilizza il nome della
classe. Il quinto parametro indica se il valore delle istanze della classe può essere
trasmesso come stringa. Volendo è possibile aggiungere un sesto parametro (non
visualizzato qui) per controllare in che modo dovrebbero essere rappresentati nei
pacchetti SOAP più riferimenti alla stessa istanza dell’oggetto.
N Se non si include una direttiva stored o se si assegna un qualsiasi altro valore alla
direttiva stored (anche una funzione che restituisce AS_ATTRIBUTE), la proprietà
viene codificata come un nodo piuttosto che come un attributo.
Se il valore del nuovo discendente TRemotable rappresenta un tipo scalare in un
documento WSDL, come classe di base si dovrebbe utilizzare invece TRemotableXS.
TRemotableXS è un discendente di TRemotable che introduce due metodi per la
conversione della nuova classe nella sua rappresentazione di stringa. Implementare
questi metodi ridefinendo i metodi XSToNative e NativeToXS.
Per alcuni tipi scalari di XML comunemente usati, la unit XSBuiltIns definisce e
registra automaticamente una serie di classi remotable. Queste sono elencate nella
seguente tabella:
Dopo avere definito una classe remotable, la si deve registrare con il registro dei tipi
remotable, come descritto in “Registrazione di tipi non scalari” a pagina 38-5. Questa
registrazione avviene automaticamente su server quando si registra l’interfaccia che
utilizza la classe. Sui client, il codice per registrare la classe viene generato
automaticamente quando si importa il documento WSDL che definisce il tipo.
viene utilizzato per ogni chiamata di messaggio. Per evitare che l’oggetto remotable
venga liberato insieme al contesto di dati, modificarne la proprietà DataContext.
DestList.Clear;
DestList.Capacity := Length(Strings);
DestList.CaseSensitive := CaseSensitive;
DestList.Sorted := Sorted;
DestList.Duplicates := Duplicates;
for I := 0 to Length(Strings) - 1 do
DestList.Add(Strings[I]);
end;
Facoltativamente, si potrebbe volere registrare la nuova classe remotable in modo
che sia possibile specificare il suo nome di classe. Se non si registra la classe, essa
viene registrato automaticamente quando si registra l’interfaccia che la utilizza. Allo
stesso modo, se si registrano la classe ma non i tipi TDuplicates e TStringDynArray che
essa utilizza, essi vengono registrati automaticamente. Il codice seguente mostra
come registrare la classe TRemotableStringList e il tipo TDuplicates. TStringDynArray
viene registrato automaticamente perché è uno dei tipi array dinamici nativi
dichiarati nella unit Types.
Questo codice di registrazione va nella sezione initialization della unit in cui viene
definita la classe remotable:
RemClassRegistry.RegisterXSInfo(TypeInfo(TDuplicates), MyNameSpace, 'duplicateFlag');
RemClassRegistry.RegisterXSClass(TRemotableStringList, MyNameSpace, 'stringList', '',False);
“Creazione di applicazioni server per Internet” e nel Capitolo 34, “Utilizzo di Web
Broker”.
Per avviare SOAP application wizard, scegliere File|New|Other e sulla pagina
WebServices, fare doppio clic sull’icona Soap Server Application. Scegliere il tipo di
applicazione per Web server che si desidera utilizzare per il Web Service. Per
informazioni sui vari tipi di applicazioni per Web server, vedere “Tipi di applicazioni
per server Web” a pagina 33-6.
Spuntare la casella per indicare se si sta scrivendo un’applicazione multipiattaforma
o un’applicazione solo per Windows. Se si specifica per multipiattaforma, la
Component palette non visualizzerà alcun componente specifico per Windows.
Il wizard genera una nuova applicazione per Web server che include un modulo
Web che contiene tre componenti:
• Un componente invoker (THTTPSoapPascalInvoker). L’invoker effettua la
conversione tra i messaggi SOAP e i metodi di una qualunque interfaccia
richiamabile registrata nell’applicazione Web Service.
• Un componente dispatcher (THTTPSoapDispatcher). Il dispatcher risponde
automaticamente ai messaggi SOAP in arrivo e li invia all’invoker. È possibile
utilizzare la sua proprietà WebDispatch per identificare i messaggi di richiesta
HTTP a cui l’applicazione risponde. Ciò implica l’impostazione della proprietà
PathInfo per indicare la parte di percorso di un qualunque URL indirizzato
all’applicazione e della proprietà MethodType per indicare l’header del metodo per
i messaggi di richiesta.
• Un publisher WSDL (TWSDLHTMLPublish). Il publisher WSDL pubblica un
documento WSDL che descrive le interfacce e la modalità con cui chiamarle. Il
documento WSDL dice ai client come effettuare la chiamata all’applicazione Web
Service. Per i dettagli sull’utilizzo dell’editor WSDL, vedere “Generazione di
documenti WSDL per un’applicazione Web Service” a pagina 38-19.
Il dispatcher SOAP e il publisher WSDL sono componenti auto-dispatching. Questo
significa che essi si registrano automaticamente con il modulo Web in modo che
inoltri qualsiasi richiesta in arrivo indirizzata utilizzando le informazioni di percorso
che essi specificano nelle rispettive proprietà WebDispatch. Se si fa clic destro sul
modulo Web, è possibile vedere che, oltre a questi componenti auto-dispatching, ha
un singolo elemento di azione Web di nome DefaultHandler.
DefaultHandler è l’elemento di azione predefinito. Cioè, se il modulo Web riceve una
richiesta per la quale non è in grado di trovare un gestore (non è in grado di trovare
una corrispondenza con le informazioni di percorso), invia quel messaggio
all’elemento di azione predefinito. DefaultHandler genera una pagina web che
descrive il Web Service. Per modificare l’azione predefinita, modificare il gestore di
evento OnAction dell’elemento di azione.
N Se non si conosce l’URL del documento WSDL che si vuole importare, è possibile
cercarne uno facendo clic sul pulsante Search UDDI. Così facendo si avvia il browser
UDDI, descritto in “Esame dei Business services” a pagina 38-15.
T L’interprete della riga comandi include alcune opzioni che non sono disponibili
quando si utilizza l’importatore WSDL nell’IDE. Per i dettagli, consulatre la Guida in
linea alla voce WSDLIMP.
Presentazione di UDDI
UDDI è l’acronimo di Universal Description, Discovery, and Integration. È un
formato generico per la registrazione di servizi disponibili tramite web. Esistono
diversi registri pubblici, che danno informazioni sui servizi registrati disponibili.
Idealmente, questi registri pubblici contengono tutti le stesse informazioni, benché vi
possano essere piccole discrepanze dovute alle differenze temporali
nell’aggiornamento delle proprie informazioni.
I registri UDDI contengono informazioni su più di un Web Services. Il formato è
sufficientemente generale che può essere utilizzato per descrivere qualsiasi business
service. Le voci nel registro UDDI sono organizzate gerarchicamente; primo per
business, quindi per tipo di servizio e da ultimo per informazioni dettagliate
all’interno di un servizio. Queste informazioni dettagliate sono dette TModel. Un Web
Service, che può includere una o più interfacce richiamabili, compone un singolo
TModel. Pertanto, un singolo business service può includere più Web Services come
pure altre informazioni sul business. Ogni TModel può includere una vasta gamma di
informazioni, comprese le informazioni per contattare le persone all’interno del
business, una descrizione del servizio e dettagli tecnici come un documento WSDL.
Ad esempio, si consideri un’ipotetico business Widgets Inc. Questo business
potrebbe avere due servizi, produzione di widget e progettazione di widget custom.
Sotto il servizio di produzione di widget, si potrebbero trovare due TModels, uno per
la vendita di parti a Widgets Inc. e uno per l’ordinazione di widget. Ognuno di questi
potrebbe essere un Web Service. Sotto il servizio di progettazione di widget custom,
si potrebbe trovare che un Web Service per ottenere la valutazione dei costi e un altro
TModel, che non è un Web Service, che restituisce l’indirizzo di un sito Web per la
visualizzazione di progetti custom precedenti.
TSOAPHeader definisce due proprietà che sono utilizzate per rappresentare gli
attributi del nodo dello header SOAP. Questi sono MustUnderstand e Actor. Quando
l’attributo MustUnderstand è True, il destinatario di un messaggio che include lo
header deve essere in grado di riconoscerlo. Se il destinatario non è in grado di
interpretare un header con attributo MustUnderstand, deve annullare
l’interpretazione dell’intero messaggio. Un’applicazione può ignorare in tutta
sicurezza qualsiasi header che non è in grado di riconoscere se il loro attributo
MustUnderstand non è impostato. L’utilizzo di MustUnderstand è qualificato dalla
proprietà Actor. Actor è un URI che identifica l’applicazione a cui è indirizzata lo
header. Pertanto, ad esempio, se l’applicazione Service Web inoltra richieste a un
altro servizio per un’elaborazione ulteriore, alcuni header nei messaggi client
possono essere puntati a quell’altro servizio. Se tale header include l’attributo
MustUnderstand, non si dovrebbe abortire la richiesta anche se l’applicazione non è in
grado di interpretare lo header. L’applicazione è interessata solo a quegli header che
riportano come Actor la sua URL.
N Questa registrazione della classe header con il registro delle chiamate è aggiuntiva
rispetto alla registrazione della classe con il registro dei tipi remotable.
39
Operazioni con i socket
Capitolo 39
I protocolli di servizio
Prima di poter scrivere un server o un client di rete, occorre capire il servizio che
l’applicazione deve fornire o utilizzare. Molti servizi hanno protocolli standard che
devono essere supportati dall’applicazione di rete. Se si sta scrivendo
un’applicazione di rete per un servizio standard quale, ad esempio, HTTP, FTP, o
anche Finger o Time, occorre anzitutto capire i protocolli usati per comunicare con gli
altri sistemi. Consultare la documentazione su un determinato servizio che viene
fornito o utilizzato.
Se si sta fornendo un nuovo servizio per un’applicazione che comunica con altri
sistemi, il primo passo consiste nella progettazione del protocollo di comunicazione
per i server e i client di questo servizio. Quali messaggi vengono trasmessi? Come
vengono coordinati questi messaggi? Come sono codificate le informazioni?
Servizi e porte
La maggior parte dei servizi standard sono associati, per convenzione, con
determinati numeri di porta. Parleremo dettagliatamente dei numeri di porta nelle
pagine seguenti. Per il momento, si consideri il numero di porta come un codice
numerico per il servizio.
Se si sta implementando un servizio standard in applicazioni multipiattaforma, gli
oggetti socket di Linux mettono a disposizione dei metodi che consentono di cercare
il numero di porta del servizio. Se si sta fornendo un nuovo servizio, è possibile
specificare il numero di porta associato nel file /etc/services (o in un file equivalente
di una determinata distribuzione Linux). Per maggiori informazioni, consultare la
documentazione di Linux.
Una volta stabilita una connessione con un socket client, la connessione server è
praticamente indistinguibile da una connessione client. Entrambi i punti terminali
hanno le stesse funzionalità e ricevono gli stessi tipi di evento. Solo la connessione di
ascolto è fondamentalmente differente, in quanto possiede soltanto un singolo punto
terminale.
Connessioni client
Le connessioni client connettono un socket client posto sul sistema locale con un
socket server posto su un sistema remoto. Le connessioni client vengono iniziate dal
socket client. Per prima cosa, il socket client deve descrivere il socket server a cui
desidera connettersi. Il socket client quindi cerca il socket server e, una volta
localizzatolo, richiede una connessione. Il socket server può non completare la
connessione immediatamente. I socket server conservano una coda di richieste client
e completano le connessioni quando ne hanno il tempo. Quando il socket server
accetta la connessione client, trasmette al socket client una descrizione completa del
socket server al quale si sta connettendo e la connessione viene completata dal client.
Connessioni di ascolto
I socket server non localizzano i client. Formano invece “mezze connessioni” passive
che ascoltano le richieste del client. I socket server associano una coda alle loro
connessioni di ascolto; la coda registra le richieste di connessione client via via che
queste vengono inoltrate. Quando il socket server accetta una richiesta di
connessione dall’applicazione client, forma un nuovo socket per connettersi con
client, così da lasciare la connessione di ascolto aperta per accettare altre richieste
client.
Connessioni server
Nel momento in cui il socket di ascolto accetta una richiesta del client, il socket server
forma le connessioni server. Quando il server accetta la connessione, il client riceve
una descrizione del socket server che completa la connessione. La connessione viene
stabilita quando il socket client riceve questa descrizione e completa la connessione.
Per descrivere appieno una connessione socket occorre fornire gli indirizzi dei socket
su entrambe le estremità della connessione. È possibile descrivere l’indirizzo di
ciascun punto terminale del socket o indicandone l’indirizzo IP oppure l’host e il
numero della porta.
Prima di poter stabilire una connessione socket, è necessario descrivere
completamente i socket costituenti i relativi punti terminali. Alcune informazioni
sono reperibili dal sistema su cui è in esecuzione l’applicazione. Non è ad esempio
necessario descrivere l’indirizzo IP locale di un socket client dato che questa
informazione è disponibile da sistema operativo.
Le informazioni che occorre fornire dipendono dal tipo di socket col quale si sta
operando. I socket client devono descrivere il server con il quale vogliono
connettersi. I socket server di ascolto devono descrivere la porta che rappresenta il
servizio che forniscono.
Descrizione dell’host
L’host è il sistema che sta eseguendo l’applicazione contenente il socket. È possibile
descrivere l’host di un socket fornendo il suo indirizzo IP, che è una stringa di
quattro valori numerici (byte) nella notazione con punti standard di Internet, come
ad esempio
123.197.1.2
Un singolo sistema può supportare più di un indirizzo IP.
Gli indirizzi IP sono spesso difficili da ricordare e capita spesso di scriverli in modo
non corretto. Un’alternativa è quella di usare il nome dell’host. I nomi di host sono
alias dell’indirizzo IP che si vedono spesso negli Uniform Resource Locators (URL).
Sono stringhe che contengono un nome di dominio e un servizio, quale ad esempio
http://www.ASite.com
La maggior parte delle Intranet forniscono nomi host per gli indirizzi IP dei sistemi in
Internet. È possibile apprendere il nome dell’host associato a un qualsiasi indirizzo IP
(nel caso esista) impartendo il seguente comando dalla riga comandi:
nslookup IPADDRESS
in cui IPADDRESS è l’indirizzo IP a cui si è interessati. Se al proprio indirizzo IP
locale non è associato un nome di host e si vuole averne uno, si deve contattare
l’amministratore della rete. È comune per i computer fare riferimento a sé stessi con il
nome di localhost e con il numero IP 127.0.0.1.
I socket server non hanno bisogno di specificare un host. L’indirizzo IP locale può
essere letto dal sistema. Se il sistema locale supporta più di un indirizzo IP, i socket
server ascolteranno le richieste client simultaneamente su tutti gli indirizzi IP.
Quando un socket server accetta una connessione, il socket client fornisce l’indirizzo
IP remoto.
I socket client devono specificare l’host remoto fornendone il nome oppure
indicando l’indirizzo IP.
Associati con ciascuno di questi componenti socket ci sono gli oggetti socket, che
rappresentano il punto terminale di una connessione socket in uso. I componenti
socket usano gli oggetti socket per incapsulare le chiamate del socket server; pertanto
l’applicazione non deve preoccuparsi dei dettagli necessari per stabilire la
connessione o di gestire i messaggi del socket.
Se si vogliono personalizzare i dettagli delle connessioni che i componenti socket
creano per conto dell’utente, si possono usare le proprietà, gli eventi e i metodi degli
oggetti socket.
Eventi di errore
I socket client e server generano eventi di errore quando ricevono messaggi di errore
dalla connessione. È possibile scrivere un gestore di evento OnError che risponda a
questi messaggi di errore. Al gestore di evento vengono passate informazioni
relativamente a
• Quale oggetto socket ha ricevuto la notifica dell’errore.
• Ciò che il socket stava cercando di fare quando si è verificato l’errore.
• Il codice di errore fornito dal messaggio di errore.
Connessioni bloccanti
Quando la connessione è di tipo bloccante, il proprio socket deve iniziare a leggere o
a scrivere sulla connessione. Il socket non può aspettare passivamente una notifica
dalla connessione. Si usi un socket di tipo bloccante quando la propria estermità della
IV
Sviluppo di applicazioni COM
Part IV
Capitolo
N I componenti COM, come quelli sulle pagine ActiveX, COM+ e Servers della
Component palette, non possono essere utilizzati nelle applicazioni CLX. Questa
tecnologia è destinata al solo utilizzo in ambiente Windows e non è multipiattaforma.
COM è un modello software a componenti, indipendente dal linguaggio, che
consente l’interazione tra i componenti software e le applicazioni in ambiente
Microsoft. La caratteristica principale di COM è quella di consentire la
comunicazione tra componenti, tra applicazioni e tra client e server mediante
interfacce definite in modo univoco. Le interfacce consentono ai client di chiedere a
un componente COM, in fase di esecuzione, quali sono le funzionalità che supporta.
Per aggiungere altre funzionalità ai propri componenti è sufficiente aggiungere
un’ulteriore interfaccia, specifica per queste funzionalità.
Le applicazioni possono accedere alle interfacce dei componenti COM, presenti sullo
stesso computer su cui risiede l’applicazione o che esistono su un altro computer
della rete, mediante un meccanismo detto Distributed COM (DCOM). Per maggiori
informazioni sui client, sui server e sulle interfacce, consultare la sezione “Parti di
un’applicazione COM” a pagina 40-3.
Questo capitolo fornisce una panoramica concettuale della tecnologia sulla quale i
controlli Automation e ActiveX sono costruiti. Nei capitoli successivi vengono
riportate informazioni dettagliate sulla creazione degli oggetti Automation e dei
controlli ActiveX in Delphi.
Estensioni COM
Essendosi evoluto, COM si è esteso oltre i servizi COM. COM è la base di altre
tecnologie, come Automation, controlli ActiveX, Active Documents e Active
Directories. Per informazioni dettagliate sulle estensioni COM, consultare
“Estensioni COM” a pagina 40-10.
Inoltre, quando si lavora all’interno di vasti ambienti distribuiti, è possibile creare
oggetti COM transazionali. Prima di Windows 2000, tali oggetti non facevano parte
dell’architettura COM, ma piuttosto pensati per funzionare in ambiente Microsoft
Transaction Server (MTS). Con l’avvento di Windows 2000, tale supporto è stato
integrato in COM+. Gli oggetti transazionali sono descritti in dettaglio nel Capitolo
46, “Creazione di oggetti MTS o COM+”.
Delphi fornisce i wizard per implementare con facilità nell’ambiente Delphi
applicazioni che incorporano le tecnologie sopra menzionate. Per informazioni
dettagliate, consultare il paragrafo “Implementazione degli oggetti COM con i
wizard” a pagina 40-19.
Interfaccia COM Il modo in cui un oggetto espone i suoi servizi all’esterno dei client.
Un oggetto COM fornisce un’interfaccia per ciascun gruppo di
metodi correlati e proprietà. Si noti che le proprietà COM non sono
identiche alle proprietà degli oggetti della VCL. Le proprietà COM
utilizzano sempre metodi di accesso in lettura e scrittura.
COM Server Un modulo (EXE, DLL o OCX) che contiene il codice per un
oggetto COM. Le implementazioni dell’oggetto risiedono nei
server. Un oggetto COM implementa una o più interfacce.
COM Client Il codice che chiama le interfacce per ottenere i servizi richiesti dal
server. I client sanno che cosa acquisire dal server (tramite
l’interfaccia), ma non sanno come il server fornisce i servizi. Delphi
semplifica il processo di creazione di un client, consentendo
l’installazione nella Component palette di server COM (come un
documento Word o una presentazione PowerPoint) sotto forma di
componenti. Ciò consente di effettuare la connessione al server e di
agganciarne gli eventi mediante l’Object Inspector.
Interfacce COM
I client COM comunicano con gli oggetti tramite interfacce COM. Le interfacce sono
gruppi di routine correlate logicamente o semanticamente, che forniscono la
comunicazione tra un provider di un servizio (oggetto server) e i suoi client. Il modo
standard per illustrare un’interfaccia COM è mostrato nella Figura 40.1:
Figura 40.1 UnÊinterfaccia COM
Interface
COM
Object
• Per convenzione, gli identificatori dell’interfaccia COM iniziano con una lettera
maiuscola I, seguita poi da un nome simbolico che definisce l’interfaccia, come
IMalloc o IPersist.
• Le interfacce hanno un’identificazione univoca, chiamata Globally Unique
Identifier (GUID), che è un numero a 128 bit generato in modo casuale. I GUID
dell’interfaccia vengono chiamati Interface Identifiers (IID). Ciò elimina i conflitti
nei nomi tra versioni differenti di un prodotto o tra prodotti diversi.
• Le interfacce sono indipendenti dal linguaggio. È possibile usare qualsiasi
linguaggio per implementare un’interfaccia COM a condizione che supporti una
struttura di puntatori e possa chiamare, in modo esplicito o implicito, una
funzione tramite un puntatore.
• Le interfacce non sono di per sé oggetti; esse forniscono un modo per accedere ad
un oggetto. Pertanto, i client non accedono direttamente ai dati, ma attraverso un
puntatore di interfaccia. Windows 2000 aggiunge un’ulteriore strato di
indirezione, noto come interceptor, grazie a cui fornisce funzioni COM+ come
l’attivazione just-in-time e la centralizzazione degli oggetti.
• Le interfacce sono sempre ereditate dall’interfaccia fondamentale, IUnknown.
• Le interfacce possono essere reindirizzate da COM tramite i proxy per consentire
chiamate al metodo dell’interfaccia per la comunicazione tra thread, processi e
macchine collegate in rete, il tutto senza che gli oggetti client o server debbano
preoccuparsi del reindirizzamento. Per ulteriori informazioni consultare il
paragrafo “Server in-process, out-of-process e remoti” a pagina 40-6.
Server COM
Un server COM è un’applicazione o una libreria che fornisce servizi ad
un’applicazione client o a una libreria. Un server COM è costituito da uno o più
oggetti COM, dove un oggetto COM è un insieme di proprietà e di metodi.
I client non sanno come un oggetto COM esegue il suo servizio; l’implementazione
dell’oggetto rimane incapsulata. Un oggetto rende disponibili i suoi servizi tramite le
sue interfacce, come descritto precedentemente.
Inoltre, i client non hanno bisogno di sapere dove risiede un oggetto COM. COM
fornisce l’accesso trasparente indipendentemente della dislocazione dell’oggetto.
l’oggetto risieda nello stesso processo del client, in un altro processo nella macchina
client o in un’altra macchina della rete. I diversi tipi di server sono conosciuti come:
Server in process Una libreria (DLL) che viene eseguita nello stesso spazio di
processo del client, ad esempio, un controllo ActiveX
incorporato in una pagina Web visualizzata in Internet
Explorer o Netscape. Il controllo ActiveX viene, cioè, prelevato
nella macchina client e richiamato all’interno dello stesso
processo del browser Web.
Il client comunica con il server in-process usando chiamate
dirette all’interfaccia COM.
Server Un’altra applicazione (EXE) in esecuzione in un differente spazio
out-of-process di processo, ma sulla stessa macchina del client. Per esempio, un
(o server locale) foglio elettronico Excel incorporato in un documento di Word
sono due applicazioni separate in esecuzione sulla stessa
macchina.
Il server locale utilizza COM per comunicare con il client.
Server remoto Una DLL o un’altra applicazione in esecuzione su una macchina
diversa da quella del client. Per esempio, un’applicazione
database di delphi è collegata a un application server su
un’altra macchina della rete.
Il server remoto usa interfacce COM (DCOM) distribuite per
accedere e comunicare con l’application server.
Come mostrato nella Figura 40.3, per i server in-process i puntatori alle interfacce
dell’oggetto sono nello stesso spazio di processo del client, e pertanto COM effettua
chiamate dirette all’implementazione dell’oggetto.
Figura 40.3 Server in-processr
Client Process
In-process
Object
Client
Server
N Ciò non è sempre vero in ambiente COM+. Quando un client effettua una chiamata a
un oggetto in un contesto differente, COM+ intercetta la chiamata, facendo così in
modo che essa si comporti come una chiamata a un server out-of-process (vedere più
avanti) anche se il server è in-process. Per maggiori informazioni sulle operazioni con
COM+, consultare il Capitolo 46, “Creazione di oggetti MTS o COM+”
Come mostrato nella Figura 33.4, quando il processo si trova in un processo o in una
macchina diversi, COM usa un proxy per iniziare le chiamate della procedura
remota. Il proxy risiede nello stesso processo del client, quindi dal punto di vista del
In-process In-process
COM Stub
Proxy Object
RPC
Client
Remote machine
DCOM
RPC Remote machine
In-process
Stub
Object
La differenza tra i server out-of-process e quelli remoti sta nel tipo di comunicazione
usata dai processi. Il proxy usa COM per comunicare con un server out-of-process e
le interfacce COM (DCOM) distribuite per comunicare con una macchina remota.
DCOM trasferisce, in modo del tutto trasparente, una richiesta di un oggetto locale
ad un oggetto remoto in esecuzione su una macchina differente.
Il meccanismo di smistamento
Lo smistamento è il meccanismo che consente ad un client di effettuare chiamate a
oggetti remoti in un altro processo o su una macchina differente. Lo smistamento
• Prende un puntatore di interfaccia nel processo del server e rende disponibile un
puntatore proxy al codice del processo del client.
• Trasferisce gli argomenti di una chiamata all’interfaccia come passati dal client e li
colloca nello spazio di processo dell’oggetto remoto.
Per qualsiasi chiamata all’interfaccia, il client mette gli argomenti in uno stack ed
effettua una chiamata di funzione tramite il puntatore di interfaccia. Se la chiamata
all’oggetto non è in-process, questa viene passata al proxy. Il proxy chiude gli
argomenti in un pacchetto di smistamento e trasmette la struttura all’oggetto remoto.
Lo stub dell’oggetto apre il pacchetto, mette gli argomenti nello stack e chiama
Aggregazione
A volte, un oggetto server utilizza un altro oggetto COM per compiere alcune
funzioni. Per esempio, un oggetto gestione magazzino potrebbe fare uso di un
oggetto fattura separato per gestire le fatture dei clienti. Se l’oggetto gestione
magazzino desiderasse presentare l’interfaccia fattura ai client, ci sarebbe tuttavia un
problema: Sebbene un client dotato dell’interfaccia magazzino possa chiamare
QueryInterface per ottenere l’interfaccia fattura, al momento della creazione
dell’oggetto fattura non sapeva niente dell’oggetto gestione magazzino e non può
restituire un’interfaccia magazzino in risposta ad una chiamata a QueryInterface. Un
client che ha l’interfaccia fattura non può rimettersi in contatto con l’interfaccia
magazzino.
Per evitare questo problema, alcuni oggetti COM supportano l’aggregazione.
Quando l’oggetto gestione magazzino crea un’istanza dell’oggetto fattura, gli passa
una copia della propria interfaccia IUnknown. L’oggetto fattura può utilizzare quindi
quella interfaccia IUnknown per gestire tutte le chiamate a QueryInterface che
richiedono un’interfaccia, come l’interfaccia magazzino che egli non supporta.
Quando accade ciò, i due oggetti insieme sono definiti un aggregato. L’oggetto
fattura è detto oggetto interno, oppure l’oggetto contenuto dell’aggregato, e l’oggetto
magazzino è detto oggetto esterno.
Estensioni COM
Client COM
I client sempre possono interrogare le interfacce di un oggetto COM per determinare
cosa è i grado di fornire. Tutti gli oggetti COM consentono ai client di richiedere le
interfacce note. Inoltre, se il server supporta l’interfaccia IDispatch, i client possono
interrogare il server per ricevere informazioni sui metodi supportati dall’interfaccia.
Gli oggetti server non possono fare previsioni sull’utilizzo dei propri oggetti da parte
dei client. Analogamente, i client non hanno bisogno di sapere come (né tantomeno
dove) un oggetto fornisce i servizi; semplicemente si affidano agli oggetti server per
fornire i servizi che reclamizzano tramite le proprie interfacce.
Esistono due tipi di client COM, controller e contenitori. I controller lanciano il server
e interagiscono con esso tramite la sua interfaccia. Richiedono servizi dall’oggetto
COM oppure lo pilotano come processo separato. I contenitori ospitano i controlli
visuali o gli oggetti che appaiono nell’interfaccia utente del contenitore. Utilizzano
interfacce predefinite per trattare le questioni di visualizzazione con gli oggetti
server. È impossibile avere una relazione di contenitori su DCOM; ad esempio, i
controlli visuali che appaiono nell’interfaccia utente del contenitore devono essere
situati localmente. Ciò è dovuto al fatto che ci si aspetta che i controlli si traccino da
soli, il che richiede che abbiano accesso a risorse GDI locali.
Delphi semplifica lo sviluppo di client COM consentendo l’importazione di una
libreria di tipi o di un controllo ActiveX in un wrapper di componenti, in modo che
l’oggetto server assomigli agli altri componenti della VCL. Per maggiori informazioni
su questo processo, consultare il Capitolo 42, “Creazione di client COM”..
Estensioni COM
Originariamente COM è stato progettato per fornire una funzionalità centrale di
comunicazione e per consentirne l’ampliamento tramite le estensioni. COM ha esteso
poi la sua funzionalità centrale definendo set specialistici di interfacce per scopi
specifici.
L’elenco seguente riporta alcune delle estensioni dei servizi COM forniti attualmente.
Le sezioni successive descrivono questi servizi più in dettaglio..
Estensioni COM
Gli oggetti COM possono essere visuali o non visuali. Alcuni devono essere eseguiti
nello stesso spazio di processo dei loro client; altri possono essere eseguiti in processi
differenti o in macchine remote, purché gli oggetti forniscano il supporto per lo
smistamento. La Tabella 40.1 riassume i tipi di oggetti COM che è possibile creare,
Estensioni COM
indica se sono visuali o meno, gli spazi di processo in cui possono essere eseguiti,
come provvedono allo smistamento e se richiedono o meno una libreria di tipi.
Server Automation
Automation si riferisce alla possibilità di un’applicazione di controllare da
programma gli oggetti di un’altra applicazione, come una macro che può manipolare
più di un’applicazione contemporaneamente. L’oggetto server da manipolare viene
chiamato oggetto Automation, mentre Il client di un oggetto Automation viene
definito come Automation controller.
L’oggetto Automation può essere usato su server in-process, locali e remoti.
L’oggetto Automation è caratterizzato fondamentalmente da due aspetti:
• Definisce un set di proprietà e comandi e descrive le loro capacità attraverso le
descrizioni di tipo. Per ottenere ciò, occorre trovare il modo di fornire
informazioni sulle interfacce, sui metodi di interfaccia e sugli argomenti di questi
metodi. Normalmente queste informazioni sono disponibili in una libreria di tipi.
Automation server può generare anche informazioni di tipo dinamico, quando
interrogato tramite la sua interfaccia IDispatch (vedere di seguito).
• Rende i metodi accessibili in modo che le altre applicazioni possano usarli. Per
questo, implementa l’interfaccia IDispatch. Tramite questa interfaccia un oggetto
può esporre tutti i suoi metodi e tutte le sue proprietà. Tramite il metodo
principale di questa interfaccia è possibile richiamare i metodi dell’oggetto, dopo
che sono stati identificati attraverso le informazioni di tipo.
Estensioni COM
Spesso gli sviluppatori utilizzano Automation per creare e utilizzare oggetti OLE non
visuali che vengono eseguiti in tutti gli spazi di processo perché l’interfaccia
IDispatch di Automation rende automatico il processo di smistamento. Automation,
comunque, limita i tipi che è possibile utilizzare.
Per un elenco dei tipi che risultano validi per le librerie di tipi in generale, e per le
interfacce Automation in particolare, consultare “Tipi consentiti” a pagina 41-12.
Per informazioni sulla scrittura di un Automation server, consultare il Capitolo 44,
“Creazione di semplici server COM”.
Controlli ActiveX
ActiveX è una tecnologia che consente di creare componenti COM, in particolar
modo controlli, più compatti ed efficienti. Questa caratteristica risulta necessaria
specialmente per quei controlli da utilizzare nelle applicazioni Intranet e che,
affinché il client li possa utilizzare, devono essere scaricati.
I controlli ActiveX sono controlli visuali che vengono eseguito solo come server in-
process, e possono essere inglobati in un’applicazione contenitore di tipo controllo
ActiveX. Essi non sono di per sé applicazioni complete, ma possono essere pensati
come controlli OLE prefabbricati riutilizzabili in varie applicazioni. I controlli
ActiveX hanno un’interfaccia utente visibile e devono appoggiarsi a interfacce
predefinite per concordare le modalità di I/O e di visualizzazione con i contenitori
che li ospitano.
I controlli ActiveX fanno uso di Automation per esporre le loro proprietà, i loro
metodi e i loro eventi. Le funzionalità dei controlli ActiveX includono la possibilità di
Estensioni COM
Active Document
Gli Active Document (precedentemente definiti documenti OLE) costituiscono un set
di servizi COM, che supportano il collegamento e l’incorporamento, il drag-and-
drop, e l’editing visuale. Gli Active Document possono incorporare agevolmente dati
o oggetti di formati differenti, quali clip sonore come testo e bitmap.
A differenza dei controlli ActiveX, gli Active Document non sono limitati ai server in-
process; possono essere usati anche in applicazioni cross-process.
A differenza degli oggetti Automation, che raramente sono visuali, gli oggetti Active
Document possono essere attivi in modo visuale in un’altra applicazione. Pertanto,
essi vengono associati a due tipi di dati: i dati di presentazione, usati per visualizzare
l’oggetto su un monitor o su un dispositivo di output, e i dati nativi, usati per
modificare un oggetto.
Gli oggetti Active Document possono essere contenitori o server di documenti.
Anche se Delphi non fornisce un wizard automatico per la creazione di Active
Document, si può usare la classe TOleContainerdella VCL per supportare il
collegamento e l’incorporamento di Active Document esistenti.
È anche possibile usare TOleContainer come base per un contenitore Active
Document. Per creare oggetti per i server Active Document, si deve usare il COM
object wizard e aggiungere le interfacce appropriate, a seconda dei servizi che
l’oggetto ha bisogno di supportare. Per ulteriori informazioni sulla creazione e
sull’uso dei server Active Document, visitare il sito Web ActiveX di Microsoft.
Oggetti transazionali
Delphi utilizza il termine “oggetti transazionali”per fare riferimento a oggetti che
sfruttano i servizi per le transazioni, la sicurezza e la gestione delle risorse forniti da
Microsoft Transaction Server (MTS) (per le versioni di Windows precedenti a
Estensioni COM
Windows 2000) o da COM+ (per Windows 2000 e versioni successive). Questi oggetti
sono pensati per lavorare in vasti ambienti distribuiti.
I servizi per le transazione forniscono la solidità, garantendo sempre il
completamento delle attività o il ritorno alla stato di origine (il server non compie
mai un’attività solo parzialmente). I servizi per la sicurezza consentono di esporre
diversi livelli di supporto a classi diverse di client. La gestione delle risorse consente
ad un oggetto di gestire più client unendo le risorse o mantenendo attivi gli oggetti
soltanto quando sono utilizzati. Per consentire al sistema di fornire questi servizi,
l’oggetto deve implementare l’interfaccia IObjectControl. Per accedere ai servizi, gli
oggetti transazionale usano un’interfaccia di nome IObjectContext creata per loro
conto da MTS o da COM+.
In ambiente MTS, l’oggetto server deve essere incorporato in una libreria (DLL) che
va quindi installata nell’ambiente di esecuzione di MTS. Ovvero, l’oggetto server è
un server in-process che viene eseguito nel spazio del processo di esecuzione di MTS.
In ambiente COM+, questa restrizione non esiste in quanto tutte le chiamate COM
vengono indirizzate tramite un interceptor. Dal punto di vista dei client la differenza
tra MTS e COM+ è inesistente.
I server MTS o COM+ raggruppano oggetti transazionali che vengono eseguiti nello
stesso spazio di processo. In ambiente MTS, questo gruppo è definito un package
MTS, mentre in ambiente COM+ è definito un’applicazione COM+. Una singola
macchina può eseguire molti package MTS (o applicazioni COM+) diversi, dove
ciascuno di essi viene eseguito in un spazio di processo separato.
Dal punto di vista dei client, l’oggetto transazionale può apparire come qualsiasi
altro oggetto server COM. Il client non dovrà mai sapere nulla sulle transazioni, sulla
sicurezza oppure sull’attivazione just-in-time, a meno che non stia iniziando una
transazione per suo conto.
MTS e COM+ forniscono entrambi un strumento separato per amministrare gli
oggetti transazionali. Questo strumento consente di configurare oggetti in package o
applicazioni COM+, vedere package o applicazioni COM+ installate su un computer,
vedere o modificare gli attributi degli oggetti inclusi, esaminare e gestire transazioni,
rendere disponibili oggetti a client, e così via. In ambiente MTS, questo strumento è
MTS Explorer. In ambiente COM+ è il COM+ Component Manager.
Librerie di tipi
Le librerie di tipi forniscono un modo per ottenere ulteriori informazioni di tipo su
un oggetto che può essere determinato dall’interfaccia di un oggetto. Le informazioni
contenute nelle librerie di tipi forniscono i dati necessari sugli oggetti e sulle loro
interfacce, comunicando, per esempio, quali interfacce esistono nei diversi oggetti
(dato il CLSID), quali funzioni membro esistono in ciascuna interfaccia e quali
argomenti richiedono tali funzioni.
È possibile ottenere informazioni di tipo sottoponendo a query un’istanza in
esecuzione di un oggetto o caricando e leggendo le librerie di tipi. Con queste
informazioni si può implementare un client per l’uso di un oggetto desiderato,
sapendo specificamente quali funzioni membro occorrono, e che cosa passare loro.
Estensioni COM
I client degli Automation server, dei controlli ActiveX e degli oggetti transazionali si
aspettano che le informazioni di tipo siano disponibili. Tutti i wizard di Delphi
generano automaticamente una libreria di tipi, anche se questa è un’opzione
facoltativa per il COM object wizard. È possibile visualizzare o modificare queste
informazioni di tipo usando il Type Library Editor, come descritto nel Capitolo 41,
“Operazioni con le librerie di tipi”.
Questa sezione descrive che cosa contiene una libreria di tipi, come viene creata,
quando viene usata e come vi si può accedere. Per gli sviluppatori che vogliono
condividere le interfacce tra più linguaggi, la sezione termina con suggerimenti
sull’uso degli strumenti della libreria di tipi.
Estensioni COM
per scrivere interfacce e CoClass, consultare il Capitolo 41, “Operazioni con le librerie
di tipi”.
Interfaccia Descrizione
ITypeLib Fornisce i metodi per accedere alle descrizioni di una liberia di tipi.
ITypeLib2 Potenzia ITypeLib in modo da includere il supporto per stringhe di
documentazione, dati custom e dati statistici sulla libreria di tipi.
ITypeInfo Fornisce le descrizioni dei singoli oggetti contenuti in una libreria di tipi. Per
esempio, un browser usa questa interfaccia per estrarre le informazioni sugli
oggetti dalla libreria di tipi.
ITypeInfo2 Potenzia ITypeInfo in modo da accedere ad altre informazioni sulla libreria di
tipi, inclusi i metodi per accedere ad elementi dati custom.
ITypeComp Fornisce un modo rapido per accedere alle informazioni che servono al
compilatore per il collegamento ad un’interfaccia.
Estensioni COM
Il COM object wizard fornisce anche una implementazione per IDispatch nel caso si
specifichi che si sta creando un oggetto che supporta un discendente di IDispatch.
Come mostrato nella Figura 40.7, per gli oggetti Automation e Active Server, il
wizard implementa IUnknown e IDispatch, che forniscono lo smistamento automatico.
Figura 40.7 Interfaccia di un oggetto Automation
IUnknown
Automation
IDispatch Object
Come mostrato nella Figura 40.8, per gli oggetti controlli ActiveX e schede ActiveX, il
wizard implementa tutte le necessarie interfacce dei controlli ActiveX, IUnknown,
IDispatch, IOleObject, IOleControl, e così via. Per un elenco completo delle interfacce,
vedere la pagina di riferimento per l’oggetto TActiveXControl.
IDispatch
IOleObject
ActiveX
IOleControl Control
Object
IOleInPlaceObject
·
·
·
ISpecifyPropertyPages
Tabella 40.2 Wizard di Delphi per lÊimplementazione di oggetti COM, Automation e ActiveX
Wizard Interfacce implementate Cosa fa il wizard
COM server IUnknown (e IDispatch se si Esporta le routine per gestire la registrazione del server,
seleziona un’interfaccia la registrazione della classe, il caricamento e lo
predefinita che deriva da scaricamento del server, e l’istanziazione di un oggetto.
IDispatch) Crea e gestisce le class factory per gli oggetti
implementati nel server.
Prepara gli elementi del file di registro per quegli
oggetti che specificano il modello di threading
selezionato.
Dichiara i metodi che implementano una interfaccia
selezionata, e preparando la struttura base delle
implementazioni che il programmatore dovrà poi
completare.
Fornisce una libreria di tipi, se necessario.
Permette di selezionare un’interfaccia arbitraria,
registrata nella libreria di tipi, e di implementarla. Se lo
si fa, è necessario utilizzare una libreria di tipi.
Automation server IUnknown, IDispatch Esegue le funzioni di un wizard per server COM server
(descritto in precedenza), e inoltre:
• Implementa l’interfaccia specificata, duale o
dispatch.Fornisce, se occorre, il supporto lato server
per la generazione degli eventi.
• Fornisce automaticamente una libreria di tipi.
Tabella 40.2 Wizard di Delphi per lÊimplementazione di oggetti COM, Automation e ActiveX (continua)
Wizard Interfacce implementate Cosa fa il wizard
Active Server Object IUnknown, IDispatch, Esegue le funzioni di un wizard per oggetti Automation
(IASPObject) (descritto in precedenza) e
• genera facoltativamente una pagina .ASP che può
essere caricata in un browser Web. Lascia aperto il
Type Library editor per consentire, se occorre, la
modifica delle proprietà dell’oggetto e dei metodi.
• Fa emergere le caratteristiche intrinseche di ASP
sotto forma di proprietà in modo da semplificare il
reperimento delle informazioni relative
all’applicazione ASP e ai messaggi HTTP che l’hanno
avviata.
ActiveX Control IUnknown, IDispatch, Esegue le funzioni del wizard per Automation server
IPersistStreamInit, (descritti in precedenza), e inoltre:
IOleInPlaceActiveObject, • Genera una CoClass che corrisponde al controllo
IPersistStorage, IViewObject, della VCL su cui è basato il controllo ActiveX e che
IOleObject, IViewObject2, implementa tutte le interfacce ActiveX.
IOleControl,
IPerPropertyBrowsing, • Lascia aperto l’editor del codice sorgente in modo
IOleInPlaceObject, che si possa modificare la classe di implementazione.
ISpecifyPropertyPages
ActiveForm Stesse interfacce di ActiveX Esegue le funzioni del wizard per controlli ActiveX, e
Control inoltre:
• Crea un discendente di TActiveForm che sostituisce la
classe VCL preesistente nel wizard ActiveX control.
Questa nuova classe consente di progettare la Active
Form con le stesse modalità usate per progettare una
scheda in una applicazione Windows.
Transactional object IUnknown, IDispatch, Aggiunge al progetto corrente una nuova unit che
IObjectControl contiene la definizione dell’oggetto MTS o COM+.
Inserisce GUID proprietari nella libreria di tipi in modo
che Delphi possa installare correttamente l’oggetto,
lasciando aperto il Type Library editor per consentire la
definizione delle interfacce che l’oggetto espone ai
client. L’oggetto deve essere installato separatamente
dopo averlo generato.
Property Page IUnknown, IPropertyPage Crea una nuova pagina di proprietà che è possibile
progettare in Forms designer.
COM+ Event object Nessuna, per impostazione Crea un oggetto evento COM+ che è possibile definire
predefinita usando il Type Library editor. A differenza dei wizard
per gli altri oggetti, COM+ Event object wizard non crea
una unit di implementazione in quanto gli oggetti
evento non hanno implementazione (che è fornita
dalll’oggetto subscriber).
Type Library Nessuna, per impostazione Crea una nuova libreria di tipi e la associa al progetto
predefinita attivo.
ActiveX library Nessuna, per impostazione Crea un nuovo ActiveX o server COM DLL ed espone le
predefinita necessarie funzioni di esportazione.
Ogni wizard genera una unit di implementazione che implementa l’oggetto server
COM. L’oggetto server COM (l’oggetto di implementazione) discende da una delle
classi in DAX:
Tabella 40.3 Classi DAX di base per le classi di implementazione generate (continua)
Wizard Classe DAX di base Supporto ereditato
ActiveX Control TActiveXControl Quanto previsto da TAutoObject, più:
• Supporto per l’incorporazione in un
contenitore.
• Supporto per l’attivazione in loco.
• Supporto per proprietà e pagine di
proprietà.
• La capacità di delegare a un controllo con
finestra associato da lui creato.
ActiveForm TActiveFormControl Quanto previsto da TAutoObject, ad eccezione
del fatto che opera con un discendente di
TActiveForm invece che con un’altra classe di
controllo con finestra.
MTS object TMTSAutoObject Quanto previsto da TAutoObject, più:
• Supporto per l’interfaccia IObjectControl.
Property Page TPropertyPage • Supporto per le interfacce IUnknown e
ISupportErrorInfo.
• Supporto per aggregazione, gestione di
eccezioni OLE e convenzione di chiamata
safecall su interfacce duali.
• Supporto per l’interfaccia IPropertyPage.
In corrispondenza alle classi nella Figura 40.9 esiste una gerarchia di oggetti class
factory che gestiscono la creazione di questi oggetti COM. Il wizard aggiunge del
codice alla sezione di inizializzazione della unit di implementazione che istanzia la
class factory appropriata per la classe di implementazione.
I wizard generano anche una libreria di tipi e la relativa unit associata, il cui nome
assume il formato Project1_TLB. La unit Project1_TLB include le definizioni che
l’applicazione ha bisogno di utilizzare, le definizioni di tipo e le interfacce definite
nella libreria di tipi. Per maggiori informazioni sui contenuti di questo file, consultare
“Codice generato durante l’importazione delle informazioni di una libreria di tipi” a
pagina 42-5.
È possibile modificare l’interfaccia generata dal wizard utilizzando il Type Library
editor. Se si apportano modifiche, la classe di implementazione viene
automaticamente aggiornata in modo da tener conto di tali modifiche. Per
completare l’implementazione, sarà necessario solamente completare il corpo dei
metodi generati.
Capitolo
generato inizia con la libreria di tipi, poiché è in essa che si definiscono le proprietà e
i metodi che la libreria espone ai client: si modifica l’interfaccia della CoClass
generata dal wizard utilizzando il Type Library editor. Il Type Library editor
aggiorna automaticamente la unit di implementazione dell’oggetto, e tutto ciò che si
dovrà fare sarà completare il corp dei metodi generati.
Il Type Library editor di Delphi può anche essere utilizzato nello sviluppo di
applicazioni CORBA (Common Object Request Broker Architecture). Con i
tradizionali strumenti di sviluppo CORBA, è necessario definire, mediante il
linguaggio IDL (Interface Definition Language) di CORBA, le interfacce degli oggetti
in sede separata rispetto all’applicazione. Quindi, si esegue un programma di utilità
che genera, a partire da tali definizioni, il codice di stub e skeleton. Delphi è in grado
di generare stub, skeleton e il codice IDL in modo automatico. L’interfaccia utente
può essere modificata in modo molto semplice con il Type Library editor e Delphi
aggiorna automaticamente i file sorgenti opportuni.
N Il Type Library editor è utilizzato anche per definire le interfacce CORBA in progetti
che utilizzano i wizard CORBA Object o CORBA Data Module.
Il Type Library editor genera due tipi di file che rappresentano i contenuti della
libreria di tipi:
Tali parti sono illustrate nella Figura 41.1, che mostra il Type Library editor che
visualizza le informazioni di tipo per un oggetto COM di nome cyc.
Barra strumenti
La barra strumenti del Type Library editor, posizionata nella parte superiore del
Type Library editor, contiene i pulsanti che è possibile selezionare per aggiungere
alla libreria di tipi nuovi oggetti.
Il primo gruppo di pulsanti consente di aggiungere elementi alla libreria di tipi. Se si
fa clic su un pulsante della barra strumenti, nel pannello Object list appaiono le icone
relative a quel certo elemento. È quindi possibile personalizzarne gli attributi
utilizzando il pannello di destra. A seconda dell’icona selezionata, sulla destra
appaiono pagine di informazioni differenti.
La tabella seguente elenca gli elementi che è possibile aggiungere alla libreria di tipi:
Icone Significato
Una CoClass.
Una enumerazione.
Un alias.
Un record.
Icone Significato
Una union.
Un modulo.
Quando si seleziona nel pannello Object list uno degli elementi elencati in
precedenza, il secondo gruppo di pulsanti visualizza i membri che risultano validi
per quel certo elemento. Per esempio, quando si seleziona Interface, le icone Method
e Property nel secondo riquadro diventano attive poiché è possibile aggiungere alla
definizione di interfaccia metodi e proprietà. Quando si seleziona Enum, il secondo
gruppo di pulsanti cambia per visualizzare il membro Const, che è l’unico membro
valido per le informazioni di tipo Enum.
La tabella seguente elenca i membri che è possibile aggiungere agli elementi nel
pannello Object list:
Icone Significato
Dal nodo della libreria di tipi si diramano verso il basso gli elementi inclusi nella
libreria di tipi:
Figura 41.2 Pannello Object list
Barra di stato
Quando si effettua l’editing o il salvataggio di una libreria di tipi, la sintassi, gli errori
di traduzione e i messaggi di segnalazione vengono elencati nel pannello Status.
Per esempio, se si specifica un tipo IDL non supportato dal Type Library editor, viene
visualizzato un errore di sintassi. Per un elenco completo dei tipi supportati dal type
Library editor, consultare “Tipi consentiti” a pagina 41-12.
N Per informazioni più particolareggiate sulle varie opzioni che è possibile impostare
nelle pagine delle informazioni di tipo, consultare la Guida in linea del Type Library
editor.
È possibile utilizzare tutte le pagine delle informazioni di tipo per vedere o
modificare i valori in esse visualizzate. La maggior parte delle pagine organizza le
informazioni in una serie di controlli, consentendo sia l’immissione di valori sia la
loro selezione da un elenco, senza dover necessariamente conoscere la sintassi delle
dichiarazioni corrispondenti. In questo modo è possibile prevenire molti piccoli
errori come quelli di battitura durante la specifica di valori da una serie limitata.
Tuttavia, per alcuni potrebbe risultare più rapido immettere direttamente le
dichiarazioni. Per fare ciò, utilizzare la pagina Text.
Tutti gli elementi della libreria di tipi hanno una pagina Text che visualizza la sintassi
dell’elemento. Questa sintassi appare in un subset di IDL del Microsoft Interface
Definition Language, o in Delphi. Qualsiasi modifica apportata in altre pagine
dell’elemento si riflette nella pagina di testo. Se si aggiunge del codice direttamente
nella pagina Text, le modifiche si riflettono nelle altre pagine del Type Library editor.
Il Type Library editor genera errori di sintassi se si aggiungono identificatori che non
sono supportati attualmente dall’editor; l’editor supporta attualmente solamente
quegli identificatori che fanno riferimento al supporto per le libreria di tipi (non
supportano RPC né i costrutti utilizzati dal compilatore IDL di Microsoft per la
generazione di codice sorgente C++ o per il supporto del marshaling).
Interfacce
Una interfaccia descrive i metodi (e qualsiasi proprietà espressa come funzione ’get’ e
’ set’) per un oggetto a cui si deve accedere tramite una tabella virtuale delle funzioni
(vtable). Se un’interfaccia è contrassegnata come duale, eredita da IDispatch, e
l’oggetto può consentire sia il bound anticipato, mediante accesso a vtable, sia il
binding in esecuzione tramite OLE automation. Per impostazione predefinita, la
libreria di tipi contrassegna come duali tutte le interfacce aggiunte dall’utente.
N Se una proprietà è specificata come Write By Reference, vuol dire che viene passata
come puntatore piuttosto che per valore. Alcune applicazioni, come Visual Basic,
usano Write By Reference, se presente, per ottimizzare le prestazioni. Per passare la
proprietà solamente per riferimento invece che per valore, utilizzare il tipo di
proprietà By Reference Only. Per passare la proprietà per riferimento e per valore,
scegliere Read|Write|Write By Ref. Per richiamare questo menu, selezionare sulla
barra strumenti la freccia accanto all’icona della proprietà.
Una volta aggiunte le proprietà o i metodi utilizzando il pulsante della barra
strumenti o il menu contestuale del pannello Object list, se ne descrivono sintassi e
attributi selezionando la proprietà o il metodo e utilizzando le pagine delle
informazioni di tipo.
La pagina Attributes consente di assegnare alla proprietà o al metodo un nome e l’ID
di smistamento (in modo da poterla chiamare utilizzando IDispatch). Per le
proprietà, si deve assegnare anche un tipo. La firma della funzione viene creata
utilizzando la pagina Parameters, in cui è possibile aggiungere, rimuovere e
riordinare parametri, impostarne il tipo ed eventuali modificatori, e specificare i tipi
restituiti della funzione.
Dispinterface
Le interfacce vengono usate più frequentemente delle dispinterfaces per descrivere le
proprietà e i metodi di un oggetto. Le dispinterface sono accessibili solamente tramite
binding dinamico, mentre le interfacce possono disporre del bind statico tramite una
vtable.
È possibile aggiungere metodi e proprietà alle dispinterfaces secondo le stesse
modalità usate per le interfacce. Comunque, quando si crea una proprietà per una
dispinterface, non è possibile specificare il genere della funzione o i tipi dei
parametri.
CoClass
Una CoClass descrive un oggetto COM univoco che implementa un o più interfacce.
Quando si definisce una CoClass, è necessari specificare qual è l’interfaccia
implementata predefinita dell’oggetto e, facoltativamente, quale dispinterface è la
sorgente predefinita per gli eventi. Notare che nel Type Library editor non si
aggiungono proprietà o metodi a una CoClass. Proprietà e metodi vengono esposti ai
client dalle interfacce, che a loro volta vengono associate alle CoClass usando la
pagina Implements.
Definizioni di tipo
Enumerativi, alias, record e union dichiarano tutti tipi che potrebbero essere quindi
utilizzati altrove nella libreria di tipi.
Gli Enums sono costituiti da un elenco di costanti, ognuno delle quali deve essere
numerica. L’input numerico normalmente è un intero in formato decimale o
esadecimale. Per impostazione predefinita, il valore base è zero. È possibile
aggiungere costanti all’enumerativo selezionandolo nel pannello Object list e facendo
clic sul pulsante Const sulla barra strumenti, oppure selezionando il comando New|
Const nel menu contestuale del pannello Object list.
Moduli
Un modulo definisce un gruppo di funzioni, di solito una serie di punti d’ingresso
nelle DLL. Un modulo può essere definito
• Specificando sulla pagina degli attributi la DLL che esso rappresenta.
Tipi consentiti
In una libreria di tipi si utilizzano identificatori di tipo differenti a seconda del fatto
che si stia operando in IDL o in Delphi. Il linguaggio che si vuole utilizzare va
specificato nella finestra di dialogo Environment options.
I tipi elencati di seguito sono utilizzabili in una libreria di tipi per lo sviluppo di
applicazioni COM. La colonna Compatibile con Automation specifica se il tipo può
essere utilizzato o meno da un’interfaccia i cui flag Automation o Dispinterface sono
stati selezionati. Questi sono i tipi di cui COM è in grado di eseguire il marshaling
automatico tramite la libreria di tipi.
Il Type Library editor memorizza nel file generato di libreria di tipi (.TLB) le
informazioni di tipo in formato binario.
Se un tipo parametro viene specificato come tipo Pointer, di solito il Type Library
editor traduce tale tipo in un parametro variabile. Al salvataggio della libreria di tipi,
i flag IDL dell’ElemDesc associato al parametro variabile vengono contrassegnati
come IDL_FIN o IDL_FOUT.
Spesso, quando il tipo è preceduto da un Pointer, i flag IDL di ElemDesc non
vengono contrassegnati da IDL_FIN o IDL_FOUT. Oppure, nel caso delle
dispinterface, di solito i flag IDL non vengono utilizzati. In questi casi, accanto
all’identificatore della variabile si vedrà un commento come {IDL_None} o {IDL_In}.
Questi commenti vengono utilizzati durante il salvataggio della libreria di tipi per
contrassegnare i flag IDL in modo corretto.
SafeArrays
COM richiede che gli array siano passati mediante un tipo di dati speciale noto come
SafeArray. I SafeArray possono essere creati e distrutti chiamando speciali funzioni
COM dedicate, e tutti gli elementi di un SafeArray devono essere tipi consentiti e
compatibili con Automation. Il compilatore di Delphi è in grado di riconosce i
SafeArray di COM e chiamerà automaticamente le API di COM per creare, copiare e
distruggere i SafeArray.
Nel Type Library editor, un SafeArray deve specificare il tipo dei suoi elementi. Per
esempio, la linea seguente prelevata dalla pagina Text dichiara un metodo con un
parametro che è un SafeArray, il cui tipo dell’elemento è Integer:
procedure HighLightLines(Lines: SafeArray of Integer);
N Quando si lavora a un oggetto CORBA, nella pagina Text non si utilizza nessuno dei
due modi. È necessario utilizzare invece il linguaggio IDL di CORBA.
È possibile selezionare il linguaggio da utilizzare modificando le impostazioni della
finestra di dialogo Environment Options. Selezionare il comando Tools|
Environment Options e, nella pagina Type Library della finestra di dialogo,
specificare Pascal o IDL per l’opzione Language.
N La scelta della sintassi Delphi o IDL influenza anche le scelte disponibili nella pagina
degli attributi dei parametri.
Come di solito accade in tutte le applicazioni Delphi, gli identificatori usati nella
libreria di tipi non risentono dell’uso delle maiuscole o delle minuscole. Possono
essere lunghi fino a 255 caratteri e devono iniziare con una lettera o con un carattere
di sottolineatura (_).
{
methods:
[source] interface IMyInt);
dispinterface DMyInt;
};
ID: Integer;
StartDate: TDate;
EndDate: TDate;
Ownername: WideString;
Subtasks: safearray of Integer;
end;
La sintassi corrispondente in Microsoft IDL è
[uuid '{2MD36ABF-90E3-11D1-AA75-02C04FB73F42}',
helpstring "Task description"]
typedef struct
{
long ID;
DATE StartDate;
DATE EndDate;
BSTR Ownername;
SAFEARRAY (int) Subtasks;
} Tasks;
N Le modifiche apportate alle informazioni della libreria di tipi con il Type Library
editor possono essere riportatate automaticamente nella classe di implementazione
associata. Se si preferisce rivedere le modifiche prima che vengano aggiunte, occorre
accertarsi che la finestra di dialogo Apply Updates sia attiva. Per impostazione
predefinita è attiva ed è possibile modificarne l’impostazione se si seleziona
l’opzione “Display updates before refreshing” nella finestra di dialogo richiamata
mediante il comando Tools| Environment Options|Type Library. Per ulteriori
informazioni, consultare la sezione “Finestra di dialogo Apply Updates” a
pagina 41-27.
Viene richiesta l’aggiunta di un nome; ciò fatto, i membri del metodo per accesso
alla proprietà o il membro del metodo vengono aggiunti al pannello Object list.
2 Scrivere un nome per il membro.
Il nuovo membro contiene impostazioni predefinite, visibili sulle pagine Attributes,
Parameters e Flags, che è possibile modificare per adattarle al membro. Per esempio,
potrebbe essere necessario assegnare un tipo a una proprietà usando la pagina
Attributes. Se si sta aggiungendo un metodo, potrebbe essere necessario specificarne
i suoi parametri sulla pagina Parameters.
Come metodo alternativo, è possibile aggiungere proprietà e metodi scrivendo
direttamente nella pagina Text e usando la sintassi Delphi o IDL. Ad esempio, se si
sta operando con la sintassi Delphi, nella pagina Text di un’interfaccia è possibile
scrivere la seguente dichiarazione di proprietà:
Interface1 = interface(IDispatch)
[ uuid '{5FD36EEF-70E5-11D1-AA62-00C04FB16F42}',
version 1.0,
dual,
oleautomation ]
function AutoSelect: Integer [propget, dispid $00000002]; safecall; // Add this
function AutoSize: WordBool [propget, dispid $00000001]; safecall; // And this
procedure AutoSize(Value: WordBool) [propput, dispid $00000001]; safecall; // And this
end;
Se si sta operando in IDL, è possibile aggiungere la stessa dichiarazione nel seguente
modo:
[
uuid(5FD36EEF-70E5-11D1-AA62-00C04FB16F42),
version(1.0),
dual,
oleautomation
]
interface Interface1: IDispatch
{ // Add everything between the curly braces
[propget, id(0x00000002)]
HRESULT _stdcall AutoSelect([out, retval] long Value );
[propget, id(0x00000003)]
HRESULT _stdcall AutoSize([out, retval] VARIANT_BOOL Value );
[propput, id(0x00000003)]
HRESULT _stdcall AutoSize([in] VARIANT_BOOL Value );
};
Dopo aver aggiunto i membri ad una pagina del membro interfaccia, i membri
appaiono come elementi distinti nel pannello dell’elenco degli oggetti, ciascuno con
le proprie pagine di attributi, flag e parametri. È possibile modificare ogni nuova
proprietà o metodo selezionandolo nel pannello Object list e utilizzando queste
pagine, oppure apportando le modifiche direttamente nella pagina Text.
Se l’interfaccia è associata a una CoClass generata da un wizard, è possibile fare in
modo che il Type Library editor applichi le modifiche al file di implementazione
facendo clic sul pulsante Refresh sulla barra strumenti. Il Type Library editor
aggiungerà nuovi metodi alla classe di implementazione per aggiornarla in base ai
nuovi membri. In seguito, sarà possibile individuare i nuovi metodi nel codice
sorgente della unit di implementazione e scriverne il corpo in modo da completare
l’implementazione.
Se la finestra di dialogo Apply Updates è attiva, il Type Library editor notificherà
tutte le modifiche prima di aggiornare i sorgenti, segnalando anche eventuali
problemi.
N Se si aggiunge una CoClass a una libreria di tipi utilizzando la barra strumenti invece
di un wizard, si dovrà generare manualmente l’implementazione della CoClass e
aggiornarla ogni volta che si modifica un elemento in una delle interfacce della
CoClass. Non è possibile aggiungere membri a un CoClass in modo diretto. I membri
vengono aggiunti in modo implicito quando si aggiunge un’interfaccia alla CoClass.
N La libreria di tipi viene registrata come file binario separato (.TLB), ma viene anche
eseguito il link nel server (.EXE, DLL o .OCX).
• Register, per aggiungere un elemento della libreria di tipi nel registro di sistema di
Windows. L’operazione viene eseguita automaticamente se il server con cui è
associato il file .TLB è esso stesso registrato.
• Export, per salvare un file .IDL contenente le definizione dei tipi e delle interfacce
secondo la sintassi IDL.
Tutti i metodi precedenti eseguono un controllo della sintassi. Quando si aggiorna,
registra o salva la libreria di tipi, Delphi aggiorna automaticamente la unit di
implementazione di tutte le CoClass che sono state create usando un wizard.
Facoltativamente , se l’opzione Apply Updates del Type Library editor è attiva, è
possibile rivedere le modifiche prima che vengano confermate.
Capitolo
N La finestra di dialogo Import Type Library non crea wrapper di classe per oggetti
evento di COM+. Per scrivere un client che risponda agli eventi generati da un
oggetto evento di COM+, si deve creare da programma il convogliatore dell’evento.
Questo procedimento è descritto in “Gestione di eventi COM+” a pagina 42-16.
Per maggiori informazioni sul codice generato durante l’importazione di una libreria
di tipi, consultare “Codice generato durante l’importazione delle informazioni di una
libreria di tipi” a pagina 42-5.
Questo file contiene le dichiarazioni per gli elementi definiti nella liberia di tipi oltre
al wrapper di componenti generato per il controllo ActiveX.
N Questa parte della unit TypeLibName_TLB viene generata anche quando si utilizza il
Type Library editor o il programma di utilità TLIBIMP.
Se si vuole utilizzare un controllo ActiveX, oltre alle dichiarazioni descritte in
precedenza, è necessario avere anche il wrapper della VCL generato. Il wrapper della
VCL si occupa delle problematiche di gestione della finestra del controllo. Nella
finestra di dialogo Import Type Library dovrebbe essere stato generato anche un
wrapper VCL per le altre CoClass. Questi wrapper VCL semplificano il compito di
creare oggetti server e di chiamare i rispettivi metodi. Se ne raccomanda l’uso
specialmente se si desidera che l’applicazione client risponda agli eventi.
Le dichiarazioni per i wrapper VCL generati appaiono al fine della sezione interface.
I wrapper di componenti per i controlli ActiveX derivano da TOleControl. I wrapper
di componenti per gli oggetti Automation derivano da TOleServer. Il wrapper di
componente generato aggiunge le proprietà, gli eventi e i metodi esposti
dall’interfaccia della CoClass. È possibile utilizzare questo componente come
qualsiasi altro componente VCL.
N Per informazioni più aggiornate sul codice generato, fare riferimento ai commenti
nella unit TypeLibName_TLB generata automaticamente.
Wrapper ActiveX
Quando si ospitano controlli ActiveX, si dovrebbe utilizzare sempre un wrapper di
componenti in quanto esso integra la finestra del controllo nel framework della VCL.
Le proprietà e i metodi che un controllo ActiveX eredita da TOleControl consentono di
accedere all’interfaccia associata o di ottenere informazioni sul controllo. La maggior
parte delle applicazioni, comunque, non ha bisogno di utilizzarli. Per contro, si
utilizzerà il controllo importato secondo le stesse modalità usate per un qualsiasi
altro controllo VCL.
Di solito, i controlli ActiveX dispongono di una pagina di proprietà che consente di
impostarne le proprietà. Le pagine di proprietà sono simili agli editor di componenti
che alcuni componenti visualizzano quando si fa doppio clic su di essi nel Form
Designer. Per visualizzare la pagina di proprietà di un controllo ActiveX, fare clic
destro e scegliere l’opzione Properties.
Il modo in cui si utilizza la maggior parte dei controlli ActiveX importati è
determinato dall’applicazione server. Comunque, i controlli ActiveX utilizzano una
serie standard di notifiche quando rappresentano i dati di un campo di database. Per
informazioni su come utilizzare questi controlli ActiveX, consultare “Uso di controlli
ActiveX associati ai dati” a pagina 42-8.
Le modalità di chiamata dei metodi o di accesso alle proprietà sono analoghe a quelle
utilizzate per qualsiasi altro componente:
TServerComponent1.DoSomething;
La gestione degli eventi è semplice, poiché è possibile utilizzare l’Object Inspector
per scrivere i gestori di evento. Si noti, tuttavia, che il gestore di evento del
componente potrebbe avere parametri leggermente diversi da quelli definiti per
l’evento nella libreria di tipi. Specificatamente, i tipi puntatore (parametri var e
puntatori a interfaccia) vengono modificati in Variants. È necessario convertire
esplicitamente i parametri var nel tipo sottostante prima di assegnar loro un valore. I
puntatori a interfaccia possono essere convertiti nel tipo interfaccia appropriato
utilizzando l’operatore as. Per esempio, il codice seguente mostra un gestore di
evento per l’evento OnNewWorkBook di ExcelApplication. Il gestore di evento ha un
parametro che fornisce l’interfaccia di un’altra CoClass (ExcelWorkbook).
Comunque, l’interfaccia non viene passata come un puntatore all’interfaccia di
ExcelWorkbook, ma piuttosto come un OleVariant.
procedure TForm1.XLappNewWorkbook(Sender: TObject; var Wb:OleVariant);
begin
{ Note how the OleVariant for the interface must be cast to the correct type }
ExcelWorkbook1.ConnectTo((iUnknown(wb) as ExcelWorkbook));
end;
In questo esempio, il gestore di evento assegna il workbook a un componente
ExcelWorkbook, (ExcelWorkbook1). L’esempio dimostra come connettere un
wrapper di componenti a un’interfaccia esistente utilizzando il metodo ConnectTo. Il
metodo ConnectTo viene aggiunto al codice generato per il wrapper di componenti.
I server che hanno un oggetto applicazione espongono su quell’oggetto un metodo
Quit per consentire ai client di terminare la connessione. Quit espone di solito
funzionalità che sono equivalenti all’utilizzo del menu File per terminare
l’applicazione. Il codice per chiamare il metodo Quit viene generato nel metodo
Disconnect del componente. Se è possibile chiamare il metodo Quit senza parametri, il
wrapper di componenti ha anche una proprietà AutoQuit. AutoQuit fa in modo che il
controller chiami il metodo Quit nel momento in cui il componente viene liberato. Se
si vuole effettuare la disconnessione in un altro momento, oppure se il metodo Quit
richiede dei parametri, è necessario chiamarlo esplicitamente. Quit appare nel
componente generato come un metodo pubblico.
Per visualizzare il Data Bindings editor, fare clic destro sul controllo ActiveX
associato ai dati in modo da visualizzare un elenco di opzioni. Oltre alle opzioni di
base, apparirà anche la voce aggiuntiva Data Bindings. Selezionare l’elemento per
visualizzare il Data Bindings editor che elenca i nomi dei campi nel dataset e le
proprietà collegabili del controllo ActiveX.
Per collegare un campo a una proprietà,
1 Nella finestra di dialogo Data Bindings Editor di ActiveX, selezionare un campo e
un nome di proprietà.
Field Name elenca i campi del database e Property Name elenca le proprietà del
controllo ActiveX che possono essere collegate a un campo del database. Il dispID
della proprietà è racchiuso tra parentesi, ad esempio Value(12).
2 Fare clic su Bind e poi su OK.
N Se nella finestra di dialogo non appare alcuna proprietà, significa che il controllo
ActiveX non contiene proprietà associate ai dati. Per attivare l’associazione semplice
semplice di dati per una proprietà di un controllo ActiveX, utilizzare la libreria di tipi
come descritto in “Attivazione dell’associazione di dati semplici con la libreria di
tipi” a pagina 45-11.
L’esempio seguente illustra passo passo l’utilizzo di un controllo ActiveX associato ai
dati nel contenitore di Delphi. Questo esempio utilizza il controllo Calendar di
Microsoft che è disponibile se sul sistema è installato Microsoft Office 97.
1 Dal menu principale di Delphi, scegliere l’opzione Component|Import ActiveX
Control.
2 Selezionare un controllo ActiveX associato ai dati, come Microsoft Calendar
control 8.0 e modificare il nome della classe in TCalendarAXControl, quindi fare clic
su Install.
3 Nella finestra di dialogo Install, fare clic su OK per aggiungere il controllo al
package utente predefinito rendendo così il controllo disponibile sulla Palette.
4 Scegliere il comando Close All e, successivamente, File|New|Application per
iniziare una nuova applicazione.
5 Dalla pagina ActiveX della Component palette, trascinare sulla scheda un oggetto
TCalendarAXControl che è stato appena aggiunto alla Palette.
6 Dalla pagina Data Access, trascinare sulla scheda un oggetto DataSource e, dalla
pagina BDE, un oggetto Table.
7 Selezionare l’oggetto DataSource e impostarne la proprietà DataSet a Table1.
8 Selezionare l’oggetto Table e fare quanto segue:
• Impostare la proprietà DatabaseName a DBDEMOS.
• Impostare la proprietà TableName a EMPLOYEE.DB.
• Impostate la proprietà Active a True.
9 Selezionare l’oggetto TCalendarAXControl e impostarne la proprietà DataSource a
DataSource1.
2 Fare clic sui Microsoft Office Sample Automation Server Wrapper Components e
scegliere Remove.
La pagina Servers della Component palette non conterrà più nessuno dei server
forniti con Delphi. (Se non sono stati importati altri server, anche la pagina Servers
sarà rimossa.)
begin
FileName := OpenDialog1.FileName;
WordApplication1.Documents.Open(FileName,
EmptyParam,EmptyParam,EmptyParam,
EmptyParam,EmptyParam,EmptyParam,
EmptyParam,EmptyParam,EmptyParam);
WordApplication1.ActiveDocument.PrintOut(
EmptyParam,EmptyParam,EmptyParam,
EmptyParam, EmptyParam,EmptyParam,
EmptyParam,EmptyParam,EmptyParam,
EmptyParam,EmptyParam,EmptyParam,
EmptyParam,EmptyParam);
end;
end;
2 Compilare ed eseguire il programma. Facendo clic sul pulsante, Word richiederà
un file da stampare.
Connessione a un server
Prima di poter pilotare un Automation server mediante un’applicazione controller, è
necessario ottenere un riferimento ad una delle interfacce che esso supporta.
Solitamente si effettua una connessione a un server mediante la sua interfaccia
principale. Per esempio, ci si connettete a Microsoft Word tramite il componente
WordApplication.
Se l’interfaccia principale è un’interfaccia duale, è possibile utilizzare l’oggetto
creatore nel file TypeLibName_TLB.pas. Le classi creatore hanno lo stesso nome della
CoClass, col in più il prefisso “Co“. È possibile effettuare una connessione a un server
sulla stessa macchina chiamando il metodo Create, oppure a un server su una
macchina remota utilizzando il metodo CreateRemote. Poiché Create e CreateRemote
sono metodi di classe, per poterli chiamare non è necessaria un’istanza della classe
creatore.
MyInterface := CoServerClassName.Create;
MyInterface := CoServerClassName.CreateRemote('Machine1');
Create e CreateRemote restituiscono l’interfaccia predefinita per la CoClass.
N Occorre essere certi che il server abbia rilasciato la sua connessione al convogliatore
di eventi prima di poterlo liberare. Poiché non si sa come il server risponde alla
notifica di disconnessione iniziata da InterfaceDisconnect, ciò potrebbe trasformarsi in
una specie di gara nel caso si liberi il convogliatore di eventi immediatamente dopo
la chiamata. Il modo più semplice per evitare questo problema consiste nel fare in
modo che il convogliatore di eventi gestisca un proprio contatore dei riferimenti che
non venga decrementato finché il server non rilascia l’interfaccia del convogliatore di
eventi.
N Gli oggetti che effettuano una sottoscrizione a eventi COM+ devono essere installati
in un’applicazione di COM+.
Creazione di client per server che non hanno una libreria di tipi
Creazione di client per server che non hanno una libreria di tipi
Alcune vecchie tecnologie COM, come ad esempio OLE (object linking and
embedding), non forniscono informazioni di tipo in una libreria di tipi. Esse si
appoggiano invece ad una serie standard di interfacce predefinite. Per scrivere client
in grado di ospitare tali oggetti, è possibile utilizzare il componente TOleContainer.
Questo componente è presente sulla pagina System della Component palette.
TOleContainer si comporta come sito ospitante per un oggetto Ole2. Implementa
l’interfaccia IOleClientSite e, facoltativamente, IOleDocumentSite. La comunicazione
viene gestita utilizzando verbi OLE.
Per utilizzare TOleContainer,
1 Collocare un componente TOleContainer sulla scheda.
2 Impostare a True la proprietà AllowActiveDoc se si desidera ospitare un Active
document.
3 Impostare la proprietà AllowInPlace per indicare se l’oggetto ospitato deve
apparire nel TOleContainer o in una finestra separata.
4 Scrivete i gestori di evento per rispondere all’attivazione, alla disattivazione, allo
spostamento o al ridimensionamento dell’oggetto.
5 Per eseguire il bind dell’oggetto TOleContainer in fase di progetto, fare clic destro e
scegliere il comando Insert Object. Nella finestra di dialogo Insert Object, scegliere
un oggetto server da ospitare.
6 Per eseguire il bind dell’oggetto TOleContainer in fase esecuzione, esistono molti
metodi fra cui scegliere, a seconda di come si desidera identificare l’oggetto server.
Fra questi vi sono CreateObject, che richiede un id di programma,
CreateObjectFromFile, che richiede il nome di un file in cui è stato salvato l’oggetto,
CreateObjectFromInfo, che richiede un record contenente informazioni su come
creare l’oggetto, oppure CreateLinkToFile, che richiede il nome di un file in cui è
stato salvato l’oggetto e a cui si collega invece che incorporarlo.
7 Una volta collegato l’oggetto, è possibile accedere alla sua interfaccia utilizzando
la proprietà OleObjectInterface. Tuttavia, poiché la comunicazione con gli oggetti
Ole2 era basata su verbi OLE, molto più probabilmente si trasmetteranno comandi
al server utilizzando il metodo DoVerb.
8 Quando si desidera rilasciare l’oggetto server, chiamare il metodo DestroyObject.
L’assembly mscorlib.dll di .NET contiene i tipi che sono integrali per il Framework
.NET. Tutti gli assembly .NET devono referenziare l’assembly mscorlib,
semplicemente perché fornisce le funzionalità di base del Framework .NET sulla
piattaforma Microsoft Windows. Se si utilizzeranno tipi contenuti direttamente
nell’assembly mscorlib, sarà necessario eseguire il programma di utilità regasm su
mscorlib.dll. Il programma di installazione Delphi registra automaticamente
l’assembly mscorlib, nel caso non sia già registrato.
I componenti .NET possono essere distribuiti in due modi: in un’ubicazione globale e
condivisa di nome Global Assembly Cache (GAC), o nella stessa directory insieme
all’eseguibile. I componenti condivisi tra più applicazioni dovrebbero essere
distribuiti nel GAC. Poiché sono condivisi, e a causa delle possibilità di distribuzione
side-by-side del Framework .NET, agli assembly distribuiti nel GAC deve essere
assegnato un nome sicuro (cioè devono essere firmati numericamente). Il Framework
.NET contiene un programma di utilità di nome sn, utilizzato per generare le chiavi
di crittografia. Dopo aver generato le chiavi e aver generato il componente,
l’assembly viene installato nella cache globale degli assembly utilizzando un altro
programma di utilità .NET di nome gacutil.
Un componente .NET può essere distribuito anche nella stessa directory
dell’eseguibile non gestito. In questo scenario di distribuzione, non sono necessari la
chiave di sicurezza e il programma di utilità di installazione GAC. Tuttavia, il
componente deve essere ancora registrato utilizzando il programma di utilità
regasm. A differenza di un comune oggetto COM, la registrazione di un componente
.NET non lo renda accessibile a un’applicazione esterna alla directory in cui è
distribuito il componente.
{ Add an item }
dotNetArrayList.Add('A string item');
[assembly:AssemblyKeyFile("KeyFile.snk")]
namespace InteropTest1 {
public interface MyInterface {
void myMethod1();
void myMethod2(string msg);
}
// Restrict clients to using only implemented interfaces.
[ClassInterface(ClassInterfaceType.None)]
public class MyClass : MyInterface {
// The class must have a parameterless constructor for COM interoperability
public MyClass() {
}
// Implement MyInterface methods
public void myMethod1() {
MessageBox.Show("In C# Method!");
}
public void myMethod2(string msg) {
MessageBox.Show(msg);
}
}
}
L’assembly è contrassegnato con l’attributo AssemblyKeyFile. Ciò è necessario se il
componente deve essere distribuito nella Global Assembly Cache. Se si distribuisce il
componente nella stessa directory dell’eseguibile client non gestito, la chiave di
sicurezza non è necessaria. Questo componente di esempio sarà distribuito nella
GAC, pertanto prima verrà generato il file della chiave utilizzando la Strong Name
Utility del Framework SDK .NET:
sn -k KeyFile.snk
Eseguire questo comando dalla stessa directory in cui è situato il file sorgente C# .
Il passo successivo consiste nel compilare il codice utilizzando il compilatore C# .
Supponendo che il codice C# sia in un file di nome interoptest1.cs:
csc /t:library interoptest1.cs
Il risultato di questo comando è la creazione di un assembly di nome interoptest1.dll.
L’assembly ora deve essere registrato, utilizzando il programma di utilità regasm.
Regasm è concettualmente simile a tregsvr; esso crea delle voci nel registro di
Windows che consentono di esporre il componente ai client COM non gestiti.
regasm /tlb interoptest1.dll
L’utilizzo dell’opzione /tlb fa sì che regasm faccia due cose. Per prima cosa vengono
create le voci del registro per l’assembly. In secondo luogo, i tipi nell’assembly
vengono esportati in una libreria di tipi e la libreria di tipi viene anche registrata.
Infine, il componente viene distribuito nella GAC utilizzando il comando gacutil:
gacutil -i interoptest1.dll
L’opzione - i indica che l’assembly deve essere installato nella GAC. Il comando
gacutil deve essere eseguito ogni volta che si genera una nuova versione del
componente .NET. Successivamente, se si desidera rimuovere il componente dalla
GAC, eseguire nuovamenteil comando gacutil, usando questa volta l’opzione - u:
gacutil -u interoptest1
Capitolo
• Se si opera con IIS 3 o IIS 4, si utilizzerà Page Level Event Methods. In base a
questo modello, l’oggetto implementa i metodi, OnStartPage e OnEndPage, che
vengono chiamati al momento del caricamento e dello scarico dell’Active Server
Page. Quando l’oggetto viene caricato, ottiene automaticamente un’interfaccia
IScriptingContext che esso utilizza per accedere agli intrinsics di ASP. Queste
interfacce, a loro volta, sono rese accessibili come proprietà ereditate dalla classe
base (TASPObject).
• Se si opera con IIS5 o con una versione successiva, si utilizza il tipo Object Context.
In base a questo modello, l’oggetto recupera un’interfaccia IObjectContext che
utilizzerà per accedere agli intrinsics di ASP. Ancora una volta, queste interfacce
sono rese accessibili come proprietà nella classe base ereditata (TASPMTSObject).
Uno dei vantaggi derivanti da questo secondo approccio è che l’oggetto ha accesso
a tutti gli altri servizi disponibile tramite IObjectContext. Per accedere
all’interfaccia IObjectContext, è sufficiente chiamare GetObjectContext (definito
nella unit mtx) nel seguente modo:
ObjectContext := GetObjectContext;
Per maggiori informazioni sui servizi disponibili tramite IObjectContext, consultare
il Capitolo 46, “Creazione di oggetti MTS o COM+”..
È possibile chiedere al wizard di generare una semplice pagina ASP che ospiti il
nuovo Active Server Object. La pagina generata fornisce uno script ridotto (stilato in
VBScript) che crea l’Active Server Object in base al suo ProgID, e indica dove è
possibile chiamarne i metodi. Questo script chiama Server.CreateObject per avviare
l’Active Server Object.
N Sebbene lo script di test generato utilizzi VBScript, le Active Server Pages possono
anche essere scritte utilizzando Jscript.
All’uscita dal wizard, al progetto corrente viene aggiunta una nuova unit che
contiene la definizione dell’Active Server Object. Inoltre, il wizard aggiunge un
progetto di libreria di tipi e apre il Type Library editor. A questo punto è possibile
esporre le proprietà e i metodi dell’interfaccia mediante la libreria di tipi come
descritto nella sezione “Definizione dell’interfaccia di un oggetto COM” a
pagina 44-9. Durante la scrittura dell’implementazione delle proprietà e dei metodi
dell’oggetto, è possibile sfruttare gli intrinsics di ASP (descritti di seguito) per
ottenere informazioni sull’applicazione ASP e sui messaggi HTTP utilizzati per
comunicare con i browser.
Gli Active Server Object, come tutti gli altri oggetti Automation, implementano una
interfaccia duale, che supporta sia il binding anticipato (in compilazione) tramite la
Vtable sia il binding differito (in esecuzione) tramite l’interfaccia IDispatch. Per
maggiori informazioni sulle interfacce duali, consultare “Interfacce duali” a
pagina 44-13.
Application
All’oggetto Application si accede tramite un’interfaccia IApplicationObject. Esso
rappresenta l’intera applicazione ASP, definita come l’insieme di tutti i file .asp
contenuti in una directory virtuale e nelle sue subdirectory. L’oggetto Application
può essere condiviso da più client, e pertanto include il supporto per i blocchi che si
dovrebbe utilizzare per prevenire conflitti di thread.
IApplicationObject include quanto segue:
Request
All’oggetto Request si accede tramite un’interfaccia IRequest. Esso fornisce
informazioni sui il messaggio di richiesta HTTP che hanno provocato l’apertura
dell’Active Server Page.
Response
All’oggetto Response si accede tramite un’interfaccia IResponse. Consente di
specificare le informazioni sul messaggio di risposta HTTP restituito al browser
client.
IResponse include quanto segue:
Session
All’oggetto Session si accede tramite l’interfaccia ISessionObject. Consente di
memorizzare variabili che permangono per tutta la durata dell’interazione di un
client con l’applicazione ASP. Ovvero, queste variabili non vengono azzerate quando
il client si sposta da una pagina all’altra all’interno dell’applicazione ASP, ma
solamente quando il client esce completamente dall’applicazione.
ISessionObject include quanto segue:
Server
All’oggetto Server si accede tramite un’interfaccia IServer. Fornisce varie utilità per
scrivere l’applicazione ASP. IServer include quanto segue:
N Se si desidera rimuovere dal sistema l’oggetto Active Server Page, si dovrebbe per
prima cosa annullare la registrazione, eliminando dal file di registro di Windows gli
elementi ad esso relativi.
Capitolo
N Server COM e Automation non sono disponibili per l’uso in applicazioni CLX. This
technology is for use on Windows only and is not cross-platform.
Due wizard, in particolare, facilitano il processo di creazione di semplici oggetti
COM:
• COM Object wizard costruisce un oggetto COM leggero la cui interfaccia
predefinita deriva da IUnknown o che implementa un’interfaccia già registrata nel
sistema. Questa procedura guidata fornisce il livello di flessibilità massimo nei tipi
di oggetti COM che è possibile creare.
• Automation Object wizard crea un semplice oggetto Automation la cui interfaccia
predefinita deriva da IDispatch. IDispatch introduce un meccanismo standard di
marshaling e supporta il binding differito delle chiamate di interfaccia.
N L’istanziazione viene ignorata quando l’oggetto COM viene utilizzato solo come
server interno al processo.
Quando il wizard crea un nuovo oggetto COM, può avere uno dei seguenti tipi di
istanziazione:
Istanziazione Significato
Internal L’oggetto può essere creato solo internamente. Un’applicazione esterna non
può creare direttamente un’istanza dell’oggetto, anche se l’applicazione può
creare l’oggetto e passare ai client un’interfaccia per l’oggetto.
Single Instance Consente ai client di creare solamente una singola istanza dell’oggetto per
ciascun eseguibile (applicazione), e pertanto la creazione di più istanze produce
come risultato l’avvio di più istanze dell’applicazione. Ogni client ha la propria
istanza dedicata dell’applicazione server.
Multiple Specifica che più client possono creare istanze dell’oggetto nello stesso spazio
Instances di processo.
W Il gestore di marshaling free threaded viola le normali regole del marshaling COM
per fornire una maggiore efficienza. Lo si deve utilizzare con cautela. In particolare,
essa va aggregato solo con oggetti free threaded in un server in-process, e va
istanziato solo dall’oggetto che lo utilizza (non da un altro thread).
1 Nell’editor della libreria dei tipi, selezionare l’interfaccia duale per l’oggetto.
L’interfaccia predefinita dovrebbe avere lo stesso nome dell’oggetto, con
anteposta la lettera “I”. Per determinare l’interfaccia predefinita, nel Type Library
editor scegliere il separatore CoClass and Implements e controllare nell’elenco
delle interfacce implementate quella contrassegnata con “Default.”
2 Per esporre una proprietà lettura/scrittura, fare clic sul pulsante Property nella
barra degli strumenti; diversamente, fare clic sulla freccia accanto al pulsante
Property nella barra degli strumenti, quindi fare clic sul tipo di proprietà da
esporre.
3 Nel quadro Attributes, specificare il nome e il tipo di proprietà.
4 Nella barra degli strumenti, fare clic sul pulsante Refresh.
Nella unit di implementazione dell’oggetto viene inserita una definizione e delle
implementazioni di partenza per i metodi di accesso della proprietà.
5 Nella unit di implementazione localizzare i metodi di accesso per la proprietà. I
loro nomi hanno la forma Get_PropertyName e Set_PropertyName. Aggiungere il
codice che ottenga o imposti il valore della proprietà dell’oggetto. Questo codice
può chiamare semplicemente una funzione esistente all’interno dell’applicazione,
accedere a membri dati che si aggiungono alla definizione dell’oggetto, o
implementare la proprietà in altri modi.
N Il COM object wizard non genera codice di supporto per gli evento. Se si desidera che
l’oggetto generi gli eventi tradizionali, si dovrebbe utilizzare l’Automation object
wizard.
Affinché un oggetto generi eventi, è necessario svolgere le seguenti operazioni:
1 Nell’Automation wizard, selezionare la casella Generate event support code .
Il wizard crea un oggetto che include un’interfaccia Events oltre all’interfaccia
utente predefinita. Il nome di questa interfaccia Events ha la forma
ICoClassnameEvents. È un’interfaccia rivolta all’esterno (origine), cioè non si tratta
di un’interfaccia che l’oggetto implementa, ma un’interfaccia che i client devono
implementare e che viene chiamata dall’oggetto. (Ciò può essere verificato
selezionando la propria CoClass, andando alla pagina Implements, e osservando
che la colonna Source nell’interfaccia Events indica True.)
Oltre all’interfaccia Events, il wizard aggiunge l’interfaccia
IConnectionPointContainer per la dichiarazione della classe di implementazione e
aggiunge numerosi membri di classe per la gestione degli eventi. Fra questi nuovi
membri di classe, i più importanti sono FConnectionPoint e FConnectionPoints, che
implementano le interfacce IConnectionPoint e IConnectionPointContainer
utilizzando le classi incorporate della VCL. FConnectionPoint viene gestito da un
altro metodo aggiunto dal wizard, EventSinkChanged.
2 In the Type Library editor, select the outgoing Events interface for your object.
(This is the one with a name of the form ICoClassNameEvents)
3 Click the Method button from the Type Library toolbar. Each method you add to
the Events interface represents an event handler that the client must implement.
4 Nel quadro Attributes, specificare il nome del gestore di eventi, come MyEvent.
5 Nella barra degli strumenti, fare clic sul pulsante Refresh.
A questo punto l’implementazione dell’oggetto ha tutto il necessario per accettare
sink di eventi e mantenere un elenco di interfacce da chiamare quando se ne
verifica uno. Per chiamare queste interfacce, è possibile creare un metodo per
generare ogni evento sui client.
6 Nel Code Editor, aggiungere un metodo all’oggetto per generare ciascun evento.
Ad esempio,
unit ev;
interface
uses
ComObj, AxCtrls, ActiveX, Project1_TLB;
type
TMyAutoObject = class (TAutoObject,IConnectionPointContainer, IMyAutoObject)
private
.
.
.
public
procedure Initialize; override;
procedure Fire_MyEvent; { Add a method to fire the event}
7 Implementare il metodo aggiunto all’ultimo punto in modo che esamini in
sequenza tutti i convogliatori di evento gestiti dal membro FConnectionPoint
dell’oggetto:
procedure TMyAutoObject.Fire_MyEvent;
var
I: Integer;
EventSinkList: TList;
EventSink: IMyAutoObjectEvents;
begin
if FConnectionPoint <> nil then
begin
EventSinkList :=FConnectionPoint.SinkList; {get the list of client sinks }
for I := 0 to EventSinkList.Count - 1 do
begin
EventSink := IUnknown(FEvents[I]) as IMyAutoObjectEvents;
EventSink.MyEvent;
end;
end;
end;
8 Ogni volta che è necessario attivare l’evento in modo che i client siano informati
della sua occorrenza, chiamare il metodo che smista l’evento a tutti i sink di eventi:
if EventOccurs then Fire_MyEvent; { Call method you created to fire events.}
Interfacce di Automation
Interfacce di Automation
Per impostazione predefinita, il wizard Automation Object implementa l’interfaccia
duale, il che significa che entrambi gli oggetti Automation supportano
• Il binding differito in esecuzione, che avviene tramite l’interfaccia IDispatch.
Questa viene implementata come un’interfaccia di dispatch o dispinterface.
• Il binding anticipato in fase di compilazione, che avviene tramite una chiamata
diretta a una delle funzioni membro presenti nella tabella virtuale delle funzioni
dell’oggetto (VTable). Questo modo viene anche detto interfaccia custom.
N Qualsiasi interfaccia generata dal wizard COM object che non deriva da IDispatch
supporta solo chiamate VTable.
Interfacce duali
Una interfaccia duale è allo stesso tempo un’interfaccia custom e una dispinterface.
Viene implementata come un’interfaccia VTable di COM derivata da IDispatch. Per
quei controller che possono accedere all’oggetto solo in fase di esecuzione, è
disponibile la dispinterface. Per gli oggetti che possono avvalersi del binding in fase
di compilazione, viene utilizzata invece la più efficiente interfaccia VTable.
Le interfacce duali presentano i seguenti vantaggi combinati delle interfacce VTable e
delle dispinterface:
• Per le interfacce VTable, il compilatore esegue un controllo di tipo e fornisce
messaggi di errore più informativi.
• Per i controller Automation che non sono in grado di ottenere informazioni di
tipo, la dispinterface consente di accedere all’oggetto in esecuzione.
• Per i server in-process, tramite le interfacce VTable si ottiene il beneficio di un’alta
velocità di accesso.
• Per i server out-of-process, COM provvede ad eseguire il marshaling dei dati sia
per le interfacce VTable sia per le dispinterface. COM possiede
un’implementazione proxy/stub generica in grado di eseguire il marshaling delle
interfacce in base alle informazioni di tipo contenute in una libreria di tipi. Per
maggiori informazioni sul marshaling, consultare “Marshaling dei dati” a
pagina 44-15.
Il seguente diagramma illustra l’interfaccia IMyInterfacein un oggetto che supporta
un’interfaccia duale di nome IMyInterface. Le prime tre voci della VTable di
un’interfaccia duale fanno riferimento all’interfaccia IUnknown, la quattro voci
successive fanno riferimento all’interfaccia IDispatch e la voci rimanenti sono voci
COM per l’accesso diretto ai membri dell’interfaccia custom.
Interfacce di Automation
QueryInterface
IUnknown
AddRef
methods
Release
GetIDsOfNames
GetTypeInfo
IDispatch
methods GetTypeInfoCount
Invoke
Method1
IMyInterface Method2
methods
Remaining methods
of IMyInterface
Interfacce di dispatch
I controller Automation sono client che usano l’interfaccia IDispatch di COM per
accedere agli oggetti server di COM. Il controller deve per prima cosa creare
l’oggetto, quindi richiedere all’interfaccia IUnknown dell’oggetto un puntatore alla
propria interfaccia IDispatch. IDispatch tiene traccia internamente dei metodi e delle
proprietà tramite un identificatore di dispatch (dispID), che è un numero di
identificazione univoco per un membro dell’interfaccia. Attraverso IDispatch un
controller recupera le informazioni di tipo dell’oggetto per l’interfaccia dispatch e
quindi collega i nomi dei membri dell’interfaccia ai relativi dispID. Questi dispID
sono disponibili in fase di esecuzione e i controller li ottengono chiamando il metodo
GetIDsOfNames di IDispatch .
Una volta in possesso del dispID, il controller può chiamare il metodo Invoke, di
IDispatch per eseguire il codice appropriato (proprietà o metodo), compattando i
parametri per la proprietà o metodo in uno dei parametri di Invoke. Invoke ha una
segnatura fissata in fase di compilazione che gli consente di accettare un qualsiasi
numero di argomenti quando effettua una chiamata a un metodo dell’interfaccia.
L’implementazione di Invoke di un oggetto Automation deve quindi decompattare i
parametri, chiamare la proprietà o il metodo e stare pronta a gestire gli eventuali
errori che si potrebbero verificare. Al ritorno dalla proprietà o dal metodo, l’oggetto
passa il suo valore di ritorno al controller.
Questo modo di agire viene detto binding differito perché il controller esegue il
binding alla proprietà o al metodo in fase di esecuzione invece che in fase di
compilazione.
N Quando si importa una libreria di tipi, Delphi richiederà i dispID nel momento in cui
genera il codice, permettendo pertanto alle classi dei wrapper generate di chiamare
Invoke senza chiamare GetIDsOfNames. Questo fatto può incrementare notevolmente
le prestazioni di esecuzione dei controller.
Interfacce custom
Le interfacce custom sono interfacce definite dall’utente, che consentono ai client di
chiamare i metodi dell’interfaccia in base al loro ordine nella VTable e alla
conoscenza dei tipi degli argomenti. La VTable elenca gli indirizzi di tutte le
proprietà e i metodi che sono membri dell’oggetto, comprese le funzioni membro
dell’interfaccia che essa supporta. Se l’oggetto non supporta IDispatch, gli elementi
relativi ai membri delle interfacce custom dell’oggetto sono elencati nella VTable
subito dopo i membri di IUnknown.
Se l’oggetto possiede una libreria di tipi, è possibile accedere all’interfaccia custom
mediante il layout della sua VTable, che è ottenibile utilizzando il Type Library
editor. Se l’oggetto possiede una libreria di tipi e supporta anche IDispatch, un client
può anche ottenere i dispID dell’interfaccia IDispatch ed eseguire il bind direttamente
a un offset di VTable. Il programma per l’importazione delle librerie di tipi di Delphi
(TLIBIMP) recupera i dispID al momento dell’importazione, e pertanto i client che
utilizzano le dispinterface possono evitare di chiamare GetIDsOfNames;
l’informazione è già inclusa nella unit _TLB. Tuttavia, i client devono sempre
chiamare Invoke.
N Il primo metodo (che usa IDispatch) è l’unico disponibile nei server Automation. Il
secondo metodo è automaticamente disponibile su tutti gli oggetti che sono stati
creati con un wizard e che utilizzano una libreria di tipi.
Marshaling personalizzato
Di solito si usa il marshaling automatico nei server out-of-process e in quelli remoti
poiché è molto più semplice-COM provvede a ciò in modo automatico. Tuttavia, si
potrebbe voler implementare un marshaling personalizzato nel caso si pensi che ciò
possa incrementare le prestazioni del marshaling. Quando si implementa marshaling
personalizzato, è necessario supportare l’interfaccia IMarshal. Per maggiori
informazioni su questo approccio, consultare la documentazione di Microsoft.
N Se il server COM deve essere utilizzato sotto COM+, è necessario installarlo come
applicazione COM+ invece di registrarlo. L’installazione dell’oggetto in
un’applicazione COM+ provvede a gestire automaticamente la registrazione. Per
informazioni su come installare un oggetto in un’applicazione COM+, vedere
“Installazione di oggetti transazionali” a pagina 46-28.
Il controllo VCL
L’implementazione alla base di un controllo ActiveX in Delphi è un controllo della
VCL. Quando si crea un controllo ActiveX, per prima cosa è necessario progettare o
scegliere il controllo VCL da cui sarà generato il controllo ActiveX.
Il controllo VCL sottostante deve essere un discendente di TWinControl, in quanto
deve avere una finestra che possa apparentarsi con l’applicazione host. Quando si
create una Active form, questo oggetto è un discendente di TActiveForm.
Wrapper ActiveX
L’oggetto COM attuale è un oggetto wrapper ActiveX per il controllo VCL. Per le
Active form, questa classe è sempre TActiveFormControl. Per altri controlli ActiveX,
essa ha il nome della scheda TVCLClassX, in cui TVCLClass è il nome della classe del
controllo VCL. Pertanto, per fare un esempio, il nome del wrapper ActiveX per
TButton sarebbe TButtonX.
La classe wrapper discende da TActiveXControl che fornisce il supporto per le
interfacce ActiveX. Il wrapper ActiveX eredita questo supporto che gli consente di
trasmettere messaggi di Windows al controllo VCL e apparentare la sua finestra
nell’applicazione host.
Il wrapper ActiveX espone ai client le proprietà e i metodi del controllo VCL tramite
la sua interfaccia predefinita. Il wizard implementa automaticamente la maggior
parte delle proprietà e dei metodi della classe wrapper, delegando le chiamate ai
metodo al controllo VCL associato. Il wizard fornisce anche alla classe wrapper i
metodi che attivano gli eventi del controllo VCL sui client e assegna questi metodi
come gestori di evento nel controllo VCL.
La libreria di tipi
I wizard ActiveX control generano automaticamente una libreria di tipi che contiene
le definizioni di tipo per la classe wrapper, la sua interfaccia predefinita e tutte le
definizioni di tipo richieste. Queste informazioni di tipo forniscono un modo per il
controllo per rendere noti i propri servizi alle applicazioni host. È possibile
visualizzare e modificare queste informazioni utilizzando il Type Library editor.
Sebbene queste informazioni siano memorizzate in un file binario di libreria di tipi
separato (estensione .TLB), esse vengono anche compilate automaticamente nel
controllo ActiveX DLL sotto forma di risorsa.
Pagina di proprietà
Se si vuole, è possibile dotare il controllo ActiveX di una pagina di proprietà. La
pagina di proprietà consente all’utente di un’applicazione host (il client) di vedere e
modificare le proprietà del controllo. È possibile raggruppare più proprietà su una
sola pagina, oppure utilizza una pagina per fornire un’interfaccia per una
Nel wizard, selezionare il nome del controllo VCL che sarà sviluppato dal nuovo
controllo ActiveX. La finestra di dialogo elenca tutti i controlli disponibili,
discendenti da TWinControl e che non sono stati registrati come incompatibile con
ActiveX utilizzando la procedura RegisterNonActiveX.
T È una buona regola controllare i metodi che il wizard aggiunge alla classe del
wrapper ActiveX. Non solo si ha l’opportunià di controllare se il wizard ha omesso
qualche proprietà associata ai dati o metodi non compatibili con Automation, ma si
ha la possibilità di lascia di scoprire i metodi per i quali il wizard non è stato in grado
di generare un’implementazione. Tali metodi appaiono nell’implementazione con un
commento che indica il problema.
N Per maggiori informazioni su ciò che appare nella unit _TLB generata, consultare
“Codice generato durante l’importazione delle informazioni di una libreria di tipi” a
pagina 42-5.
Per esempio, si consideri una proprietà Caption, di tipo TCaption nell’oggetto VCL
associato. Per aggiungere questa proprietà all’interfaccia dell’oggetto, nel Type
Library editor si deve immettere quanto segue:
property Caption: TCaption read Get_Caption write Set_Caption;
Delphi aggiunge alla classe del wrapper le seguenti dichiarazioni:
function Get_Caption: WideString; safecall;
procedure Set_Caption(const Value: WideString); safecall;
Aggiunta di eventi
Il controllo ActiveX può scatenare eventi nel suo contenitore nello stesso modo in cui
un oggetto Automation scatena eventi nei client. Questo meccanismo è descritto in
“Esposizione di eventi ai client” a pagina 44-11.
Attributo Descrizione
Bindable Indica che la proprietà supporta l’associazione di dati. Se l’attributo
bindable è selezionato, quando il valore della proprietà viene
modificato, la proprietà lo notifica al proprio contenitore.
Request Edit Indica che la proprietà supporta la notifica di OnRequestEdit. Questo
consente al controllo di chiedere al contenitore se il valore può essere
modificato dall’utente.
Display Bindable Indica che il contenitore può mostrare agli utenti che la proprietà è
bindable.
Default Bindable Indica la singola proprietà bindable che meglio rappresenta l’oggetto.
Le proprietà che hanno l’attributo default bindable devono avere
anche l’attributo bindable. Non è possibile specificare l’attributo su
più di una proprietà di una dispinterface.
Immediate Bindable Consente alle singole proprietà bindable su una scheda di specificare
questo comportamento. Quando questo bit risulta impostato, tutte le
modifiche verranno notificate. Affinché questo bit attributo abbia
effetto, è necessario impostare i bit di attributo bindable e request
edit.
4 Fare clic sul pulsante Refresh sulla barra strumenti per aggiornare la libreria di
tipi.
Per poter collaudare un controllo con associazione di dati, è necessario anzitutto
registrarlo.
Ad esempio, per convertire un controllo TEdit in un controllo ActiveX associato ai
dati, si deve creare il controllo ActiveX a partire da TEdit e quindi cambiare i flag
della proprietà Text in Bindable, Display Bindable, Default Bindable e Immediate
Bindable. Dopo aver registrato e importato il controllo, è possibile utilizzarlo per
visualizzare i dati.
Normalmente, gli utenti accedono alla pagina di proprietà facendo clic con il tasto
destro sul controllo ActiveX e scegliendo l’opzione Properties.
Il processo di creazione di una pagina di proprietà è simile a quello della creazione di
una scheda.
1 Creare una nuova pagina di proprietà.
2 Aggiungere i controlli alla pagina di proprietà.
3 Associare i controlli sulla pagina di proprietà alle proprietà di un controllo
ActiveX.
4 Collegare la pagina di proprietà al controllo ActiveX.
N È anche possibile scrivere una pagina di proprietà che rappresenti più di un controllo
ActiveX. In questo caso, non si utilizza la proprietà OleObject. Invece, si deve scorrere
in sequenza un elenco delle interfacce, che è conservato nella proprietà OleObjects.
Aggiornamento dell’oggetto
Il metodo UpdateObject viene chiamato quando l’utente apporta dei cambiamenti ai
controlli sulla pagina di proprietà. Per impostare le proprietà del controllo ActiveX ai
loro nuovi valori, occorre aggiungere del codice al metodo UpdateObject.
In questo modo viene creata una base per la distribuzione che contiene il controllo
ActiveX in una libreria ActiveX (con estensione OCX). In base alle opzioni
specificate, questa base di distribuzione può contenere anche un file cabinet (con
estensione CAB) o un file di informazioni (con estensione INF).
La libreria ActiveX viene collocata nella Target Directory indicata al punto 2. Il file
HTML ha lo stesso nome del file di progetto ma con estensione HTM. Viene creato
nella HTML Directory indicata al punto 4. Il file HTML contiene un riferimento
URL alla libreria ActiveX presente alla posizione specificata al punto 3.
Attivazione just-in-time
La possibilità per un oggetto di essere disattivato e riattivato mentre i client
contengono riferimenti ad esso, viene chiamata attivazione just-in-time. Dal punto
di vista del client, solo una singola istanza dell’oggetto esiste dal momento in cui il
client lo crea al momento in cui lo rilascia definitivamente. In realtà, è possibile che
l’oggetto sia stato disattivato e riattivato molte volte. Avendo disattivato gli oggetti, i
client possono contenere riferimenti all’oggetto per un tempo illimitato senza
influenzare le risorse di sistema. Quando un oggetto viene disattivato, ne rilascia
tutte le risorse. Per esempio, se si disattiva un oggetto, potrebbe rilasciare la sua
connessione al database, consentendo così ad altri oggetti di utilizzarlo.
Per utilizzare la risorsa dello Shared Property manager, si deve per prima cosa usare
la funzione helper CreateSharedPropertyGroup per creare un gruppo di proprietà
condivise. Poi si possono scrivere tutte le proprietà in quel gruppo e leggerle da quel
gruppo. Utilizzando un gruppo di proprietà condivise, le informazioni di stato
vengono salvate tutte le volte che si disattiva un oggetto transazionale. Inoltre, le
informazioni di stato possono essere condivise tra tutti gli oggetti transazionali
installati nello stesso package MTS o nella stessa applicazione COM+. È possibile
installare oggetti transazionali in un package secondo la modalità descritta nel
paragrafo “Installazione di oggetti transazionali” a pagina 46-28.
Affinché gli oggetti condividano lo stato, devono essere eseguiti tutti nello stesso
processo. Se si desidera che istanze di componenti diversi condividano proprietà, è
necessario installarli nello stesso package MTS o nella stessa applicazione COM+.
Poiché c’è il rischio che gli amministratori spostino componenti da un package a un
altro, è più sicuro limitare l’uso di un gruppo di proprietà condivise a istanze di
oggetti definiti nella stessa DLL o nello stesso EXE.
Gli oggetti che condividono proprietà devono avere lo stesso attributo di attivazione.
Se due componenti nello stesso package hanno attributi di attivazione differenti,
normalmente non potranno condividere le proprietà. Per esempio, se un componente
è configurato per funzionare nel processo di un client e l’altro è configurato per
funzionare in un processo del server, i loro oggetti di solito saranno eseguiti in
processi diversi, anche se sono inclusi nello stesso package MTS o nella stessa
applicazione COM+.
L’esempio seguente mostra come aggiungere del codice per supportare lo Shared
Property manager in un oggetto transazionale:
implementation
uses ComServ;
{ Tfoobar }
procedure Tfoobar.OnActivate;
var
Exists: WordBool;
Counter: ISharedProperty;
begin
Group := CreateSharedPropertyGroup('MyGroup');
Counter := Group.CreateProperty('Counter', Exists);
end;
procedure Tfoobar.IncCounter;
var
Counter: ISharedProperty;
begin
Counter := Group.PropertyByName['Counter'];
Counter.Value := Counter.Value + 1;
end;
procedure Tfoobar.OnDeactivate;
begin
Group := nil;
end;
initialization
TAutoObjectFactory.Create(ComServer, Tfoobar, Class_foobar, ciMultiInstance, tmApartment);
end.
unit Unit1;
interface
uses
MtsObj, Mtx, ComObj, Project2_TLB;
type
Tfoobar = class(TMtsAutoObject, Ifoobar)
private
Group: ISharedPropertyGroup;
protected
procedure OnActivate; override;
procedure OnDeactivate; override;
procedure IncCounter;
end;
implementation
uses ComServ;
{ Tfoobar }
procedure Tfoobar.OnActivate;
var
Exists: WordBool;
Counter: ISharedProperty;
begin
Group := CreateSharedPropertyGroup('MyGroup');
Counter := Group.CreateProperty('Counter', Exists);
end;
procedure Tfoobar.IncCounter;
var
Counter: ISharedProperty;
begin
Counter := Group.PropertyByName['Counter'];
Counter.Value := Counter.Value + 1;
end;
procedure Tfoobar.OnDeactivate;
begin
Group := nil;
end;
initialization
TAutoObjectFactory.Create(ComServer, Tfoobar, Class_foobar, ciMultiInstance, tmApartment);
end.
Attributi di transazione
Ciascun oggetto transazionale ha un attributo di transazione che viene registrato nel
catalogo MTS o memorizzato con COM+.
Delphi consente di impostare l’attributo di transazione in fase di progetto utilizzando
il wizard dell’oggetto transazionale o il Type Library editor.
Ciascun attributo di transazione può essere impostato con questi parametri:
Requires a Gli oggetti devono essere eseguiti all’interno del campo d’azione di
transaction una transazione. Quando viene creato un nuovo oggetto, il suo
contesto eredita la transazione dal contesto del client. Se il client
non ha un contesto di transazione, ne crea automaticamente uno
nuovo.
Requires a new Gli oggetti devono essere eseguiti all’interno delle loro transazioni.
transaction Quando viene creato un nuovo oggetto, una nuova transazione
viene creata automaticamente per l’oggetto, indipendentemente
dal fatto che il suo client abbia una transazione. Un oggetto non
viene mai eseguito all’interno del campo d’azione della
transazione del suo client. Il sistema, invece, crea sempre
transazioni indipendenti per i nuovi oggetti.
Supports Gli oggetti possono essere eseguiti all’interno del campo d’azione
transactions delle transazioni del loro client. Quando viene creato un nuovo
oggetto, il suo contesto eredita la transazione dal contesto del
client. Questo attributo rende possibile la composizione di più
oggetti in un’unica transazione. Se il client non ha una
transazione, anche il nuovo contesto viene creato senza.
Transactions Gli oggetti non vengono eseguiti nel campo d’azione delle transazioni.
Ignored Quando si crea un nuovo oggetto, il suo contesto di oggetto viene
creato senza una transazione, indipendentemente da fatto che il
client abbia una transazione. Questa impostazione è disponibile
solamente in ambiente COM+.
Does not support Il significato di questa impostazione varia, in base al fatto che si
transactions stia installando l’oggetto in ambiente MTS o COM+. In ambiente
MTS, questa impostazione ha lo stesso significato di Transactions
Ignored in ambiente COM+. In ambiente COM+, non solo il
contesto dell’oggetto viene creato senza una transazione, ma
questa impostazione impedisce di attivare l’oggetto se il client ha
una transazione.
W Quando si imposta l’attributo di transazione, Delphi inserisce uno speciale GUID per
l’attributo specificato sotto forma di dato custom nella libreria di tipi. Questo valore
non è riconosciuto al di fuori di Delphi. Pertanto, ha un effetto solamente se si installa
l’oggetto transazionale dall’IDE. In alternativa, questo valore può essere impostato
da un amministratore di sistema utilizzando COM+ Component Manager o MTS
Explorer.
Quando una transazione viene completata o abbandonata, tutti gli oggetti che sono
coinvolti nella transazione vengono disattivati, causando la perdita di qualsiasi stato
acquisito nel corso della transazione. Questa operazione aiuta a garantire
l’isolamento della transazione e la coerenza del database; inoltre, libera le risorse del
server affinché siano utilizzate in altre transazioni. Il completamento di una
transazione consente di reclamare le risorse utilizzate da un oggetto al momento
della sua disattivazione. Per informazioni su come controllare quando viene
rilasciato lo stato di una oggetto, consultare la sezione seguente.
Il mantenimento dello stato su un oggetto richiede che l’oggetto rimanga attivato,
conservando risorse potenzialmente preziose come le connessione ad un database.
Inizio di transazioni
Le transazioni possono essere controllate in tre modi:
• Possono essere controllate dal client.
I client possono avere un controllo diretto sulle transazioni utilizzando un oggetto
contesto di transazione (utilizzando l’interfaccia ITransactionContext).
• Possono essere controllate dal server.
I server possono controllare le transazioni creando esplicitamente per esse un
oggetto contesto. Quando il server crea un oggetto in tal modo, l’oggetto creato
viene assimilato automaticamente nella transazione corrente.
• Le transazioni possono verificarsi automaticamente come risultato dell’attributo
di transazione dell’oggetto.
Gli oggetti transazionali possono essere dichiarati in modo che i rispettivi oggetti
siano sempre eseguiti all’interno di una transazione, indipendentemente da come
gli oggetti sono stati creati. In questo modo, gli oggetti non devono includere
alcuna logica per gestire le transazioni. Questa caratteristica riduce anche il carico
sulle applicazioni client. I client non dovranno iniziare una transazione
semplicemente perché il componente che stanno utilizzando lo richiede.
end;
procedure TAccountTransfer.Transfer(DebitAccountId, CreditAccountId: TGuid;
Amount: Currency);
var
CreditAccountIntf, DebitAccountIntf: IAccount;
begin
try
OleCheck(ObjectContext.CreateInstance(DebitAccountId,
IAccount, DebitAccountIntf));
OleCheck(ObjectContext.CreateInstance(CreditAccountId,
IAccount, CreditAccountIntf));
DebitAccountIntf.Debit(Amount);
CreditAccountIntf.Credit(Amount);
except
DisableCommit;
raise;
end;
EnableCommit;
end;
N Per le applicazioni che necessitano di una sicurezza più forte, gli oggetti contesto
implementano l’interfaccia ISecurityProperty, i cui metodi consentono il reperimento
dell’identificatore di sicurezza di Window (SID) del chiamante diretto e del creatore
dell’oggetto, oltre che del SID dei client che stanno utilizzando l’oggetto.
N Questi modelli di threading sono simili a quelli definiti dagli oggetti COM. Tuttavia,
poiché l’ambiente MTS e COM+ forniscono un maggiore supporto di base per i
thread, il significato di ciascun modello di threading qui è diverso. Inoltre, i modelli
free threading non si applicano agli oggetti transazionali a causa del supporto
residente delle attività.
Attività
Oltre al modello di threading, gli oggetti transazionali supportano la concorrenzialità
tramite le attività. Le attività sono registrate nel contesto dell’oggetto e l’associazione
tra un oggetto ed un’attività non può essere cambiata. Un’attività include l’oggetto
transazionale creato dal client base, oltre a tutti gli oggetti MTS creati da
quell’oggetto e dai suoi discendenti. Questi oggetti possono essere distribuiti in uno
o più processi, che vengono eseguiti su uno o più computer.
Per esempio, l’applicazione clinica per i medici può avere un oggetto transazionale
per aggiungere gli aggiornamenti e rimuovere i record ai vari database medici,
ciascuno rappresentato da un oggetto diverso. Questo record aggiunto può usare
anche altri oggetti, come un oggetto ricezione per registrare la transazione. Ciò
genera diversi oggetti transazionali che sono direttamente o indirettamente sotto il
controllo di un client base. Questi oggetti appartengono tutti alla stessa attività.
MTS o COM+ tengono la traccia del flusso d’esecuzione in ciascuna attività,
impedendo così che il parallelismo involontario danneggi lo stato dell’applicazione.
Questa caratteristica genera un singolo thread logico di esecuzione per tutta una serie
di oggetti potenzialmente distribuiti. Avendo un thread logico, le applicazioni sono
notevolmente più facili da scrivere.
Quando un oggetto transazionale viene creato da un contesto esistente, tramite un
oggetto contestuale di transazione o un contesto di oggetto, il nuovo oggetto diventa
un membro della stessa attività. In altre parole, il nuovo contesta eredita
l’identificatore di attività del contesto usato per crearlo.
applicazione utilizzata per contenere il componente della classe evento. Dopo avere
installato il componente, per ogni interfaccia di evento supportata dal componente si
deve creare una subscription. Dopo avere creato la subscription, selezionare quelle
classi evento (cioè i publisher) che si desidera siano ricevute dal componente. Un
componente subscriber può selezionare singole classi evento oppure tutte le classi
evento.
A differenza dell’oggetto evento di COM+, un oggetto subscription di COM+
contiene la propria implementazione di un’interfaccia di evento; questa è la
posizione in cui viene svolto il lavoro effettivo per rispondere all’evento nel
momentoin cui viene generato. Il COM+ Event Subscription Object wizard di Delphi
può essere utilizzato per creare un progetto che contiene un componente subscriber.
La figura seguente rappresenta l’interazione fra publisher, subscriber e il Catalog di
COM+:
Figura 46.1 Il sistema a eventi di COM+
Event
Event Class Subscription Interface
Publisher
Instantiates Delivers
Generate
event
event
Subscriber
COM+ Events
Event Object
Event
Interface
oppure è possibile fare clic sul pulsante Browse per attivare una lista di tutte le classi
evento attualmente installate nel Catalog di COM+. Anche la finestra di dialogo
COM+ Event Interface Selection contiene un pulsante Browse. È possibile utilizzare
questo pulsante per cercare e selezionare una libreria di tipi che contenga l’interfaccia
dell’evento. Quando si seleziona una classe evento esistente (o si immette la libreria),
il wizard darà la possibilità di implementare automaticamente l’interfaccia
supportata da quella classe evento. Se si seleziona la casella di controllo Implement
Existing Interface, il wizard creerà automaticamente tutti i metodi nell’interfaccia. È
possibile decidere di fare implementare al wizard le interfacce ereditate selezionando
la casella di controllo Implement Ancestor Interfaces. Tre interfacce dell’antenato non
vengono mai implementate dal wizard: IUnknown, IDispatch e IAppServer. Per
completare il wizard, immettere una breve descrizione del componente subscriber
dell’evento e fare clic su OK.
Quando un oggetto MTS vuole passare un riferimento a se stesso per un client o per
un altro oggetto (da usare, per esempio, come callback), prima chiamerà sempre
SafeRef e dopo passerà il riferimento restituito da questa chiamata. Un oggetto non
passerà mai un puntatore self, o un riferimento a se stesso ottenuto tramite una
chiamata interna a QueryInterface, ad un client o a qualsiasi altro oggetto. Una volta
che un tale riferimento è stato passato fuori dal contesto dell’oggetto, non è più un
riferimento valido.
La chiamata a SafeRef su un riferimento che è già sicuro restituisce il riferimento
stesso non modificato, tranne che il numero di riferimento sull’interfaccia non viene
incrementato.
Quando un client chiama QueryInterface su un riferimento sicuro, il riferimento
restituito al client è un riferimento sicuro.
Un oggetto che ottiene un riferimento sicuro deve rilasciare tale riferimento quando
non gli occorre più.
Per informazioni dettagliate su SafeRef, consultare l’argomento SafeRef nella
documentazione Microsoft.
Callback
Gli oggetti possono effettuare il callback ai client e agli altri oggetti transazionali. Per
esempio, è possibile avere un oggetto che crei un altro oggetto. La creazione di un
oggetto può passare un riferimento di se stesso all’oggetto creato; tale oggetto può
usare poi questo riferimento per chiamare l’oggetto creante.
Se si sceglie di usare i callback, si devono tenere presenti le seguenti restrizioni:
• Una chiamata di ritorno al client base o ad un altro package richiede la sicurezza a
livello di accesso sul client. Inoltre, il client deve essere un server DCOM.
• I firewall intermedi potrebbero bloccare le chiamate di ritorno al client.
• Il lavoro fatto sul callback viene eseguito nell’ambiente dell’oggetto da chiamare.
Può far parte della stessa transazione, di una transazione diversa o di nessuna
transazione.
• In ambiente MTS, l’oggetto che crea deve chiamare SafeRef e passare il riferimento
restituito all’oggetto creato in modo da effettuare una chiamata di ritorno a se
stesso.
Indice I-1
Add New Web Service wizard 38-12 ADT, campi 25-24, 25-24 – 25-26
Add to Interface, comando 30-17 campi persistenti 25-25 – 25-26
Add To Repository, comando 8-21 esplicitazione 20-24
Add, metodo visualizzazione 20-24, 25-24 – 25-25
colonne persistenti 20-21 ADTG, file 27-15
menu 9-45 AfterApplyUpdates, evento 29-33, 31-8
stringhe 5-20 AfterCancel, evento 24-22
AddAlias, metodo 26-26 AfterClose, evento 24-4
AddFieldDef, metodo 24-41 AfterConnect, evento 23-3, 30-28
AddFontResource, funzione 18-15 AfterDelete, evento 24-21
AddIndexDef, metodo 24-41 AfterDisconnect, evento 23-4, 30-29
AddObject, metodo 5-22 AfterDispatch, evento 34-6, 34-9
AddParam, metodo 24-56 AfterEdit, evento 24-18
AddPassword, metodo 26-23 AfterGetRecords, evento 31-8
_AddRef, metodo 4-15, 4-18, 4-20 AfterInsert, evento 24-19
AddRef, metodo 40-4 AfterOpen, evento 24-4
Address, proprietà AfterPost, evento 24-21
TSocketConnection 30-25 AfterScroll, evento 24-5
AddStandardAlias, metodo 26-26 aggancio 7-4
AddStrings, metodo 5-21 AggFields, proprietà 29-14
ADO 24-2, 27-1, 27-2 aggiornamenti batch 27-12 – 27-15
componenti 27-1 – 27-21 annullamento 27-15
panoramica 27-1 – 27-2 applicazione 27-15
datastore 27-2, 27-4 aggiornamenti in cache 29-16 – 29-26
distributori di risorse 46-6 ADO 27-12 – 27-15
distribuzione 18-7 annullamento 27-15
provider 27-3, 27-4 applicazione 27-15
transazioni implicite 27-7 BDE 26-34 – 26-50
ADO, comandi 27-7 – 27-8, 27-18 – 27-21 aggiornamento dataset a sola lettura 26-11
annullamento 27-19 applicazione 26-11, 26-36 – 26-40
asincroni 27-19 tabelle multiple 26-42, 26-47
esecuzione 27-19 gestione degli errori 26-40 – 26-41
iterazione 23-14 dataset client 19-11 – 19-15, 29-17, 29-21 – 29-26
parametri 27-20 – 27-21 aggiornamento dataset a sola lettura 26-11
reperimento dati 27-20 applicazione 26-11, 29-22 – 29-23
specifica 27-18 tabelle multiple 26-42, 26-47
ADO, connessioni 27-2 – 27-9 errori di aggiornamento 29-24 – 29-26, 31-12
asincrone 27-5 transazioni 23-7
connessione a datastore 27-2 – 27-7 oggetti update 29-20
esecuzione di comandi 27-6 panoramica 29-17 – 29-19
eventi 27-8 – 27-9 provider 31-8
time out 27-5 – 27-6 relazioni master/detail 29-19
ADO, dataset 27-9 – 27-17 aggiornamenti in cascata 31-6
aggiornamenti batch 27-12 – 27-15 Aggregates, proprietà 29-12, 29-14
connessione 27-10 – 27-11 aggregati di manutenzione 29-12 – 29-14
esecuzione di comandi 27-21 specifica 29-12 – 29-13
file dati 27-15 – 27-16 aggregazione
prelievo asincrono 27-12 controlling Unknown 4-18, 4-20
ricerche basate su indice 24-29 interfacce 4-16, 4-18
ADO, oggetti 27-1 oggetto esterno 4-18
oggetto Connection 27-4 – 27-5 oggetto interno 4-18
RDS DataSpace 27-17 aggregazioni
Recordset 27-9, 27-11 COM 40-9
ADO, pagina (Component palette) 19-2, 27-1 dataset client 29-12 – 29-14
ADOExpress 27-1 aggregazioni di manutenzione 19-16
Index I-3
socket e 39-1 AppServer, proprietà 29-34, 30-17, 30-29, 31-3
Web Services 38-20 – 38-23 Appunti
applicazioni database 8-11 azzeramento della selezione 7-11
basate su file 27-15 – 27-16 oggetti grafici 12-3, 20-10
distribuite 8-12 Arc, metodo 12-4
distribuzione 18-6 architettura
XML e 32-1 – 32-11 applicazioni basate su BDE 26-1 – 26-2
applicazioni di servizio 8-4 – 8-9 applicazioni database 19-6 – 19-15, 26-1 – 26-2
codice di esempio 8-5, 8-7 client 30-4
debug 8-9 server 30-5
esempio 8-7 multi-tier 30-4, 30-5
applicazioni internazionali basata su Web 30-32
localizzazione 17-11 Web Broker, applicazioni server 34-3
applicazioni multi-thread array
sessioni 26-13, 26-30 – 26-31 safe 41-14
applicazioni multi-tier 30-1 – 30-44 array, campi 25-24
applicazioni Web 30-32 – 30-44 esplicitazione 20-24
creazione 30-33 – 30-34, 30-35 – 30-44 visualizzazione 20-24, 25-24 – 25-25
architettura 30-4, 30-5 as, operatore
callback 30-17 e Iinterface 4-16
componenti 30-2 – 30-3 interfacce 4-16
creazione 30-11 as, parola riservata
licenze del server 30-3 binding anticipato 30-30
vantaggi 30-2 AS_ApplyUpdates, metodo 31-3
applicazioni per console AS_ATTRIBUTE 38-6
VCL e 8-4 AS_DataRequest, metodo 31-3
applicazioni remote AS_Execute, metodo 31-3
TCP/IP 39-1 AS_GetParams, metodo 31-3
applicazioni server AS_GetProviderNames, metodo 31-3
architettura 30-5 AS_GetRecords, metodo 31-4
COM 40-9, 44-1 – 44-18 AS_RowRequest, metodo 31-4
interfacce 39-2 ASCII, tabelle 26-5
multi-tier 30-5 – 30-11, 30-12 – 30-18 ascolto connessioni 39-3, 39-7
registrazione 30-22 chiusura 39-8
servizi 39-1 ascolto di connessioni 39-9
Web Services 38-9 – 38-20 ASP 40-10, 40-13, 43-1 – 43-9
applicazioni single-tier 19-3 confronto con ActiveX 43-7
applicazioni three-tier Vedi applicazioni multi-tier confronto con Web Broker 43-1
applicazioni two-tier 19-3, 19-9, 19-13, 29-38 documenti HTML 43-1
applicazioni Web generazione di pagine 43-3
ActiveX 45-16 – 45-18 limiti nelle prestazioni 43-1
client multi-tier 30-33 linguaggio script 40-13, 43-3
database 30-32 – 30-44 progettazione della UI 43-1
oggetto 34-3 ASP, intrinsics 43-3 – 43-7
Apply Updates, finestra di dialogo 41-27 accesso 43-2 – 43-3
Apply, metodo 26-48 oggetto Application 43-4
ApplyRange, metodo 24-36 oggetto Request 43-4 – 43-5
ApplyUpdates, metodo 15-30, 26-35 oggetto Response 43-5 – 43-6
BDE, dataset 26-38 oggetto Server 43-7
dataset client 27-13, 29-7, 29-21, 29-22 – 29-23, oggetto Session 43-6 – 43-7
31-3 assegnazione del nome a un thread 13-13 – 13-15
provider 29-22, 31-3, 31-8 assegnazione, istruzioni, variabili oggetto 4-7
TDatabase 26-37 assembler, codice 15-16
TXMLTransformClient 32-11 Assign Local Data, comando 29-14
AppNamespacePrefix, variabile 38-3 Assign, metodo
Index I-5
BatchMove, metodo 26-8 distruzione 12-22
BDE eventi draw-item 7-17
distributori di risorse 46-6 impostazione dello stato iniziale 12-18
BDE Administration, utilità 26-15, 26-57 in frame 9-16
BDE, dataset 19-1, 24-2, 26-2 – 26-13 internazionalizzazione 17-8
applicazione aggiornamenti in cache 26-38 pennelli 12-9
copia 26-53 proprietà dei pennelli 12-8, 12-9
database 26-3 – 26-4 quando appaiono nelle applicazioni 12-2
operazioni batch 26-50 – 26-55 scorrimento 12-18
sessioni 26-3 – 26-4 sostituzione 12-21
supporto decisionale, componenti e 22-5 temporanee 12-17, 12-18
supporto per database locali 26-5 – 26-8 vuote 12-18
tipi 26-2 bitmap a scorrimento 12-17
BDE, pagina (Component palette) 19-1 bitmap, oggetti 12-3
BeforeApplyUpdates, evente 29-33 bitmap, pulsanti 10-9
BeforeApplyUpdates, evento 31-8 BLOB 20-9, 20-10
BeforeCancel, evento 24-22 memorizzazione in cache 26-4
BeforeClose, evento 24-4 BLOB, campi 20-3
BeforeConnect, evento 23-3, 30-28 acquisizione su richiesta 31-6
BeforeDelete, evento 24-21 ottenimento di valori 26-4
BeforeDisconnect, evento 23-4, 30-29 visualizzazione di grafici 20-10
BeforeDispatch, evento 34-5, 34-7 visualizzazione di valori 20-9, 20-10
BeforeEdit, evento 24-18 blocchi esclusivi
BeforeGetRecords, evento 31-8 tabelle 26-6
BeforeInsert, evento 24-19 blocchi protetti 14-1
BeforeOpen, evento 24-4 annidamento 14-6 – 14-7
BeforePost, evento 24-21 codice di pulizia 14-8, 14-9
BeforeScroll, evento 24-5 Delphi 14-2
BeforeUpdateRecord, evento 26-35, 26-42, 29-23, blocco di oggetti
31-11 annidamento di chiamate 13-8
BeginDrag, metodo 7-1 thread 13-8
BeginRead, metodo 13-9 BlockMode, proprietà 39-9, 39-10, 39-11
BeginTrans, metodo 23-7 bmBlocking 39-11
BeginWrite, metodo 13-9 BMPDlg, unit 12-21
bevel 10-21 bmThreadBlocking 39-9, 39-11
Beveled 10-8 Bof, proprietà 24-6, 24-7, 24-9
bidirezionali, applicazioni bookmark
metodi 17-5 – 17-6 supporto in base al tipo di dataset 24-9
bidirezionali, cursor 24-52 Bookmark, proprietà 24-10
bin, directory 15-22 BookmarkValid, metodo 24-10
binari, operatori 5-44 Boolean, campi 20-2
BinaryOp, metodo 5-45 BorderWidth, proprietà 10-16
binding anticipato bordi, disegno 12-6
Automation 40-18, 44-13 bordi, pannelli 10-16
COM 40-17 Borland Database Engine 8-11, 19-1, 24-2, 26-1 –
binding di dati 45-11 26-57
binding differito 30-29 aggiornamenti in cache 26-34 – 26-50
Automation 44-13, 44-14 errori di aggiornamento 26-40
binding dinamico 30-29 alias 26-3, 26-14, 26-17, 26-26 – 26-27
binding statico 30-30 cancellazione 26-27
bitmap 10-21, 12-18 – 12-19 creazione 26-26
aggiunta di scorribili 12-17 disponibilità 26-26
associazione a stringhe 5-22, 7-14 query eterogenee 26-10
barre strumenti 9-51 specifica 26-14, 26-15
disegno 12-19 apertura di connessioni a database 26-20
Index I-7
tipi speciali 25-5, 25-6 caselle di gruppo 10-15
campi stringa 10-20 caselle di riepilogo 10-12, 20-2, 20-13
dimensioni 25-6 data-aware 20-11 – 20-14
campi, definizioni 24-41 memorizzazione di proprietà, esempio 9-9
copia 24-42 owner-draw
campo, oggetti eventi measure-item 7-16
proprietà riempimento 20-11
condivisione 25-14 rilascio di elementi 7-3
CanBePooled, metodo 46-9 trascinamento di elementi 7-2, 7-3
Cancel, metodo 24-19, 24-22, 27-19 caselle di riepilogo di consultazione 20-2, 20-13 –
Cancel, proprietà 10-9 20-14
CancelBatch, metodo 15-30, 27-13, 27-15 campi di consultazione 20-13
cancellazioni in cascata 31-6 sorgenti dati secondarie 20-13
CancelRange, metodo 24-36 caselle grafiche 20-2
CancelUpdates, metodo 15-30, 26-35, 27-13, 29-6 Cast, metodo 5-43
CanModify, proprietà CastTo, metodo 5-44
dataset 20-5, 24-17, 24-40 CellDrawState, funzione 22-13
griglie dati 20-28 celle (griglie) 10-19
query 26-11 CellRect, metodo 10-19
canvas Cells, funzione 22-13
aggiornamento dello schermo 12-2 Cells, proprietà 10-20
aggiunta di figure 12-11 – 12-12, 12-14 CellValueArray, funzione 22-13
disegno di linee 12-6, 12-10 – 12-11, 12-11, centralizzazione di oggetti
12-28 – 12-30 moduli dati remoti 30-8 – 30-9
cambio dello spessore della penna 12-6 CGI, applicazioni 33-6, 33-7, 36-1
disegno e tracciamento 12-4 creazione 35-9
panoramica 12-1 – 12-4 CGI, programmi
proprietà comuni, metodi 12-4 creazione 34-1
tracciamento e disegno 12-22 ChangeCount, proprietà 15-29, 26-34, 29-6
Canvas, proprietà 10-22 ChangedTableName, proprietà 26-55
Caption, proprietà CHANGEINDEX 29-8
caselle di gruppo e gruppi di opzioni 10-15 Chart Editing, finestra di dialogo 22-16 – 22-19
etichette 10-5 Chart FX 18-5
griglie decisionali 22-13 CHECK, vincolo 31-13
intestazioni di colonna 20-23 Checked, proprietà 10-10
TForm 10-17 CheckSynchronize routine 13-5
voci non valide 9-35 chiavi di licenza 45-7
caratteri estesi 17-4 chiavi parziali
caratteri ideografici 17-3, 17-4 impostazione degli intervalli 24-35
abbreviazioni 17-7 ricerca 24-31
CASE, strumenti 11-1 Chord, metodo 12-4
caselle combinate 10-13, 15-6, 20-2, 20-13 ciclo dei messaggi, nei thread 13-5
consultazione 20-23 Classes, vista 11-4, 11-5
data-aware 20-11 – 20-14 classi 4-1 – 4-11
owner-draw anrenato 4-5
eventi measure-item 7-16 antenato 4-2
caselle combinate di consultazione 20-2, 20-13 – definizione 4-9 – 4-11
20-14 discendenti 4-5, 4-9
campi di consultazione 20-13 eredità 4-5
in griglie dati 20-23 istanziazione 4-8
riempimento 20-23 Tobject 3-6
sorgenti dati secondarie 20-13 classi creatore
caselle di controllo 10-10, 10-12 CoClass 42-5, 42-13
data-aware 20-14 – 20-15 classi richiamabili
TDBCheckBox 20-2 creazione 38-13
Index I-9
griglie 20-17 debug 44-18
gruppi di pulsanti di opzione 10-16 interfacce 40-3, 44-9 – 44-15
ColWidths, proprietà 7-16, 10-19 istanziazione 44-5 – 44-6
COM 8-15 modelli di threading 44-6 – 44-9
aggregazione 40-9 progettazione 44-2
applicazioni 40-3 , 40-19 registrazione 44-17 – 44-18
distribuite 8-15 wizard 44-2 – 44-4, 44-5 – 44-9
parti 40-10 wrapper di componenti 42-1, 42-2, 42-3, 42-6 –
binding anticipato 40-17 42-13
client 40-3, 40-10, 41-21, 42-1 – 42-17 COM, server 40-3, 40-9, 44-1 – 44-18
contenitori 40-10, 42-1 apertura di librerie 40-18
controller 40-10, 42-1 esterni al processo 40-7
definizione 40-2 interni al processo 40-7
estensioni 40-2, 40-10 – 40-12 progettazione 44-2
dipendenze 40-11 remoti 40-7
interfacce 40-3 – 40-5, 44-3 comandi, liste di azioni 9-20
aggiunta a librerie di tipi 41-21 comando, oggetti 27-21
Automation 44-13 – 44-15 COMCTL32.DLL 9-48
identificatori di dispatch 44-14 Command Text, editor 24-47
implementazione 40-6, 40-23 command, oggetti
informazioni di tipo 40-15 iterazione 23-14
interfacce duali 44-13 – 44-14 CommandCount, proprietà 23-14, 27-7
IUnknown 40-4 Commands, proprietà 23-14, 27-7
marshaling 40-8 CommandText, proprietà 24-47, 27-16, 27-17,
modifica 41-22 – 41-24, 44-9 – 44-12 27-18, 27-20, 28-6, 28-7, 28-8, 29-34
ottimizzazione 40-18 CommandTimeout, proprietà 27-5, 27-19
panoramica 40-1 CommandType, proprietà 27-16, 27-17, 27-18,
proxy 40-7, 40-8 28-6, 28-7, 28-8, 29-34
specifiche 40-2 Commit, metodo 23-8, 23-9
stub 40-8 CommitTrans, metodo 23-9
tecnologie 40-11 CommitUpdates, metodo 15-30, 26-35, 26-38
wizard 40-19 – 40-23, 44-1 commutatori 9-50, 9-52
COM Interop 42-18 – 42-23 Compare, metodo 5-46
COM+ 8-15, 30-6, 40-11, 40-15, 46-1 CompareBookMark, metodo 24-10
Vedi anche oggetti transazionali CompareOp, metodo 5-47
applicazioni 46-7, 46-28 compilatore, direttive 15-15
Component Manager 46-29 stringhe 5-31
condivisione di oggetti 46-9 – 46-10 compilazione condizionale 15-14, 15-15
configurazione di attività 46-21 compilazione del codice 2-5
eventi 42-16, 46-21 – 46-25 completamento delle classi 4-10
MTS e 46-2 Component Palette
oggetti evento 46-23 – 46-24 aggiunta di componenti 16-6
oggetti subscriber di eventi 46-24 elenco delle pagine 6-7
oggetti transazionali 40-14 – 40-15 frame 9-15
puntatori di interfaccia 40-5 Component palette 6-7
server in-process 40-7 ActiveX, pagina 42-5
sincronizzazione delle chiamate 46-21 ADO, pagina 19-2, 27-1
transazioni 30-18 BDE, pagina 19-1
COM, distribuiti 40-7, 40-8 Data Access, pagina 19-2, 30-2
COM, interfacce, sollevamento di eccezioni 41-10 Data Controls, pagina 19-16, 20-1, 20-2
COM, libreria 40-2 DataSnap, pagina 30-2, 30-5, 30-6
COM, oggetti 40-3, 40-9, 44-1 – 44-18 dbDirect, pagina 19-2
aggregazione 40-9 dbExpress page 28-2
controllo del tipo 40-18 Decision Cube, pagina 19-16, 22-1
creazione 44-1 – 44-17 InterBase, pagina 19-2
Index I-11
connessioni client 39-2, 39-3 data-aware 20-1 – 20-34
accettazione richieste 39-8 generazione di controlli ActiveX 45-2, 45-4 –
apertura 39-7 45-7
numeri di porta 39-5 owner-draw 7-16
connessioni con nome 28-4 – 28-6 dichiarazione 7-14
aggiunta 28-5 raggruppamento 10-15 – 10-17
cambio del nome 28-6 standard
cancellazione 28-6 visualizzazione dei dati 25-19
caricamento in esecuzione 28-5 visualizzazione dei dati 20-4
connessioni database controlli comuni 9-55
condivisione 46-6 controlli data-aware 20-1 – 20-34, 25-18
connessioni di ascolto 39-2, 39-7 a sola lettura 20-8
numeri di porta 39-5 aggiornamento dati 20-7
connessioni non bloccanti 39-10 associazione con dataset 20-3 – 20-4
connessioni remote 39-2 – 39-3 disattivazione ritracciamento 20-6, 24-8
apertura 39-7 editing 20-5 – 20-6, 24-18
invio/ricezione di informazioni 39-10 funzioni comuni 20-2
connessioni server 39-2, 39-3 griglie 20-16
numeri di porta 39-5 inserimento dati 25-15
connessioni socket 30-9 – 30-10, 30-25, 39-2 – 39-3 inserimento di record 24-20
apertura 39-7 liste 20-2 – 20-3
chiusura 39-8 rappresentazione di campi 20-8
invio/ricezione di informazioni 39-10 visualizzazione dei dati 20-6 – 20-7
multiple 39-5 nelle griglie 20-17, 20-30
punti terminali 39-3, 39-6 valori correnti 20-9
tipi 39-2 visualizzazione di grafici 20-10
console, applicazioni 8-4 controlli di animazione 12-30 – 12-32
CGI 33-7 esempio 12-31
CONSTRAINT, vincolo 31-13 controlli di editing 7-7, 10-1 – 10-4, 20-2, 20-9
ConstraintErrorMessage, proprietà 25-12, 25-23 formati rich edit 20-10
Constraints, proprietà 9-5, 29-7, 31-14 multiriga 20-9
Contains, elenco (package) 16-7, 16-9 selezione del testo 7-9, 7-10
conteggio dei riferimenti 4-19 controlli di input 10-6
interfacce 4-20 controlli di testo 10-1 – 10-4
oggetti COM 40-4 controlli di testo multiriga 20-9, 20-10
Content, metodo controlli elenco 10-12 – 10-15
produttori di pagine 34-15 controlling Unknown 4-18, 4-20
Content, proprietà controllo di versione 2-5
oggetti risposta Web 34-13 ControlType, proprietà 22-9, 22-16
ContentFromStream, metodo convalida dei dati immessi 25-17
produttori di pagine 34-15 conversione
ContentFromString, metodo PChar 5-29
produttori di pagine 34-15 stringhe 5-29
ContentStream, proprietà conversione di misure
oggetti risposta Web 34-13 classi 5-38 – 5-41
contesti di dispositivo 12-1, 12-2 conversioni complesse 5-36
contesti di oggetti 46-4 famiglie di conversione 5-34
contesti di oggetto 46-5 creazione dell’esempio 5-35
ASP 43-3 registrazione 5-35
transazioni 46-10 fattore di conversione 5-38
contesto dati utilità 5-33 – 5-41
applicazioni Web Service 38-7 valuta 5-38
ContextHelp 8-32 conversioni
controlli 3-9 valori di campo 25-17, 25-19 – 25-21
come implemetazione di controlli ActiveX 45-3 conversioni di ore 5-35
Index I-13
basati su file 19-3 dataset 19-7, 24-1 – 24-58
connessione 23-1 – 23-16 a sola lettura
connessioni implicite 23-2 aggiornamento 26-11
generazione di risposte HTML 34-18 – 34-21 aggiunta di record 24-19 – 24-20, 24-23
identificazione 26-14 – 26-15 annullamento delle modifiche 24-22
login a 19-4, 23-4 – 23-6 apertura 24-4
relazionali 19-1 basati su ADO 27-9 – 27-17
scelta 19-3 basati su BDE 26-2 – 26-13
sicurezza 19-4 campi 24-1
tipi 19-3 cancellazione di record 24-21
transazioni 19-5 categorie 24-24 – 24-26
Database Desktop 26-57 chiusura 24-4 – 24-5
Database Explorer 26-15, 26-57 conferma dei record 24-22
database locali 19-3 senza disconnessione 23-13
accesso 26-5 componenti decisionali e 22-5 – 22-7
alias 26-26 conferma dei record 24-21 – 24-22
assegnazione nuovo nome a tabelle 26-8 connessione ai server 29-38
supporto per BDE 26-5 – 26-8 contrassegno di record 24-9 – 24-11
database management systems 30-1 creazione 24-40 – 24-43
database navigator 20-2, 20-31 – 20-34, 24-5, 24-6 cursor 24-5
attivazione/disattivazione dei pulsanti 20-32, custom 24-2
20-33 documenti HTML 34-21
cancellazione dei dati 24-21 editing 24-18 – 24-19
editing 24-18 filtraggio di record 24-13 – 24-16
pulsanti 20-32 iterazione 23-13
suggerimenti della Guida 20-33 modalità 24-3 – 24-4
Database Properties editor 26-15 modifica dei dati 24-17 – 24-24
visualizzazione dei parametri di navigazione 20-31, 24-5 – 24-9, 24-17
connessione 26-15 non indicizzati 24-23
database server 23-3, 26-16 procedure registrate 24-25, 24-52 – 24-58
descrizione 23-3 provider e 31-2
tipi 19-3 query 24-25, 24-44 – 24-52
database, applicazioni 19-1 ricerca 24-11 – 24-13
architecture 30-32 chiavi parziali 24-31
architettura 19-6 – 19-15 estensione della ricerca 24-31
basate su file 19-10, 29-35 – 29-37 su più colonne 24-11, 24-12
distribuite 8-12 usando indici 24-12, 24-13, 24-29 – 24-32
multi-tier 30-3 – 30-4 riga corrente 24-5
porting 15-26 semplici, creazione 29-37
scalabilità 19-11 stati 24-3 – 24-4
database, componenti tabelle 24-25, 24-26 – 24-44
condivisi 26-17 unidirezionali 28-1 – 28-20
database, driver dataset a sola lettura
BDE 26-1, 26-3, 26-14 aggiornamento 19-11
dbExpress 28-3 – 28-4 dataset client 29-1 – 29-39, 30-3
Database, parametro 28-4 aggiornamento dei record 29-32 – 29-33
DatabaseCount, proprietà 26-22 aggiornamento record 29-21 – 29-26
DatabaseName, proprietà 23-2, 26-3, 26-14 aggregazione di dati 29-12 – 29-14
query eterogenee 26-10 annullamento delle modifiche 29-5
Databases, proprietà 26-22 applicazione degli aggiornamenti 29-22 – 29-23
DataCLX, definizione 3-1 applicazioni basate su file 29-35 – 29-37
DataField, proprietà 20-12 campi calcolati 29-11 – 29-12
caselle di riepilogo e combinate di cancellazione di indici 29-9
consultazione 20-13 caricamento di file 29-35
DataRequest, metodo 29-34, 31-3 combinazione dei dati 29-15
Index I-15
DBCtrlGrid, componente 20-3, 20-30 – 20-31 debugger integrato 2-5
proprietà 20-31 Decision Cube Editor 22-8 – 22-9
dbDirect, pagina (Component palette) 19-2 Cube Capacity 22-21
DBEdit, componente 20-2, 20-9 Dimension Settings 22-8
dbExpress 15-23 – 15-29, 18-7, 19-2, 28-1 – 28-2 Memory Control 22-9
componenti 28-1 – 28-20 Decision Cube, pagina (Component palette) 19-16,
debug 28-18 – 28-20 22-1
distribuzione 28-1 Decision Query editor 22-6
driver 28-3 – 28-4 DECnet, protocollo (Digital) 39-1
metadati 28-13 – 28-18 Default, casella di controllo 8-3
dbExpress, applicazioni 18-10 Default, proprietà
dbExpress, pagina (Component palette) 28-2 elementi di azione 34-7
dbGo 27-1 DEFAULT_ORDER, indice 29-8
DBGrid, componente 20-2, 20-17 – 20-30 DefaultColWidth, proprietà 10-19
eventi 20-29 DefaultDatabase, proprietà 27-4
proprietà 20-22 DefaultDrawing, proprietà 7-14, 20-29
DBGridColumns, componente 20-17 DefaultExpression, proprietà 25-22, 29-7
DBImage, componente 20-2, 20-10 – 20-11 DefaultPage, proprietà 35-30
DBListBox, componente 20-2, 20-11 – 20-12 DefaultRowHeight, proprietà 10-19
DBLogDlg, unit 23-4 definizioni di tipo
DBLookupComboBox, componente 20-13 – 20-14 Type Library editor 41-11
DBLookupListBox, componente 20-2, 20-13 – Delete Table, comando 24-43
20-14 Delete Templates, comando (Menu designer) 9-42,
DBMemo, componente 20-2, 20-9 – 20-10 9-44
DBMS 30-1 Delete Templates, finestra di dialogo 9-44
DBNavigator, componente 20-2, 20-31 – 20-34 Delete, comando (Menu designer) 9-42
DBRadioGroup, componente 20-2, 20-15 – 20-16 DELETE, istruzioni 26-42, 26-45, 31-10
DBRichEdit, componente 20-3, 20-10 Delete, metodo 24-21
DBSession, proprietà 26-3 elenchi di stringhe 5-21, 5-22
DBText, componente 20-2, 20-8 – 20-9 DeleteAlias, metodo 26-27
dbxconnections.ini 28-4, 28-5 – 28-6 DeleteFile, funzione 5-8
dbxdrivers.ini 28-3 – 28-4 DeleteFontResource, funzione 18-15
DCOM 40-7, 40-8 DeleteIndex, metodo 29-9
applicazioni InternetExpress 30-37 DeleteRecords, metodo 24-43
applicazioni multi-tier 30-9 DeleteSQL, proprietà 26-42
connessione all’application server 29-27, 30-24 DeleteTable, metodo 24-43
distribuzione di applicazioni 8-15 Delphi
DCOM connessioni 30-9, 30-24 ActiveX framework (DAX) 40-2
DCOMCnfg.exe 30-37 framework ActiveX (DAX) 40-22 – 40-23
.DCP, file 16-2 Delta, proprietà 29-5, 29-21
.dcp, file 16-13 $DENYPACKAGEUNIT, direttiva al
.dcu files 16-2 compilatore 16-11
.dcu, file 16-12, 16-13 DEPLOY 18-15
DDL 23-11, 24-45, 24-51, 26-9, 28-11 DEPLOY, documento 18-15
debug $DESIGNONLY, direttiva al compilatore 16-11
Active Server Objects 43-9 Destroy, metodo 4-9
applicazioni dbExpress 28-18 – 28-20 dettagli annidati 24-39
applicazioni di servizio 8-9 dettaglio, tabelle annidate 30-19
applicazioni Web server 33-9 – 33-11 dettaglio, tabelle, annidate 25-28
codice 2-5 DeviceType, proprietà 12-32
controlli ActiveX 45-16 .DFM, file 17-8
oggetti COM 44-18 .dfm, file 17-9
oggetti transazionali 46-27 – 46-28 generazione 17-12
Web server, applicazioni 35-9 .dfm e .xfm, file 15-4
debug di applicazioni Web server 34-2 .dfm, file 15-19
Index I-17
.dpk, file 16-7 elementi di azione 34-3, 34-4, 34-6 – 34-9
.DPL, file 16-2 aggiunta 34-5
drag-and-dock 7-4 – 7-7 attivazione e disattivazione 34-7
drag-and-drop 7-1 avvertenze in modifica 34-3
DLL 7-4 concatenamento 34-9
mouse pointer 7-4 gestori di evento 34-4
ottenimento di informazioni di stato 7-4 occultamento 9-25
personalizzazione 7-3 predefiniti 34-5, 34-7
DragMode, proprietà 7-1 produttori di pagine e 34-16
griglie 20-21 risposta a richieste 34-8
Draw, metodo 12-5 selezione 34-6, 34-7
DrawShape 12-16 elementi grafici
drill-down, schede 20-16 aggiunta a HTML 34-15
drintf, unit 26-56 associazione a stringhe 5-22
DriverName, proprietà 26-14, 28-3 cancellazione 12-23
DropConnections, metodo 26-14, 26-21 caricamento 12-20
DropDownCount, proprietà 10-13, 20-12 copia 12-22
DropDownMenu, proprietà 9-54 disegno di linee 12-6, 12-10 – 12-11, 12-11,
DropDownRows, proprietà 12-28 – 12-30
caselle combinate di consultazione 20-14 cambio dello spessore della penna 12-6
griglie dati 20-22, 20-23 disegno e tracciamento 12-4
durabilità esempio di effetto elastico 12-24 – 12-30
distributori di risorse 46-6 formati dei file 12-3
transazioni 19-5, 46-10 incollaggio 12-23
dynamic array, tipi 38-4 internazionalizzazione 17-8
panoramica sulla programmazione 12-1 – 12-4
E ridimensionamento 12-21, 20-11
salvataggio 12-20
EAbort 14-12 sostituzione 12-21
EBX, registro 15-8, 15-17 visualizzazione 10-21
eccezioni 3-6, 14-1 – 14-13, 15-20 elementi Web 30-40
flusso di controllo 14-2, 14-4, 14-6 – 14-7 proprietà 30-41 – 30-42
generazione 14-3 elenchi
gestori 14-4 – 14-8 uso in thread 13-5
interfacce COM 41-10 elenchi a comparsa
non gestite 14-11 – 14-12 in griglie dati 20-23
risollevamento 14-7 – 14-8 elenchi di azioni 6-5, 9-19, 9-21, 9-27 – 9-55
silenti 14-13 elenchi di file
sollevamento 14-7 – 14-8 rilascio di elementi 7-3
VCL 14-9 – 14-13 trascinamento di elementi 7-2, 7-3
Edit, metodo 24-18 elenchi di stringhe 5-16 – 5-22
EditFormat, proprietà 20-29, 25-12, 25-16 a breve termine 5-18
editing del codice 2-2 a lungo periodo 5-18
EditKey, metodo 24-29, 24-31 aggiunta a 5-20
EditMask, proprietà 25-15 cancellazione di stringhe 5-21
campi 25-12 caricamento da file 5-17
editor controlli owner-draw 7-14
Diagram Editor 11-4, 11-9 copia 5-21
Imlementation Editor 11-4, 11-7 creazione 5-17 – 5-18
Unit Code Editor 11-4, 11-8 iterazione tra 5-20
editor di proprietà 6-3 oggetti associati 5-22
Editors, pannello 11-4, 11-7 ordinamento 5-21
EditRangeEnd, metodo 24-35, 24-36 posizione in 5-20
EditRangeStart, metodo 24-35, 24-36 ricerca di stringhe 5-20
effetto elastico, esempio 12-24 – 12-30 salvataggio su file 5-17
elaborazione di dati distribuiti 30-2
Index I-19
fetch-on-demand 29-28 trattamento 5-8 – 5-10
FetchOnDemand, proprietà 29-28 file di controllo della rete 26-25
FetchParams, metodo 29-29, 31-3 file di licenza dei package 45-7
Field Link designer 24-37 file di oggetti condivisi 15-8, 15-20
FieldByName, metodo 24-34, 25-21 file di trasformazione 32-1 – 32-6
FieldCount, proprietà nodi definiti dall’utente 32-5, 32-7 – 32-8
campi persistenti 20-19 TXMLTransform 32-7
FieldDefs, proprietà 24-41 TXMLTransformClient 32-9
FieldKind, proprietà 25-12 TXMLTransformProvider 32-9
FieldName, proprietà 25-6, 25-12, 30-41 file eseguibili 15-20
campi persistenti 20-19 internazionalizzazione 17-10, 17-12
griglie dati 20-22, 20-23 server COM 40-7
griglie decisionali 22-13 modelli di threading 44-7
Fields editor 8-20, 25-3 file indice 26-7
applicazione degli attributi di campo 25-15 file indice non di produzione 26-7
barra del titolo 25-4 file scheda 3-8, 15-19, 17-12
cancellazione di campi persistenti 25-11 file sorgente
creazione di campi persistenti 25-4 – 25-5, modifica 2-2
25-5 – 25-11 package 16-10
definizione dei set di attributi 25-14 file sorgenti
liste di campi 25-5 condivisione (Linux) 15-19
pulsanti di navigazione 25-4 package 16-2, 16-7
rimozione del set di attributi 25-15 FileAge, funzione 5-10
riordinamento delle colonne 20-21 FileExists, funzione 5-8
Fields, proprietà 25-21 FileGetDate, funzione 5-10
FieldValues, proprietà 25-21 FileName, proprietà
figure 10-21, 12-11 – 12-12, 12-14 dataset client 29-36, 29-37
disegno 12-11, 12-14 FileName, proprietà, dataset client 19-10
riempimento 12-8, 12-9 FileSetDate, funzione 5-10
riempimento con bitmap 12-9 FillRect, metodo 12-5
tracciamento di contorni 12-6 Filter, proprietà 24-14, 24-14 – 24-15
file 5-5 – 5-14 Filtered, proprietà 24-13
cambio del nome 5-10 FilterGroup, proprietà 27-13, 27-14
cancellazione 5-8 FilterOnBookmarks, metodo 27-11
copia 5-10 FilterOptions, proprietà 24-16
dimensioni 5-4 filtri 24-13 – 24-16
grafici 12-19 – 12-22 attivazione/disattivazione 24-13
handle 5-5, 5-7 campi vuoti 24-14
invio attraverso il Web 34-13 confronto di stringhe 24-16
lettura e scrittura di stringhe 5-3 dataset client 29-3 – 29-5
modalità 5-7 con parametri 29-31
operazioni con 5-5 – 5-14 definizione 24-14 – 24-16
posizione 5-4 e intervalli 24-32
ricerca 5-4, 5-8 impostazione in esecuzione 24-16
risorse 9-46 – 9-47 operatori 24-15
routine opzioni per campi di testo 24-16
API di Windows 5-6 query e 24-13
della libreria runtime 5-8 sensibilità maiuscole/minuscole 24-16
routine di data-ora 5-10 uso di segnalibri 27-11 – 27-12
routine di data-ora 5-10 filtri dati 24-13 – 24-16
tipi attivazione/disattivazione 24-13
con tipo 5-6 impostazione in esecuzione 24-16
senza tipo 5-6 query e 24-13
testo 5-6 filtri sui dati
tipi incompatibili 5-6 dataset client 29-3 – 29-5
Index I-21
GetDriverParams, metodo 26-28 colore 12-6
GetFieldByName, metodo 34-9 disegno 20-29
GetFieldNames, metodo 23-15, 26-28 editing dei dati 20-6, 20-28 – 20-29
GetGroupState, metodo 29-10 inserimento di colonne 20-20
GetHandle 8-26 opzioni di esecuzione 20-27 – 20-28
GetHelpFile 8-26 ottenimento di valori 20-19
GetHelpStrings 8-27 personalizzazione 20-18 – 20-24
GetIDsOfNames, metodo 44-14 rimozione di colonne 20-18, 20-21
GetIndexNames, metodo 23-15, 24-28 riordinamento delle colonne 20-21
GetNextPacket, metodo 15-30, 26-35, 29-28, 31-4 stato predefinito 20-17
GetOptionalParam, metodo 29-16, 31-7 ripristino 20-24
GetOwner, metodo 3-7 visualizzazione dei dati 20-17, 20-18, 20-30
GetParams, metodo 31-3 griglie dati 20-2, 20-3, 20-16, 20-17 – 20-30
GetPassword, metodo 26-23 disegno 20-29
GetProcedureNames, metodo 23-15 editing dei dati 20-6, 20-28 – 20-29
GetProcedureParams, metodo 23-15 eventi 20-29 – 20-30
GetProperty, metodo 5-53 inserimento di colonne 20-20
GetRecords, metodo 31-4, 31-7 opzioni di esecuzione 20-27 – 20-28
GetSessionNames, metodo 26-31 ottenimento di valori 20-19
GetSOAPHeaders, funzione 38-17 personalizzazione 20-18 – 20-24
GetSOAPServer, metodo 30-17, 30-30 proprietà 20-31
GetStoredProcNames, metodo 26-28 rimozione di colonne 20-18, 20-21
GetTableNames, metodo 23-14, 26-28 riordinamento delle colonne 20-21
GetVersionEx, funzione 18-15 stato predefinito 20-17
GetViewerName 8-25 ripristino 20-24
GetXML, metodo 32-10 visualizzazione dei dati 20-17, 20-18, 20-30
Global Offset Table (GOT) 15-17 ADT, campi 20-24
Glyph, proprietà 9-49, 10-9 campi array 20-24
GNU, assembler 15-13 griglie decisionali 22-11 – 22-13
GNU, programma make 15-21 comportamenti in esecuzione 22-20
GotoBookmark, metodo 24-10 dimensioni
GotoCurrent, metodo 24-44 apertura/chiusura 22-12
GotoKey, metodo 24-29, 24-30 drill down 22-12
GotoNearest, metodo 24-30 riordinamento 22-12
grafici selezione 22-12
file 12-19 – 12-22 eventi 22-13
in frame 9-16 proprietà 22-13
tipi degli oggetti 12-3 – 12-4 stati del pivot 22-9, 22-10, 22-12
tracciamento e disegno 12-22 griglie di disegno 10-19
grafici decisionali 22-14 – 22-19 griglie tabellari 20-30
comportamenti in esecuzione 22-20 Grouped, proprietà, pulsanti strumento 9-52
dimensioni 22-15 GroupIndex, proprietà 10-9
modelli 22-17 menu 9-46
opzioni di visualizzazione 22-16 pulsanti di scelta rapida 9-49, 9-50
personalizzazione 22-16 – 22-19 GroupLayout, proprietà 22-11
serie dei dati 22-18 – 22-19 Groups, proprietà 22-10
stati del pivot 22-9, 22-10 gruppi di opzioni 10-15
tipi di grafici 22-17 gruppi di proprietà condivise 46-6
grafici, controlli 3-9 GUI applicazioni 9-1
Graph Custom 18-5 GUID 4-16, 40-4, 41-9
Graphic, proprietà 12-18, 12-22 Guida
GridLineWidth, proprietà 10-19 informazioni di tipo 41-9
griglie 10-19 – 10-20, 20-3 sensibile al contesto 10-19
aggiunta di righe 24-19 suggerimenti 10-19
associate ai dati 20-16, 20-30 tool-tip 10-19
Index I-23
XML, broker 30-35 ImeMode, proprietà 17-7
IAppServer, interfaccia 29-33, 29-34, 30-4, 30-5, ImeName, proprietà 17-7
31-3 – 31-4 immagini 10-21, 20-2
estensione 30-16 aggiunta 12-17
informazioni di stato 30-20 aggiunta a menu 9-40
provider locali 31-3 aggiunta di controlli per 7-15
provider remoti 31-3 cambio 12-21
transazioni 30-18 caricamento 12-20
IAppServer, interface controlli per 12-2, 12-17
chiamata 30-29 in frame 9-16
IAppServerSOAP, interfaccia 30-5, 30-27 internazionalizzazione 17-8
icone 10-21, 30-26 pennelli 12-9
aggiunta a menu 9-23 pulsanti strumento 9-51
barre strumenti 9-51 rigenerazione 12-2
oggetti grafici 12-4 salvataggio 12-20
viste ad albero 10-14 scorrimento 12-18
IConnectionPoint, interfaccia 44-12 sostituzione 12-21
IConnectionPointContainer, interfaccia 44-12 visualizzazione 10-21
ICustomHelpViewer 8-24, 8-27, 8-29 immagini, richieste 35-28
implementazione 8-25 Implementation Editor 11-4, 11-7
IDE, impostazione opzioni di progetto 8-3 implements, parola chiave 4-16, 4-18
identificatori, non validi 9-35 $IMPLICITBUILD, direttiva al compilatore 16-11
IDispatch, interfaccia 40-9, 40-19, 44-13 Import ActiveX Control, comando 42-2, 42-4
Automation 40-12 Import Type Library, comando 42-2, 42-3
identificatori 44-14, 44-15 ImportedConstraint, proprietà 25-12, 25-23
Idispatch, interfaccia 44-14 – 44-15 $IMPORTEDDATA, direttiva al compilatore 16-11
IDL (Interface Definition Language) 40-16, 40-18, impostazioni locali 5-24
41-1 formato dati 17-8
Type Library editor 41-9 moduli di risorse 17-9
IDL, compilatore 40-18 impostazioni nazionali 17-2
IDL, file incapsulazione 4-2
esportazione da libreria di tipi 41-28 Increment, proprietà 10-7
IDOMImplementation 37-3 Indent, proprietà 9-52, 9-53, 10-14
IETF, protocolli e standard 33-3 Index Files editor 26-7
IExtendedHelpViewer 8-24, 8-28 Index, proprietà
$IFDEF, direttiva 15-14 campi 25-12
$IFEND, direttiva 15-15 IndexDefs, proprietà 24-41
$IFNDEF, direttiva 15-15 IndexFieldCount, proprietà 24-28
IHelpManager 8-25, 8-32 IndexFieldNames, proprietà 24-29, 28-8, 29-8
IHelpSelector 8-25, 8-29 IndexName e 24-29
IHelpSystem 8-25, 8-32, 8-33 IndexFields, proprietà 24-28
IID 40-4 IndexFiles, proprietà 26-7
IInterface 4-14 – 4-15, 4-18 IndexName, proprietà 26-7, 28-7, 29-9
TInterfacedObject 4-15 IndexFieldNames e 24-29
Iinterface 4-21 IndexOf, metodo 5-20, 5-21
IInvokable 4-21, 38-2 indici 24-27 – 24-39
IIS 43-1 cancellazione 29-9
versione 43-3 dataset client 29-8 – 29-11
Image, marcatore HTML (<IMG>) 34-15 elenco 23-15, 24-28
ImageIndex, proprietà 9-51, 9-54 intervalli 24-32
ImageList 9-21 operazioni batch e 26-53
ImageMap, marcatore HTML (<MAP>) 34-15 ordinamento dei record 24-27 – 24-29, 29-8
Images, proprietà, pulsanti strumento 9-51 raggruppamento di dati 29-10 – 29-11
IMarshal, interfaccia 44-15, 44-17 relazioni master/detail 24-37
IME 17-7 ricerca su chiavi parziali 24-31
Index I-25
operatore as 4-16 indici e 24-32
ottimizzazione del codice 4-19 limiti estremi 24-35
polimorgismo 4-12, 4-13 modifica 24-35 – 24-36
procedure 4-14 specifica 24-33 – 24-35
richiamabili 4-21, 38-2 – 38-9 valori nulli 24-33, 24-34
riutilizzo del codice 4-16 intranet
sintassi 4-12 nomi host 39-4
sistema di Help 8-24 InTransaction, proprietà 23-7
sistemi di Help 8-24 IntraWeb 36-1 – 36-8
SOAP 4-20 documentazione 36-8
Type Library editor 41-9 – 41-10, 41-16, 41-21, modalità application 36-1
44-9 modalità page 36-1
Web Services 38-1 modalità standalone 36-1
XML, nodi 37-5 Invoke, metodo 44-14
interfacce dispatch 30-30 invoker 38-11
Type Library editor 41-17 InvokeRegistry.hpp 38-5
interfacce duali 44-13 – 44-14 IObjectContext, interfaccia 40-15, 43-3, 46-4 , 46-5
Active Server Objects 43-3 metodi per terminare una transazione 46-13
chiamata a metodi 42-14 IObjectControl, interfaccia 40-15, 46-2
compatibilità dei tipi 44-16 IOleDocumentSite, interfaccia 42-17
oggetti transazionali 46-3, 46-18 IP, indirizzi 39-4, 39-6
parametri 44-17 host 39-4
interfacce richiamabili nomi host e 39-5
chiamata 38-21 – 38-23 IProvideClassInfo 40-17
implementazione 38-12 – 38-13 IProviderSupport, interfaccia 31-2
metodi ridefiniti 38-2 IPX/SPX, protocolli 39-1
namespace 38-3 Irequest, interfaccia 43-4
registrazione 38-3 Iresponse, interfaccia 43-5
interfacce utente 9-1, 19-16 is, parola riservata 4-8
a singolo record 20-8 ISAPI 36-1
isolamento 19-6 ISAPI DLLs 18-9
layout 9-4 – 9-5 ISAPI, applicazioni 33-7
multirecord 20-16 creazione 34-1, 35-9
organizzazione dei dati 20-8, 20-16 debug 33-10
schede 9-1 – 9-4 messaggi di richiesta 34-2
Interface Definition Language (IDL) 41-1 IsCallerInRole, metodo 30-7
interfaces IScriptingContext, interfaccia 43-3
CLSID 4-21 ISecurityProperty, interfaccia 46-17
InternalCalc, campi 25-6, 29-11 – 29-12 Iserver, interfaccia 43-7
indici e 29-9 ISessionObject, interfaccia 43-6
internazionalizzazione di applicazioni 17-1 ISOAPHeaders, interfaccia 38-17, 38-24
abbreviazioni 17-7 isolamento
conversione input di tastiera 17-7 transazioni 19-5, 46-10
Internet Engineering Task Force 33-3 ISpecialWinHelpViewer 8-25
Internet Information Server (IIS) 43-1 IsSecurityEnabled 46-17
versione 43-3 istanziazione
Internet, server 33-1 – 33-11 moduli dati remoti 30-14
Internet, standard e protocolli 33-3 oggetti COM 44-5 – 44-6
InternetExpress 30-34 – 30-44 IsValidChar, metodo 25-18
e ActiveForms 30-32 – 30-33 ItemHeight, proprietà 10-12
InternetExpress, pagina (Component palette) 6-8 caselle combinate 20-12
intervalli 24-32 – 24-36 caselle di riepilogo 20-12
annullamento 24-36 ItemIndex, proprietà 10-12
applicazione 24-36 gruppi di pulsanti di opzione 10-16
e filtri 24-32 Items, proprietà
Index I-27
persistenti 5-16
ListField, proprietà 20-14
M
lists Macros, vista 11-4, 11-9
accesso agli elementi 5-15 MainMenu, componente 9-34
aggiunta di elementi 5-14 maiuscole/minuscole, sensibilità
cancellazione di elementi 5-15 indici 29-9
disposizione degli elementi 5-16 make, programma di utilità 15-21
ListSource, proprietà 20-14 Man, pagine 8-24
livelli di raggruppamento 29-10 manifest, file 9-56
aggregati di manutenzione 29-13 mappatura
-LNpath, direttiva al compilatore 16-13 XML 32-2 , 32-2 – 32-4
LoadFromFile, metodo definizione 32-4
dataset ADO 27-16 mappe di colori, menu e barre strumenti 9-24
dataset client 19-10, 29-35 mappe di tastiera 17-7, 17-8
grafici 12-20 Mappings, proprietà 26-53
stringhe 5-17 Margin, proprietà 10-9
LoadFromStream, metodo marshaling 40-8
dataset client 29-36 custom 44-17
LoadPackage, funzione 16-4 interfacce COM 40-8 , 44-4, 44-15 – 44-17
LoadParamListItems, procedura 23-15 interfaccia IDispatch 40-13, 44-15
LoadParamsFromIniFile, metodo 28-5 oggetti transazionali 46-3
LoadParamsOnConnect, proprietà 28-5 maschere 25-15
Local SQL 26-9, 26-10 master/detail, relazioni 20-16, 24-37 – 24-39,
query eterogenee 26-9 24-49 – 24-50
LocalHost, proprietà aggiornamenti in cascata 31-6
socket client 39-7 applicazioni multi-tier 30-19
localizzazione cancellazioni in cascata 31-6
localizzazione di applicazioni 17-2 dataset client 29-19
risorse 17-9, 17-10, 17-12 dataset unidirezionali 28-12 – 28-13
localizzazioni 17-12 indici 24-37
LocalPort, proprietà inegrità referenziale 19-6
socket client 39-7 tabelle annidate 24-39, 30-19
Locate, metodo 24-11 TSimpleDataSet 29-38
Lock, metodo 13-8 master/detail, schede 20-16
LockList, metodo 13-8 esempio 24-38 – 24-39
LockType, proprietà 27-13 MasterFields, proprietà 24-37, 28-13
LogChanges, proprietà 29-5, 29-37 MasterSource, proprietà 24-37, 28-13
login Max, proprietà
connessioni Web 30-26 barre di avanzamento 10-18
login information, specifying 23-5 trackbar 10-6
login, eventi 23-5 MaxDimensions, proprietà 22-21
Login, finestra di dialogo 23-4 MaxLength, proprietà 10-3
login, obbligatorio 35-18 controlli memo data-aware 20-9
LoginPrompt, proprietà 23-4 controlli rich edit data-aware 20-10
long string 5-23 MaxRecords, proprietà 30-38
Lookup, metodo 24-12 MaxRows, proprietà 34-20
LookupCache, proprietà 25-10 MaxStmtsPerConn, proprietà 28-3
LookupDataSet, proprietà 25-10, 25-12 MaxSummaries, proprietà 22-21
LookupKeyFields, proprietà 25-10, 25-12 MaxTitleRows, proprietà 20-26
LookupResultField, proprietà 25-12 MaxValue, proprietà 25-12
.lpk, file 45-7 MBCS 5-22
LPK_TOOL.EXE 45-7 MDAC 18-7
-LUpackage, direttiva al compilatore 16-13 MDI applicazioni
menu attivo 9-46
MDI, applicazioni 8-1 – 8-3
Index I-29
HTML 34-14 – 34-18 Web Broker, applicazioni 34-4
menu 9-35, 9-42, 9-43 moduli dati remoti 8-20, 30-3, 30-5, 30-12, 30-13
produttori di pagine 35-4 basati su COM 30-21
programmazione 8-3 centralizzazione 30-8 – 30-9
Web Broker, applicazioni 34-2 figlio 30-21
modelli di componente 9-13 genitore 30-21
e frame 9-15, 9-16 istanziazione 30-14
modelli di risposta 34-14 modelli di threading 30-14, 30-15
modelli di threading 44-6 – 44-9 multipli 30-21 – 30-22, 30-31 – 30-32
controlli ActiveX 45-5 senza stato 30-7, 30-9, 30-19 – 30-21
moduli dati remoti 30-14 moduli dati transazionali 30-5, 30-6 – 30-8
moduli dati transazionali 30-15 attributi della transazione 30-15
oggetti Automation 44-5 connessioni a database 30-6, 30-8
oggetti COM 44-3 centralizzazione 30-7
oggetti transazionali 46-19 – 46-20 interfaccia 30-17
registro di sistema 44-7 modelli di threading 30-15
modelli, ModelMaker 11-2 – 11-3 sicurezza 30-9
ModelMaker 11-1 – 11-10 moduli di fusione 18-3
avvio 11-2 moduli di risorsa 17-8
Diagram Editor 11-4, 11-9 moduli di risorse 17-9, 17-10
Documentation 11-4 moduli Web 34-2
Implementation Editor 11-4, 11-7 aggiunta di sessioni database 34-18
modelli 11-2 – 11-3 DLL e, avvertenze 34-3
pannello Collections 11-4 most recenty used, elenchi (MRU) 9-26
pannello Editors 11-4, 11-7 motivi 12-9
pannello Members 11-4, 11-7 motivi di riempimento 12-8, 12-9
Unit Code Editor 11-4, 11-8 motori di database
Unit Difference 11-4 di terze parti 18-7
vista Classes 11-4, 11-5 mouse pointer, drag-and-drop 7-4
vista Diagrams 11-4, 11-6 mouse, eventi 12-24 – 12-27
vista Documentation 11-9 controllo di 12-27
vista Events 11-4, 11-9 definizione 12-24
vista Macros 11-4, 11-9 drag-and-drop 7-1 – 7-4
vista Members 11-4, 11-7 informazioni di stato 12-25
vista Patterns 11-4, 11-9 parametri 12-25
vista Unit Difference 11-9 MouseToCell, metodo 10-19
vista Units 11-4, 11-5 .mov, file 12-33
modifica di script 35-22 Move, metodo
Modified, proprietà 10-3 elenchi di stringhe 5-22
Modifiers, proprietà 10-7 Move, metodo, elenchi di stringhe 5-21
ModifyAlias, metodo 26-27 MoveBy, metodo 24-7
ModifySQL, proprietà 26-42 MoveCount, proprietà 26-54
moduli MoveFile, funzione 5-10
tipi 8-16 MovePt 12-29
tipi Web 35-2 MoveTo, metodo 12-5, 12-8
Type Library editor 41-11 – 41-12, 41-19, 41-26 .mpg, file 12-33
moduli dati 19-7 MRU (most recently used), elenchi 9-26
accesso da schede 8-20 MSI, tecnologia 18-3
applicazioni Web e 34-2 MTS 8-15, 30-6, 40-11, 40-14, 46-1
componenti database 26-17 Vedi anche oggetti transazionali
creazione 8-17 ambiente di esecuzione 46-2
editing 8-17 COM+ e 46-2
remoti e standard 8-16 oggetti transazionali 40-14 – 40-15
sessioni 26-18 requisiti 46-3
Web 35-3, 35-5 riferimenti a oggetti 46-26 – 46-27
Index I-31
specifica della directory condivisa 8-21 oggetti esterni 40-9
utilizzo di elementi 8-22 oggetti evento 13-10
Object Repository, finestra di dialogo 8-21 oggetti grafici, thread 13-5
Object Repostory oggetti interni 40-9
componenti database 26-17 oggetti persistenti 3-7
Object, marcatore HTML (<OBJECT>) 34-15 oggetti richiesta
ObjectBroker, proprietà 30-25, 30-26, 30-28 informazioni dell’header 34-4
ObjectContext, proprietà oggetti thread
esempio 46-15 – 46-16, 46-16 definizione 13-2
Objects, proprietà 10-20 limiti 13-2
elenchi di stringhe 5-22, 7-17 oggetti thread-safe 13-5
ObjectView, proprietà 20-25, 24-39, 25-25 oggetti transazionali 40-11, 40-14 – 40-15, 46-1 –
.ocx, file 18-5 46-30
ODBC, driver amministrazione 40-15, 46-29 – 46-30
uso con ADO 27-1, 27-2 attività 46-20 – 46-21
utilizzo con BDE 26-1 callback 46-27
ODBC, drivers caratteristiche 46-2 – 46-3
utilizzo con BDE 26-16 condivisione di connessioni database 46-6
ODL (Object Description Language) 40-16, 41-1 condivisione di proprietà 46-6
OEM, set di caratteri 17-3 contesti di oggetto 46-4
OEMConvert, proprietà 10-3 creazione 46-17 – 46-21
oggetti 4-1 – 4-11 debug 46-27 – 46-28
vedi anche COM, oggetti disattivazione 46-5
accesso 4-5 – 4-6 gestione delle risorse 46-3 – 46-10
creazione 4-8, 4-9 installazione 46-28 – 46-29
dichiarazioni di tipo 4-7 interfacce duali 46-3
distruzione 4-9 librerie di tipi 46-3
e record 4-1 marshaling 46-3
eredità 3-5 , 3-5 – 3-6, 4-5 requisiti 46-3
eventi 4-4 rilascio di risorse 46-9
istanze multiple 4-3 senza stato 46-12 – 46-13
istanziazione 4-3 sicurezza 46-16 – 46-17
personalizzazione 4-5 transazioni 46-5, 46-10 – 46-16
proprietà 4-2 controllate dal server 46-16
scrip 35-23 oggetti translazionali
senza stato 46-13 condivisione di proprietà 46-8, 46-9
oggetti associati ai thread 13-5 transazioni
oggetti Automation 40-12 controllate dal client 46-14
oggetti campo 25-1 – 25-30 oggetto drag 7-3
accesso ai valori 25-21 – 25-22 OldValue, proprietà 26-40, 31-12
cancellazione 25-11 OLE
definizione 25-5 – 25-11 combinazione di menu 9-45
dinamici 25-2 – 25-3 contenitori 6-7
e persistenti 25-2 OLE Automation Vedi Automation
eventi 25-16 – 25-17 OLE DB 27-1, 27-2
persistenti 25-3 – 25-17 OleObject, proprietà 45-14, 45-15
e dinamici 25-2 OLEView 40-18
proprietà 25-1, 25-11 – 25-16 OnAccept, evento 39-8, 39-9
in esecuzione 25-13 socket server 39-10
visualizzazione e modifica di proprietà 25-12 OnAction, event 34-8
oggetti comando 27-18 OnAfterPivot, evento 22-10
oggetti condivis OnBeforePivot, evento 22-10
oggetti condivisi OnBeginTransComplete, evento 23-7, 27-9
e DLL OnCalcFields, evento 24-24, 25-7, 25-8, 29-11
oggetti contenuti 40-9 OnCellClick, evento 20-29
Index I-33
Options, proprietà 10-19 pacchetti delta 31-8, 31-9
griglie dati 20-27 editing 31-8, 31-9 – 31-10
griglie decisionali 22-13 valutazione degli aggiornamenti 31-11
provider 31-5 – 31-6 XML 30-37, 30-38 – 30-40
TSQLClientDataSet 29-18 package 16-1 – 16-16
opzioni del compilatore 8-3 assegnazione del nome 16-8, 16-9
opzioni del linker, package 16-13 caricate dinamicamente 16-4
opzioni di progetto 8-3 compilazione 16-11 – 16-13
predefinite 8-3 opzioni 16-11
opzioni, reciprocamente esclusive 9-50 creazione 8-10, 16-7 – 16-13
Oracle, tabelle 26-13 custom 16-5
Oracle8 di esecuzione 16-3 – 16-5, 16-8
limiti sulla creazione di tabelle 24-42 di progettazione 16-5 – 16-7
orari, internazionalizzazione 17-8 direttive al compilatore 16-11
ORDER BY, clausola 24-27 distribuzione di applicazioi 16-14
ordinamento 17-8 DLL 16-1, 16-2
dataset client 29-8 editing 16-8
discendente 29-9 elenco Contains 16-7, 16-9
impostazione 24-29 elenco Requires 16-7, 16-9
Orientation, proprietà esecuzione 16-1
griglie dati 20-31 estensioni del nome del file 16-1
track bar 10-6 file sorgenti 16-2
Origin, proprietà 12-28, 25-13 impostazioni predefinite 16-8
out-of-process, server 40-7 installazione 16-6 – 16-7
ASP 43-7 internazionalizzazione 17-10, 17-12
output, parametri 24-54, 29-29 opzione per sola progettazione 16-7
overload di procedure registrate 26-13 opzioni 16-8
Overload, proprietà 26-13 opzioni del linker 16-13
Owner, proprietà 3-8, 4-9 packaging debole 16-12
owner-draw, controlli 5-22 progettazione 16-1
caselle di riepilogo 10-12, 10-13 raccolte 16-14
dichiarazione 7-14 referenziazione 16-4
disegno 7-16, 7-17 riferimenti duplicati 16-9
domensionamento 7-16 uso in applicazioni 16-3 – 16-5
OwnerDraw, proprietà 7-14 utilizzo 8-10
Package Collection Editor 16-14
P package di esecuzione 16-1, 16-3 – 16-5
package di progettazione 16-1, 16-5 – 16-7
$P, direttiva al compilatore 5-31 package, file 18-3
pacchetti dati 20-5, 32-4 packaging debole 16-12
a sola lettura 31-5 PacketRecords, proprietà 15-30, 26-35, 29-28
acquisizione 29-27 – 29-29, 31-7 – 31-8 page dispatcher 35-10, 35-24
aggiornamento dei record aggiornati 31-6 Page, controlli 10-17
controllo di campi 31-5 page, modalità 36-1
conversione in documenti XML 32-6 – 32-8 pages, Component palette 6-7
copia 29-14 – 29-16 PageSize, proprietà 10-7
editing 31-8 pagina, controlli
garanzia di record unici 31-5 aggiunta di pagine 10-17
inclusione proprietà del campo 31-6 pagina, moduli 35-2, 35-4 – 35-5
informazioni definite dall’applicazione 29-16, pagine di codice 17-3
31-7 pagine di login
limitazione delle modifiche del client 31-5 WebSnap 35-16 – 35-18
mappatura a documenti XML 32-2 pagine di proprietà 45-12 – 45-15
XML 30-32, 30-34, 30-37 aggiornamento 45-14
modifica 30-38 aggiornamento dei controlli ActiveX 45-14
recupero 30-37 – 30-38
Index I-35
Picture, proprietà 10-21, 12-18 PrivateDir, proprietà 26-25
Pie, metodo 12-5 ProblemCount, proprietà 26-55
pivot decisionali 22-10 – 22-11 ProblemTableName, proprietà 26-55
comportamenti in esecuzione 22-19 procedure registrate 19-5, 24-25, 24-52 – 24-58
orientamento 22-10 basate su BDE 26-2, 26-12 – 26-13
proprietà 22-10 inglobamento di parametri 26-12
pulsanti di dimensione 22-10 caricate in sovrapposizione 26-13
pixel, lettura e impostazione 12-10 creazione 28-12
Pixel, proprietà 12-4 dbExpress 28-8
Pixels, proprietà 12-5, 12-10 elenco 23-15
pmCopy, costante 12-30 esecuzione 24-57
pmNotXor, costante 12-30 parametri 24-54 – 24-56
poligoni 12-12 da dataset client 29-30
disegno 12-12 in esecuzione 24-56
polimorfismo 4-2 in progettazione 24-54 – 24-56
interfacce 4-12, 4-13 proprietà 24-55 – 24-56
Polygon, metodo 12-5, 12-12 preparazione 24-57
PolyLine, metodo 12-5, 12-11 specifica del database 24-53
PopupMenu, componente 9-34 ProcedureName, proprietà 24-53
PopupMenu, proprietà 7-12 processi lenti, che usano i thread 13-1
Port, proprietà 39-7 produttori di contenuti 34-4, 34-14
TSocketConnection 30-25 gestione di eventi 34-15, 34-17
porte 39-5 produttori di pagine 34-14 – 34-18, 35-2, 35-4, 35-7
connessioni multiple 39-5 concatenamento 34-17
servizi e 39-2 Content, metodo 34-15
socket client 39-6, 39-7 ContentFromStream 34-15
socket server 39-7 ContentFromString 34-15
porting di applicazioni 15-1 – 15-31 conversione modelli 34-15
in Linux 15-2 data-aware 30-40 – 30-44, 34-19
porting del codice 15-17 gestione di eventi 34-15, 34-17
Position, proprietà 10-7, 10-18 modelli 35-4
position-independent code (PIC) 15-8, 15-16, 15-17 tipi 35-11
possesso 3-8 produttori di tabelle 34-19 – 34-21
Post, metodo 24-21 impostazione delle proprietà 34-20
Edit e 24-19 profondità dei colori 18-12
Precision, proprietà programmazione 18-14
campi 25-13 progetti
parametri 24-49, 24-55 aggiunta di schede 9-1 – 9-4
predefinite progetti, file
opzioni di progetto 8-3 distribuzione 2-5
predefiniti modifica 2-2
valori 20-11 progetto, modelli 8-23
Prepared, proprietà programmazione object-oriented
dataset unidirezionali 28-9 definizione 4-1
procedure registrate 24-57 Delphi 4-1 – 4-21
query 24-51 eredità 4-5
Preview, pagina 35-2 programmazione, modelli 8-3
primari, indici programmi di installazione 18-2
operazioni batch e 26-53 Project Manager 9-3
PRIMARY KEY, vincolo 31-13 Project Options, finestra di dialogo 8-3
principale, scheda 9-3 Property Page, wizard 45-13
Prior, metodo 24-7 Proportional, proprietà 12-3
priorità, uso dei thread 13-1, 13-3 proprietà 3-3, 4-2
Priority, proprietà 13-3 aggiunta a controlli ActiveX 45-9 – 45-10
private, sezione 4-7 aggiunta a interfacce 44-9 – 44-10
Index I-37
relazioni master/detail 24-49 – 24-50 dataset client 29-21 – 29-26
senza nome 24-47 identificazione di tabelle 31-12
parametrizzate 24-46 multiple 31-6
preparazione 24-51 operazioni batch 26-8, 26-52, 26-53
relazioni master/detail 24-49 – 24-50 pacchetti delta 31-8, 31-9
set risultato 24-52 query e 26-11
specifica 24-45 – 24-47, 28-6 – 28-7 valutazione degli aggiornamenti 31-11
specifica del database 24-44 aggiunta 24-19 , 24-20, 24-20, 24-23, 26-52
tabelle HTML 34-21 operazioni batch 26-8, 26-52, 26-53
TSimpleClientDataSet 29-39 appending
Query Builder 24-46 operazioni batch 26-8
query decisionali cancellazione 24-21, 24-43, 26-53
definizione 22-6 operazioni batch 26-8, 26-53
query eterogenee 26-9 – 26-10 conferma 24-21 – 24-22
Local SQL 26-9 alla chiusura del dataset 24-22
query parametrizzate 24-46, 24-47 – 24-49 contrassegno 24-9 – 24-11
creazione copia 26-53
in esecuzione 24-49 operazioni batch 26-8, 26-53
in progettazione 24-48 criteri di ricerca 24-11, 24-12
Query, proprietà documenti XML e 32-11
oggetti aggiornamento 26-50 e objects 4-1
QueryInterface, metodo 4-14, 4-18, 4-20, 40-4 filtraggio 24-13 – 24-16
aggregazione 40-9 inoltro 20-6
griglie dati 20-28
R iterazione tra 24-8
operazioni batch 26-52, 26-53
raccolte di package, file 16-14 ordinamento 24-27 – 24-29
raggruppamento di componenti 10-15 – 10-17 prelievo 28-8 – 28-9
raise, parola riservata 14-3 asincrono 27-12
Rave Reports 21-1 ricerca 24-11 – 24-13, 24-29 – 24-32
RC, file 9-46 riconciliazione degli aggiornamenti 29-24
RDBMS 19-3, 30-1 ripetizione della ricerca 24-31
RDSConnection, proprietà 27-17 sincronizzazione del corrente 24-44
Read, metodo, TFileStream 5-2 spostamento tra 20-31, 24-5 – 24-9, 24-17
ReadBuffer, metodo, TFileStream 5-2 Type Library editor 41-11, 41-18, 41-25 – 41-26
ReadCommitted 23-10 visualizzazione 20-30
README 18-16 RecordCount property, TBatchMove 26-54
README, documento 18-16 RecordCount, proprietà
ReadOnly, proprietà 10-3 TBatchMove 26-54
campi 25-13 RecordSet, proprietà 27-20
controlli data-aware 20-6 Recordset, proprietà 27-11
controlli memo data-aware 20-9 RecordsetState, proprietà 27-11
controlli rich edit data-aware 20-10 RecordStatus, proprietà 27-13, 27-14
griglie dati 20-22, 20-28 Rectangle, metodo 12-5, 12-11
tabelle 24-40 Refresh, metodo 20-7, 29-32
ReasonString, proprietà 34-12 RefreshLookupList, proprietà 25-10
rebar 9-47, 9-53 RefreshRecord, metodo 29-32, 31-4
ReceiveBuf, metodo 39-8 Register, metodo 12-3
Receiveln, metodo 39-8 RegisterComponents, procedura 16-6
RecNo, proprietà di dataset client 29-2 RegisterConversionType, funzione 5-34, 5-36
Reconcile, metodo 15-30, 26-35 RegisterHelpViewer 8-34
record RegisterNonActiveX, procedura 45-3
acquisizione 29-27 – 29-29 RegisterPooled, procedura 30-9
aggiornamento 20-7, 24-22 – 24-24, 26-52, RegisterTypeLib, funzione 40-18
29-32 – 29-33, 30-38 – 30-40, 31-8 RegisterViewer, funzione 8-30
da documenti XML 32-10
Index I-39
risposte HTTP drill down 20-16
azioni 35-27 gestione della memoria 9-6
risultato, parametri 24-54 IDE 4-2
ritenzione degli annullamenti 27-7 interrogazione di proprietà, esempio 9-10
ritenzione delle modifiche 27-7 istanziazione 4-3
Rollback, metodo 23-9 modali 9-6
RollbackTrans, metodo 23-9 non modali 9-6, 9-8
root, directory 15-22 ottenimento di dati 9-9 – 9-13
RoundRect, metodo 12-5, 12-12 passaggio di argomenti 9-8 – 9-9
routine principale 9-3
terminate con null 5-26 – 5-27 referenziazione 9-4
routine globali 5-1 sincronizzazione dei dati 20-4
RowAttributes, proprietà 34-20 tabelle master/detail 20-16
RowCount, proprietà 20-14, 20-31 uso di variabili locali per creare 9-8
RowHeights, proprietà 7-16, 10-19 variabile globale per 9-6
RowRequest, metodo 31-4 visualizzazione 9-6
Rows, proprietà 10-20 schede, linking 9-4
RowsAffected, proprietà 24-51 schermo
RPC 40-9 aggiornamento 12-2
RTTI risoluzione 18-12
interfacce richiamabili 38-2 programmazione 18-12, 18-13
$RUNONLY, direttiva al compilatore 16-11 ScktSrvr.exe 30-9, 30-13, 30-25
SCM 8-5
S scorciatoie di tastiera
aggiunta a menu 9-38
safe array 41-14 Screen, variabile 9-2, 17-7
SafeArray 41-14 script
safecall, convenzioni di chiamata 41-10, 45-10 active 35-21
SafeRef, metodo 46-26 generazione in WebSnap 35-22
Save as Template, comando (Menu designer) 9-42, modifica e visualizzazione 35-22
9-44 URL 33-4
Save Attributes, comando 25-14 script della shell 15-19
Save Template, finestra di dialogo 9-44 script di login 23-4 – 23-6
SaveConfigFile, metodo 26-26 script per Web 35-8
SavePoint, proprietà 29-6 script, oggetti 35-23
SaveToFile, metodo 12-20 scripting 35-8
dataset ADO 27-15 scripting lato server 35-8, 35-20 – 35-23
dataset client 19-10, 29-37 ScrollBars, proprietà 7-8, 10-19
stringhe 5-17 controlli memo data-aware 20-9
SaveToStream, metodo SDI, applicazioni 8-1 – 8-3
dataset client 29-37 Sections, proprietà 10-17
scalabilità 19-11 Seek, metodo
ScaleBy property, TCustomForm 18-13 dataset ADO 24-29
Scaled property, TCustomForm 18-13 segmenti consecutivi di linee 12-10, 12-11
ScanLine, proprietà segnalazione di eventi 13-10
esempio con bitmap 12-19 segnali 15-20
schede 9-1 segnalibri 24-9 – 24-11
accesso da altre schede 4-6 filtraggio di record 27-11 – 27-12
aggiunta a progetti 9-1 – 9-4 segni diacritici 17-8
aggiunta di campi 12-28 Select Menu, comando (Menu designer) 9-42
aggiunta di riferimenti a unit 9-4 Select Menu, finestra di dialogo 9-42
code editor 4-2 SELECT, istruzioni 24-45
collegamento 9-4 SelectAll, metodo 10-4
come tipi oggetto 4-2 – 4-4 Selection, proprietà 10-19
condivisione di gestori di evento 12-16 SelectKeyword 8-29
creazione in esecuzione 9-7
Index I-41
SetRange e 24-34 pacchetti di errore 38-19
SetSchemaInfo, metodo 28-13 wizard di applicazioni 38-10
sezioni critiche 13-8 SOAP Data Module wizard 30-16
avvertenze sull’uso 13-8, 13-9 SOAP, connessioni 30-11, 30-26
sfondi 17-8 SOAP, moduli dati 30-6
sfondi trasparenti 17-8 SOAPServerIID, proprietà 30-27, 30-31
sgancio di controlli 7-6 socket 39-1 – 39-11
Shape, proprietà 10-21 accettazione richieste del client 39-3
Shared Property Manager 46-6 – 46-8, 46-9 assegnazione host 39-4
esempio 46-7 – 46-8, 46-9 descrizione 39-3
Shift, stati 12-25 fornitura di informazioni 39-4
ShortCut, proprietà 9-38 gestione degli errori 39-8
Show, metodo 9-7, 9-8 gestione di eventi 39-8 – 39-10
ShowAccelChar, proprietà 10-5 implementazione di servizi 39-1 – 39-2, 39-7
ShowButtons, proprietà 10-14 indirizzi di rete 39-3, 39-4
ShowColumnHeaders, proprietà 10-15 lettura da 39-10
ShowFocus, proprietà 20-31 lettura/scrittura 39-10 – 39-11
ShowHint, proprietà 10-19, 20-33 scrittura su 39-10
ShowLines, proprietà 10-14 socket client 39-3, 39-6 – 39-7
ShowModal, metodo 9-6 assegnazione host 39-4
ShowRoot, proprietà 10-14 connessione a server 39-9
ShutDown 8-26 gestione di eventi 39-9
sicurezza identificazione dei server 39-6
applicazioni multi-tier 30-2 messaggi di errore 39-8
connessioni SOAP 30-26 proprietà 39-6
connessioni Web 30-10, 30-26 richiesta di servizi 39-6
database 19-4, 23-4 – 23-6 socket dispatcher, applicazione 30-13, 30-25
tabelle locali 26-22 socket server 39-7 – 39-8
DCOM 30-37 accettazione delle richieste del client 39-7, 39-9
moduli dati transazionali 30-7, 30-9 gestione di eventi 39-9
oggetti transazionali 46-16 – 46-17 messaggi di errore 39-8
registrazione di connessioni socket 30-10 specifica 39-6
sicurezza basata sul ruolo 46-16 socket, componenti 39-5 – 39-8
Simple Object Access Protocol Vedi SOAP socket, oggetti 39-6
sincronizzatore multilettura a scrittura client 39-6
esclusiva 13-8 socket client 39-6
sincronizzazione dei dati socket server 39-7
su più schede 20-4 SoftShutDown 8-26
sincronizzazione delle chiamate 46-21 sola lettura
single document interface 8-1 – 8-3 campi 20-6
single-tier, applicazioni 19-9, 19-13 sorgenti dati 19-7, 20-3
basate su file 19-10 attivazione 20-4
singola, eredità 4-12 disattivazione 20-4
sistemi di Guida eventi 20-4 – 20-5
pulsanti strumento 9-54 sorgenti decisionali 22-9 – 22-10
sito Web (supporto tecnico) 1-3 eventi 22-9
Size, proprietà proprietà 22-9
campi 25-13 Sorted, proprietà 10-12, 20-12
parametri 24-49, 24-55 SortFieldNames, proprietà 28-7
smistatore free-threaded 44-8 sottomenu 9-38
so, file Vedi shared objects sottoscrizioni permanenti 42-16
SOAP 38-1 sottoscrizioni per-utente 42-16
applicazioni multi-tier 30-11 sottoscrizioni transitorie 42-16
connessione all’application server 30-26 SourceXml, proprietà 32-7
header 38-16 – 38-18, 38-23 – 38-24 SourceXmlDocument, proprietà 32-7
Index I-43
supporto dei caratteri multi-byte 5-24 blocchi esclusivi 26-6
terminate con null 5-22, 5-26 – 5-27 cancellazione di record 26-8
trasformazione 17-2, 17-7, 17-8 chiusura 26-5
troncamento 17-3 collegamento 26-5
variabili locali 5-29, 5-30 copia record 26-8
Strings, proprietà 5-20 diritti di accesso 26-6
StrNextChar, funzione 15-14 operazioni batch 26-8 – 26-9
Structured Query Language ricerche basate su indice 24-29
Vedi SQL cancellazione 24-43
strumenti di disegno creazione 24-40 – 24-43
assegnazione come predefinito 9-49 campi persistenti 24-41
controllo di 12-12 indici 24-41
gestione di più strumenti in applicazioni 12-12 dbExpress 28-7 – 28-8
strumenti di traduzione 17-1 definizione 24-40 – 24-41
stub definizioni di campi e indici 24-41
COM 40-8 precaricamento 24-42
oggetti transazionali 46-3 elenco 23-14
Style, proprietà 7-14, 10-12 griglie non-database 10-19
caselle combinate 10-13, 20-12 indici 24-27 – 24-39
caselle di riepilogo 10-12 inserimento di record 24-19 – 24-20, 24-23
penne 12-6 intervalli 24-32 – 24-36
pennelli 10-21, 12-9 ordinamento 24-27, 28-7
pulsanti strumento 9-52 relazioni master/detail 24-37 – 24-39
web items 30-42 ricerca 24-29 – 24-32
StyleRule, proprietà 30-42 sincronizzazione 24-44
Styles, proprietà 30-42 specifica del database 24-26
StylesFile, proprietà 30-42 svuotamento 24-43
subscriber, oggetti 42-16 visualizzazione in griglie 20-18
sottoscrizioni permanenti 42-16 tabelle a sola lettura 24-40
sottoscrizioni per-utente 42-16 tabelle annidate 24-39, 25-28, 30-19
sottoscrizioni transitorie 42-16 tabelle dBASE
Subtotals, proprietà 22-13 accesso ai dati 26-9
suggerimenti 10-19 aggiunta di record 24-20
suggerimenti di Guida 20-33 tabelle detail annidate
SupportCallbacks, proprietà 30-17 acquisizione su richiesta 31-6
supporto al login tabelle Paradox
WebSnap 35-14 – 35-20 operazioni batch 26-55
supporto decisionale, componenti 19-16, 22-1 – tabelle problem 26-55
22-22 Table, marcatore HTML (</TABLE>) 34-15
assegnazione dei dati 22-5 – 22-7 TableAttributes, proprietà 34-20
gestione della memoria 22-20 TableName, proprietà 24-27, 24-41, 28-7
runtime 22-19 – 22-20 TableOfContents 8-29
supporto tecnico 1-3 TableType, proprietà 24-40, 26-5 – 26-6
Suspend, metodo 13-12 Tabs, proprietà 10-17
sviluppo, supporto 1-3 TAction 9-22
Synchronize, metodo 13-5 TActionClientItem 9-25
TActionList 9-20, 9-21
T TActionMainMenuBar 9-18, 9-20, 9-21, 9-23, 9-25
TActionManager 9-18, 9-20, 9-21
tab, controlli 10-17 TActionToolBar 9-18, 9-20, 9-21, 9-23
tabelle 24-25, 24-26 – 24-44 TActiveForm 45-3, 45-6
a sola lettura 24-40 TAdapterDispatcher 35-24
annidate 24-39 TAdapterPageProducer 35-22
basate su BDE 26-2, 26-5 – 26-9 TADOCommand 27-2, 27-7, 27-10, 27-18 – 27-21
aggiornamento record 26-8
aggiunta di record 26-8
Index I-45
in controlli 7-7 spazio di processo 13-4
internazionalizzazione 17-7 thread della VCL 13-4
operazioni con 7-7 – 7-13 uso di elenchi 13-5
ricerca di 10-3 valori restituiti 13-10
selezione 7-9, 7-10 thread a processo parallelo 13-1
stampa 10-3 thread multiprocesso 13-1
testo statico, controllo 10-5 thread principale della VCL 13-4
TEvent 13-10 evento OnTerminate 13-7
Text, proprietà 10-3, 10-13, 10-18 Thread Status, casella 13-13
TextHeight, metodo 12-5 thread, classi, definizione 13-1
TextOut, metodo 12-5 thread, funzioni 13-4
TextRect, metodo 12-5 thread, oggetti 13-1
TextWidth, metodo 12-5 inizializzazione 13-3
TField 24-1, 25-1 – 25-30 ThreadID, proprietà 13-13
eventi 25-16 – 25-17 threadvar 13-6
metodi 25-17 – 25-18 THTMLTableAttributes 34-20
proprietà 25-1, 25-11 – 25-16 THTMLTableColumn 34-20
in esecuzione 25-13 THTTPRio 38-22
TFiler 5-3 THTTPSoapDispatcher 38-9, 38-11
TFileStream 5-2, 5-6 THTTPSoapPascalInvoker 38-9, 38-11
I/O su file 5-6 , 5-6 – 5-7 TIBCustomDataSet 24-2
TFloatField, formattazione predefinita 25-16 TIBDatabase 19-9, 23-1
TFMTBcdField, formattazione predefinita 25-16 TickMarks, proprietà 10-6
TForm 4-2 TickStyle, proprietà 10-6
proprietà della barra di scorrimento 10-6 tier 30-1
TFrame 9-14 TImage component 10-21
TGraphicControl 3-5 TImage, in frame 9-16
THeaderControl 10-17 TImageList 9-51
thread 13-15 timeout, eventi 13-11
assegnazione dei nomi 13-13 – 13-15 timer 6-7
attesa di 13-10 TIniFile 5-11
multipli 13-10 TInterfacedObject 4-15, 4-19
attesa di eventi 13-10 derivazione da 4-15
attività 46-21 implementazione di Iinterface 4-15
BDE e 26-13 TInvokableClass 38-12
blocco dell’esecuzione 13-7 header di accesso 38-17
blocco di oggetti 13-8 TInvokeableVariantType 5-52 – 5-53
ciclo dei messaggi 13-5 tipi
come evitare l’accesso simultaneo 13-7 Automation 44-16 – 44-17
componenti di accesso ai dati 13-5 Char 17-3
conversione da senza nome a con nome 13-13 librerie di tipi 41-12 – 41-14
coordinamento 13-4, 13-7 – 13-11 MIME 12-22
creazione 13-11 Web Services 38-4 – 38-9
esecuzione 13-11 tipi character 17-3
id 13-13 tipi di campo
inizializzazione 13-3 conversione 25-17, 25-19 – 25-21
interruzione 13-6, 13-12 tipi di dati
ISAPI/NSAPI, programmi 34-2, 34-18 campi persistenti 25-6
liberazione 13-3, 13-4 tipi di server 35-9
limiti sul numero 13-12 tipi enumerati 38-4
oggetti grafici 13-5 costanti e 12-13
priorità 13-1, 13-3 dichiarazione 12-12
ridefinizione 13-12 Type Library editor 41-18
servizio 8-7 tipi enumerativi
sezioni critiche 13-8 Type Library editor 41-11, 41-25
Index I-47
TransIsolation, proprietà 23-10 TTextBrowser 10-2, 10-4, 10-5
transazioni locali 26-33 TTextViewer 10-2, 10-4
Transliterate, proprietà 25-13, 26-51 TThread 13-2
Transparent, proprietà 10-5 TThreadList 13-5, 13-8
trasformazione di stringhe di caratteri 17-2, 17-7, TTimeField, formattazione predefinita 25-16
17-8 TToolBar 9-21, 9-47, 9-50
trasformazione in stringhe di caratteri TToolButton 9-47
conversioni 2 byte 17-3 TTreeView 10-14
trasparenza, delle barre strumenti 9-52, 9-53 TTypedComObject
TReader 5-3 necessità di una libreria di tipi 40-17
TRegIniFile 15-22 TUpdateSQL 26-42 – 26-50
TRegistry 5-11 provider e 26-11
TRegistryIniFile 5-11, 5-13 TVarData, record 5-42
TRegSvr 18-5, 40-18 TWebActionItem 34-3
TRemotable 38-6 TWebAppDataModule 35-2
TRemotableXS 38-6 TWebAppPageModule 35-2
TRemoteDataModule 30-5 TWebConnection 30-26
TRichEdit 10-1 TWebContext 35-24
trigger 19-5 TWebDataModule 35-2
trinagoli 12-12 TWebDispatcher 35-24, 35-29
try, blocchi 14-2 TWebPageModule 35-2
try...except, istruzioni 14-4 TWebResponse 34-3
try...finally, istruzioni 14-9 TWidgetControl 3-5, 3-10, 15-6
TScrollBox 10-6, 10-16 definizione 3-6
TSearchRec 5-8 TWinControl 3-10, 15-6, 17-7
TServerSocket 39-7 definizione 3-6
TService_object 8-8 TWriter 5-3
TSession 26-17 – 26-31 TWSDLHTMLPublish 38-9, 38-19
aggiunta 26-29, 26-30 TWSDLHTMLPublisher 38-11
TSharedConnection 30-31 TXMLDocument 37-4, 37-9
TSimpleDataSet 28-2, 29-19, 29-27, 29-31, 29-37 – TXMLTransform 32-6 – 32-8
29-39 documenti sorgente 32-6
provider interno 31-1 TXMLTransformClient 32-9 – 32-11
vantaggi e svantaggi 29-38 parametri 32-10
TSoapConnection 30-26 TXMLTransformProvider 31-1, 31-2, 32-8 – 32-9
TSoapDataModule 30-6 Type Library editor 40-16, 41-2 – 41-28
TSOAPHeader 38-16 aggiornamento 41-28
TSocketConnection 30-25 alias 41-11, 41-18
TSQLConnection 19-9, 23-1, 28-2 – 28-6 aggiunta 41-25
collegamento 28-3 – 28-6 apertura di librerie 41-20 – 41-21
monitoraggio dei messaggi 28-18 application server 30-17
TSQLDataSet 28-2, 28-6, 28-7, 28-8 barra di stato 41-6
TSQLMonitor 28-18 – 28-19 barra strumenti 41-4 – 41-5
TSQLQuery 28-2, 28-6 CoClass 41-10 – 41-11, 41-17
TSQLStoredProc 28-2, 28-8 aggiunta 41-24
TSQLTable 28-2, 28-7 collegamento di attributi 45-12
TSQLTimeStampField, formattazione COM+, pagina 46-5
predefinita 25-16 definizioni dei tipi 41-11
TStoredProc 26-2, 26-12 – 26-13 dispinterface 41-10
TStream 5-2 elementi 41-9 – 41-12
TStringList 5-16 – 5-22, 8-27 caratteristiche comuni 41-9
TStrings 5-16 – 5-22 interfacce 41-9 – 41-10, 41-16
TTabControl 10-17 aggiunta 41-21
TTable 26-2, 26-5 – 26-9 modifica 41-22 – 41-24
dataset decisionali e 22-6 interfacce dispatch 41-17
Index I-49
aggiunta di moduli dati 8-20 messaggi 15-13
inclusione di package 16-4 panoramica 3-1 – 3-3
senza riferimenti circolari 9-4 ramo Tcomponent 3-8
ramo Tcontrol 3-9
V ramo Tobject 3-6
ramo Tpersistent 3-7
$V, direttiva al compilatore 5-31 ramo TWinControl 3-10
valori thread principale 13-4
dati predefiniti 20-11 unit 15-8 – 15-12
valori additivi VCL, applicazioni
crosstab 22-3 porting 15-21
valori di consultazione 20-19 vcl60.bpl 16-1, 16-9, 18-6
valori di riepilogo penwin.dll 16-12
aggregati di manutenzione 29-14 VendorLib, proprietà 28-4
cubi decisionali 22-20 VertScrollBar 10-6
grafici decisionali 22-16 video analogici 12-34
valori logici 20-2, 20-14 video cassette 12-34
Value, proprietà video clip 12-30
aggregati 29-14 video, filmati 12-32
campi 25-19 ViewStyle, proprietà 10-14
parametri 24-48, 24-49, 24-55, 24-56 vincoli
ValueChecked, proprietà 20-14 controlli 9-4 – 9-5
Values, proprietà dati 25-22 – 25-23
gruppi di pulsanti di opzione 20-15 creazione 25-22 – 25-23
ValueUnchecked, proprietà 20-14, 20-15 dataset client 29-7 – 29-8, 29-31 – 29-32
valuta disattivazione 29-32
esempio di conversione 5-38 importazione 25-23, 29-32, 31-13, 31-14
formati 17-8 violazione dell’integrità 26-55
valute violazione in accesso, stringhe 5-28
internazionalizzazione 17-8 violazioni di chiave 26-55
VarCmplx, unit 5-42 visibilità 4-6 – 4-7
variabili Visible, proprietà 3-3
dichiarazioni 4-7 barre strumenti 9-54, 9-55
oggetti 4-7 – 4-8 campi 25-13
variabili di thread 13-5 coolbar 9-54
variabili locali al thread 13-5 menu 9-45
evento OnTerminate 13-7 VisibleButtons, proprietà 20-32, 20-33
variant custom 5-41 – 5-54 VisibleColCount, proprietà 10-19
abilitazione 5-50 VisibleRowCount, proprietà 10-19
azzeramento 5-49 viste ad albero 10-14
caricamento e salvataggio di valori 5-49 – 5-50 VisualCLX
conversione di tipo 5-43 – 5-44, 5-45, 5-46, 5-51 definizione 3-2
copia 5-48 – 5-49 package 16-9
creazione 5-41, 5-43 – 5-50, 5-51 WinCLX e 15-5 – 15-7
memoria 5-48, 5-49 visualclx, package 16-1
memorizzazione dati 5-42, 5-46, 5-48, 5-49 visualizzazione di script 35-22
metodi 5-52 – 5-54 visualizzazione tabellare (griglie) 10-19
operatori di confronto 5-46 – 5-48 VisualSpeller Control 18-5
operatori unari 5-48 voci di menu 9-36 – 9-38
operazioni binarie 5-44 – 5-46 aggiunta 9-36, 9-45
proprietà 5-52 – 5-54 annidamento 9-38
scrittura di utilità 5-50 – 5-52 assegnazione dei nomi 9-35, 9-45
Variant, tipo 5-41 barre di separazione 9-37
VCL cancellazione 9-37, 9-42
definizione 3-1 definizione 9-34
e CLX 3-2
Index I-51
WebSnap 33-1 – 33-3 Wrapable, proprietà 9-52
diritti di accesso 35-18 – 35-20 Write By Reference
login obbligatorio 35-18 proprietà di interfaccia COM 41-10
pagine di login 35-16 – 35-18 Write, metodo, TFileStream 5-2
scripting lato server 35-20 – 35-23 WriteBuffer, metodo, TFileStream 5-2
supporto al login 35-14 – 35-20 WSDL 38-2
wide string 5-22 – 5-23 file 38-20
widechar 15-17 importazione 38-3, 38-14 – 38-15, 38-20 – 38-21
widestring 15-17 pubblicazione 38-18, 38-19 – 38-20
widget 15-6 WSDL administrator 38-20
widget, controlli 3-10 WSDL, publisher 38-11
Width, proprietà 9-4, 10-18
colonne delle griglia dati 20-18 X
griglie dati 20-22
penne 12-6 $X, direttiva al compilatore 5-31
TScreen 18-13 XDR, file 37-2
WIN32 15-15 Xerox Network System (XNS) 39-1
WIN64 15-15 .xfm, file 4-4, 15-4, 15-19
Win-CGI, applicazioni XML 32-1, 37-1
creazione 35-9 applicazioni database 32-1 – 32-11
WinCLX dichiarazione del tipo di documento 37-2
definizione 3-2 istruzioni di elaborazione 37-1
VisualCLX e 15-6 mappatura 32-2 , 32-2 – 32-4
Windows services 36-1 definizione 32-4
Windows XP, temi 9-55 parser 37-2
Windows, Graphics Device Interface (GDI) 12-1 SOAP 38-1
Windows, porting di applicazioni in Linux 15-2 XML Data Binding, wizard 37-6 – 37-10
wininet.dll 30-26, 30-27 XML, broker 30-35, 30-37 – 30-40
wizard 8-21 messaggi HTTP 30-39
Active Server Object 40-21, 43-2 – 43-3 XML, documenti 32-1, 37-1 – 37-10
ActiveForm 40-21, 45-6 – 45-7 attributi 32-5, 37-5
Add New Web Service 38-12 componenti 37-4, 37-9
COM 40-19 – 40-23, 44-1 conversione in pacchetti dati 32-6 – 32-8
COM+ Event object 40-21 file di trasformazione 32-1
COM+ Event subscriber, oggetto 46-24 generazione di interfacce per 37-7
COM+ Event, oggetto 46-23 – 46-24 nodi 37-2, 37-4 – 37-6
controlli ActiveX 40-21, 45-4 – 45-6 attributi 32-5
libreria ActiveX 40-21 file di trasformazione 32-1
oggetti Automation 40-20, 44-4 – 44-9 mappatura su campi 32-2
oggetti COM 40-20, 41-20 nodi figlio 37-6
oggetto COM 44-2 – 44-4, 44-5 – 44-9 nodo radice 37-4, 37-7, 37-9
oggetto transazionale 40-21, 46-18 – 46-21 proprietà dei nodi 37-7
pagina di proprietà 40-21 pubblicazione di informazioni database 32-9
Property Page 45-13 XML, file 27-15
Remote Data Module 30-14 – 30-15 XML, schemi 37-2
Resource DLL 17-9 XMLBroker, proprietà 30-41
SOAP Data Module 30-16 XMLDataFile, proprietà 31-2, 32-8
Transactional Data Module 30-15 – 30-16 XMLDataSetField, proprietà 30-41
Type Library 40-21, 41-20 XMLMapper 32-2, 32-4 – 32-6
Web Services 38-10 – 38-14 XP, temi 9-55
XML Data Binding 37-6 – 37-10 XSBuiltIns, unit 38-6
WM_PAINT, messaggi 12-2 XSD, file 37-2
WordWrap, proprietà 7-7, 10-3 XSLPageProducer 35-4
controlli memo data-aware 20-9
Wrap, proprietà 9-52
Index I-53
I-54 Guida alla programmaziome