introduzione a microsoft® visual basic

Transcript

introduzione a microsoft® visual basic
INTRODUZIONE A MICROSOFT® VISUAL BASIC®
Microsoft® Visual Basic® 6.0
Microsoft® Visual Basic® è uno strumento di sviluppo della famiglia Microsoft® Visual Studio®
che permette di realizzare in modo rapido ed immediato (RAD: Rapid Application Development)
applicazioni altamente integrate con l'insieme di sistemi operativi Windows® di Microsoft.
Il prodotto è distribuito in tre versioni principali:



Learning Edition
Professional Edition
Enterprise Edition
La differenza fonamentale tra le tre versioni non riguarda la sintassi del linguaggio di
programmazione ma gli strumenti sviluppo disponibili. La versione Learning infatti può essere
vista come una versione di base orientata agli studenti o agli hobbisti che vogliono iniziare a
conoscere il VB. E' ottima per imparare ma inevitabilmente finirete per sentire la necessità
degli strumenti presenti nelle versioni maggiori se inizierete ad usare con continuità questo
strumento. La versione Professional infatti include strumenti indispensabili per la creazione di
applicazione client/server e per Internet. La versione Enterprise è infine la scelta corretta per
gruppi di sviluppatori che necessitano di tutti gli strumenti per monitorare e migliorare le
prestazioni e l'efficienza del loro codice.
Ovviamente i prezzi dei tre prodotti cambiano in funzione delle caratteristiche, quindi si passa
dalle circa 200 mila Lire (109$) della versione Learning, al milione abbondante (549$) della
edizione Professional per finire con circa 3 milioni (1299$) della versione Enterprise.
Se la vostra intenzione è solo quella di valutare il prodotto vi consiglio la versione Learning
in quanto contiene anche un manuale di "avviamento" alla programmazione su cd-rom.
Se avete intenzione di sviluppare delle applicazioni professionali però vi ocnviene
comprare direttamente la versione Professional.
Un consiglio che mi sento di darvi: usate la versione Inglese.
Il VB è un linguaggio molto simile all'inglese, non sono 3 voci di menù in italiano che ci
semplificano la vita, l'inglese dobbiamo conoscerlo comunque per poter utilizzare il VB.
Spesso le versioni nazionalizzate hanno problemi/bug specifici che nelle versioni inglesi e/o
internazionali non sono presenti. I fix spesso escono prima nella versione inglese e poi nelle
versioni nazionalizzate, quindi se avete il VB italiano vi tocca aspettare. Se volete prima o poi
certificarvi come Microsoft Certified Professional non tutti gli esami esistono in italiano. Quelli
sul VB sono tutti in inglese quindi se voi imparate ad usare il VB in italiano rischiate poi di non
sapere le risposte alle domande relative all'interfaccia utente.
Cosa possiamo fare ?
In questa prima "puntata" intendo dare solo una panoramica veloce delle possibilità offerte dal
VB. Con le versioni Professional/Enterprise possiamo realizzare le seguenti tipologie
fondamentali di applicazione:

Standard EXE: sono i classici programmi eseguibili,
pensati per le postazioni desktop

ActiveX EXE: sono applicazioni eseguibili che
espongono ulteriori informazioni per essere
raggiungibili anche da altri programmi/computer

ActiveX DLL: sono librerie COM (Component Object
Model) ... vedremo bene di cosa si tratta nella
seconda metà del tutorial

ActiveX Control: sono dei controlli grafici che possiamo inserire nelle nostre applicazioni
o in pagine Web

ActiveX Documents: sono dei particolari documenti visualizzabili in container
(Contenitore di Office, Internet Explorer, ecc.)

AddIn: sono programmi che servono a noi programmatori per automatizzare
determinati compiti durante lo sviluppo delle nostre applicazioni

DHTML Application: sono applicazioni Web basate sul Dynamic HTML

IIS Application: sono applicazioni Internet particolari che permettono di inviare ai client
Web (Explorer, Netscape, ecc.) pagine HTML pure anche se generate dinamicamente sul
server
Kit di sopravvivenza
Prima di buttarci a capofitto nello sviluppo VB mi permetto di consigliarvi alcuni strumenti che
potete pensare come una sorta di kit di sopravvivenza.
Questi sono:

Programmare Microsoft Visual Basic 6.0 - Francesco Balena
(Microsoft Press - Mondadori Informatica)

Microsoft Access® 97/2000 - non un libro ma il software in quanto tale.

Microsoft Windows NT® Option Pack o il Personal Web Server di Windows® 9x
Il libro di Francesco Balena è un comodo supporto allo sviluppo di tutti i giorni.
I software sono praticamente indispensabili per poter lavorare e di conseguenza saranno
fondamentali anche per alcune delle realizzazione che svolgeremo nella seconda parte di
questo tutorial.
INTERFACCIA UTENTE E PROGRAMMAZIONE
GUIDATA DAGLI EVENTI
Avviamo il VB
Se mandiamo in esecuzione il nostro Microsoft® Visual Basic® 6.0
ci troviamo all'interno dell'ambiente di sviluppo.
Tramite questa interfaccia possiamo creare tutte le nostre
applicazioni e i nostri componenti. La prima schermata che ci si
presenta è quella che ci permette di scegliere il tipo di
applicazione che stiamo iniziando a creare (Standard EXE, ActiveX
EXE, ActiveX DLL, ecc.).
In questa primo caso ci occuperemo di un applicativo desktop
tradizionale e quindi chiederemo al VB di creare un modello di
progetto Standard EXE.
Questa scelta comporta il fatto che il VB crei un nuovo progetto e vi inserisca automaticamete
le informazioni necessarie a gestire la visualizzazione di una finestra.
Tradotto in pratica questo determina la creazione di un progetto di applicazione inizialmente
costituita da una sola form.
La prima Form
Selezionato il tipo di progetto quindi ci troviamo nell'ambiente di sviluppo VB e sullo schermo
del nostro PC avremo la possibilità di disegnare la nostra interfaccia utente tramite il mouse e
la casella degli strumenti, di default alla sinistra della finestra.
Un approccio classico allo sviluppo di applicazioni desktop VB è quindi il disegno dell'interfaccia
utente. Pensiamo di voler inserire un pulsante nella nostra form. Non dovremo fare altro che
selezionare nella casella degli strumenti lo strumento CommandButton e poi disegnarne la
forma sulla form affinché il pulsante venga aggiunto all'interfaccia grafica della stessa.
Se a questo punto volessimo eseguire (tasto F5 = Esegui) il nostro programma - che non farà
assolutamente nulla - vedremmo che comunque il programma è già in grado di funzionare ed
infatti la sua esecuzione comporta la visualizzazione di una finestra con lo stesso aspetto della
form da noi definita.
Questo ci permette di concludere che le applicazioni desktop per essere realizzate in termini di
interfaccia grafica possono non richiedere alcun elemento di codice.
In reltà vedremo nel prosieguo di questo tutorial che molto spesso l'interfaccia grafica viene
caricata o quantomento gestita dal codice e quindi nelle applicazioni concrete non basterà mai
definire soltanto l'aspetto grafico degli oggetti.
Se premiamo il tasto F4 (= Visuallizza Proprietà) possiamo accedere ad una finestrella come
quella riportata in figura, che ci permette di definire la maggior parte delle informazioni relative
ai nostri oggetti disegnati sullo schermo. Ad esempio generalmente ci sono le proprietà per
selezionare il colore di sfondo dell'oggetto, il colore in primo piano, ecc.
Una buona regola di comportamento, attuabile tramite l'utilizzo di questa finestra di proprietà,
è assegnare al progetto, alle form ed ai controlli dei nomi (proprietà (Name) nel pannellino)
sensati, meglio se nel rispetto della notazione ungarica.
La programmazione ad eventi
Definita l'interfaccia utente del mio programma devo pensare a scrivere il codice che la
gestisca.
L'idea alla base di questo modo di ragionare è che, definito un elemento nell'interfaccia utente
di un applicazione, posso codificare la procedura da fargli eseguire quando questo elemento
viene premuto con il mouse, piuttosto che quando il mouse gli passa sopra senza premerlo. Il
bello di questi programmi è che l'utente finale delle nostre applicazioni di solito è libero di
premere un tasto piuttosto che un altro, di muovere il mouse sopra un controllo piuttosto che
un altro. Quindi si potrebbe verificare potenzialmente qualsiasi delle casistiche accennate.
Questa idea di applicazione che risponde alle richieste ed alle azioni dell'utente, richiamando
determinate procedure senza un ordine di esecuzione prestabilito, ci porta ad avere programmi
che saranno costituiti da piccoli blocchi di codice, che gestiranno le singole situazioni che si
possono verificare (click del mouse, movimenti del mouse, altro...).
Quindi si parla di programmazione guidata dagli eventi (Event-Driven) perchè tutto ciò che si
verifica è dovuto ad eventi associati ad elementi della nostra interfaccia grafica.
Gestiamo il click di un pulsante
Chiarito il concetto di programmazione guidata dagli eventi vediamo come gestire un semplice
evento.
Inseriamo un pulsante di comando all'interno della nostra interfaccia utente e chiamiamolo
cmdButton tramite la finestra delle proprietà (F4).
Facendo doppio click sull'oggetto appena definito comparirà una finestra che ci permette di
scrivere del codice associato all'evento predefinito dell'oggetto. Si parla di evento predefinito
perchè un oggetto può essere in grado di gestire diversi eventi (click, doppio click,
mousemove, mouseover, ecc.).
Nel caso del pulsante di comando ci troveremo all'interno della procedura di gestione
dell'evento Click e quindi ci si presenterà una schermata simile a quella nella seguente.
Osserviamo che ci troviamo in un modulo di codice associato ad una form ed all'interno di
questo troviamo della sintassi VB (che nelle prossime lezioni approfondiremo) che ci definisce
una procedura cmdButton_Click, la quale scatterà ogni volta che il nostro utente farà click con
il mouse sul pulsante cmdButton.
Per verificare il funzionamento di questa logica ad eventi abbiamo inserito un'istruzione
MsgBox "Hai fatto click sul pulsante cmdButton !" che altro non fa che aprire sullo schermo una
finestrella di messaggio che riporterà come messaggio appunto la dicitura che le forniamo
come argomento.
Eseguendo (F5) il nostro progetto possiamo renderci conto del fatto che ora, contrariamente al
progetto privo di codice in esecuzione, la nostra applicazione ogni volta che viene premuto il
pulsante di comando eseguirà questa riga di codice e visualizzerà il messaggio sullo schermo.
COSTRUTTI FONDAMENTALI DEL LINGUAGGIO
VISUAL BASIC
Aree di codice
In Microsoft® Visual Basic® possiamo avere diversi file e moduli di codice all'interno di un unico
progetto di applicazione. Nei moduli di codice di Microsoft® Visual Basic® abbiamo diverse aree
che possiamo localizzare selezionandole nelle caselle a discesa che troviamo nella parte alta
dei moduli di codice stessi.
Queste aree sono:



(Generale) - (Dichiarazioni) => in questa dovremo inserire informazioni di interesse per
tutto il modulo di codice.
Nome_Oggetto - Procedura Evento => in queste aree dovremo caricare il codice
relativo a singole procedure evento (per es. Command1_Click).
(Generale) - Procedura Generica => in queste aree avremo il codice relativo alle
procedure e funzioni da noi definite (ne parleremo tra poco).
All'interno di queste aree dovremo inserire del codice di programmazione nel rispetto della
sintassi del linguaggio ed appoggiandoci ai costrutti che vedremo in questa lezione.
Le Variabili
Anche in Microsoft® Visual Basic® 6.0 come in qualsiasi linguaggio
di programmazione è possibile dichiarare delle variabili. Le
variabili sono un'area di memoria dove è possibile salvare delle
informazioni per riutilizzarle in seguito.
Le parole chiave per dichiarare delle variabili in Microsoft® Visual
Basic® sono:
Dim NomeVariabile As Tipo
Public NomeVariabile As Tipo
Private NomeVariabile As Tipo
Static NomeVariabile As Tipo
Vi sono diverse parole chiave a seconda dello spazio di azione
(visibilità) che vogliamo assegnare alle variabili che dichiariamo.
In realtà in Microsoft® Visual Basic® è possibile lavorare senza dichiarare le variabili, ma il fatto
che un linguaggio offra questa possibilità non significa che noi dobbiamo per forza sfruttarla.
Lavorare senza dichiarare le variabili che si utilizzano è una pessima abitudine. Dal momento
che lo scopo di questo tutorial è imparare a programmare bene in Microsoft® Visual Basic®, per
noi le variabili saranno sempre da dichiarare.
Per essere sicuri di non sbagliare possiamo attivare un'opzione che ci costringe a dichiarare le
variabili. Dal menù Strumenti->Opzioni selezionare il primo pannello ed attivare "Richiedi la
dichiarazione delle variabili".
A questo punto vediamo cosa significano le parole chiave elencate precedentemente:
Dim significa che stiamo dimensionando una variabile che avrà uno spazio di azione pari a
quello della sezione in cui dichiariamo la variabile. Questo significa che se useremo Dim
all'interno di una procedura (un blocco di codice che può essere richiamato più volte) allora la
variabile che dichiareremo sarà valida soltanto all'interno di quella procedura, soltanto nel
momento in cui la procedura è in esecuzione. Di solito la parola chiave Dim si usa proprio in
questo caso.
Public e Private invece si usano di solito nel dichiarare variabili nella parte che prima abbiamo
definito come (Generale) - (Dichiarazioni). Qualora si voglia avere le variabili visibili dagli altri
moduli di codice del progetto si userà Public altrimenti Private per avere le variabili visibili solo
all'interno del modulo in cui le abbiamo definite. Torneremo più avanti nel Tutorial a parlare di
queste cose (sviluppo di componenti).
La parola chiave Static infine dimensiona una variabile all'interno di una procedura in modo
tale che la stessa mantenga il suo valore tra diverse esecuzioni della procedura.
Tutte e quattro le parole chiave richiedono un nome (conviene dare nomi sensati alle variabili)
ed un tipo subito dopo la parola chiave As. Per tipo si intende la tipologia di valori che la
variabile può assumere.
I tipi di dati più comuni definiti da Microsoft® Visual Basic® sono:
Tipo di Dato
Prefisso
Valore Ammesso
Boolean
bln
True/False
Byte
byt
0-255
Currency
cur
da -922,337,203,685,477.5808 a
922,337,203,685,477.5807.
Date (Time)
dtm
Data (64 bit)
Double
dbl
da 1.79769313486231E308 a
-4.94065645841247E-324 per valori
negativi; da 4.94065645841247E-324 a
1.79769313486232E308 per valori positivi.
Integer
int
da -32,768 a 32,767
Long
lng
da -2,147,483,648 a 2,147,483,647
Object
obj
Un variabile Oggetto
Single
sng
da -3.402823E38 a -1.401298E-45 per
valori negativi; da 1.401298E-45 a
3.402823E38 per valori positivi
String
str
Sequenze di caratteri a lunghezza fissa da 0
a 63K caratteri o a lunghezza variabile da 0
a 2 billioni di caratteri.
User-defined type
udt
Tipi definiti dall'utente
Variant
vnt
Valore Variant (16/22 Byte)
Possiamo anche definire dei nostri tipi di dati personalizzati, così come possiamo definire delle
matrici di dati. Anche di questo parleremo più avanti nel corso del Tutorial.
Quando le variabili vengono inizializzate, le variabili numeriche sono inizializzate a 0, le
stringhe a lunghezza variabile sono inizializzate ad una stringa vuota (""), e le stringhe a
lunghezza fissa sono riempite con caratteri ASCII zero. Le variabili Variant sono inizializzate al
valore Empty. Ciascun elemento di un tipo definito dall'utente viene inizializzato come se fosse
un elemento isolato dal resto del tipo definito dall'utente.
Operatori Logici
Anche in Microsoft® Visual Basic® 6.0 ci sono una serie di operatori logici per valutare e
relazionare espressioni. Tra questi i più importanti sono:
NOT
OR
AND
XOR
Negazione
Disgiunzione
Congiunzione
Esclusione
Costrutti Condizionali
Tra i costrutti condizionali presenti in Microsoft® Visual Basic® 6.0 i più importanti sono:
If ... Then ... Else ... End If
Select Case ... End Select
Il primo costrutto permette di valutare diverse condizioni e di eseguire del codice al verificarsi
della prima condizione che risulti vera. Al verificarsi di una condizione le condizioni seguenti
saranno ignorate, se all'interno dello stesso blocco condizionale. I costrutti If possono essere
annidati.
If condizione Then
[istruzioni]
[ElseIf condizione-ennesima Then
[istruzioni alternative]] ...
[Else
[istruzioni da eseguire in tutti i casi non previsti]]
End If
Il secondo costrutto invece permette di valutare diverse situazioni in funzione di un'unica
espressione. Risulta comodo quando vi sono espressioni uniche che possono assumere diversi
valori a seconda del momento. In questi casi il costrutto permette di svolgere blocchi di
istruzioni piuttosto che altri in funzione del valore assunto dall'espressione valutata.
Select Case espressione da valutare
[Case lista di valori possibili separati da virgole
[istruzioni]] ...
[Case Else
[istruzioni da eseguire in qualsiasi caso non previsto]]
End Select
Il costrutto Select Case ... End Select è da preferirsi, in termini di prestazioni, al costrutto If ...
Then ... End If laddove sia possibile applicarli indistintamente.
Costrutti Iterativi
I costrutti iterativi sono quelli che permettono di eseguire più volte uno stesso blocco di
istruzioni. In Microsoft® Visual Basic® 6.0 abbiamo diverse modalità di costruzione di costrutti
iterativi. I più utilizzati sono i costrutti For ... Next e Do ... Loop .
Vediamo come funziona il primo:
For Contatore = Inizio To Fine [Step Passo]
[istruzioni]
Next [Contatore]
Il che equivale a dire che si vuole ripetere N volte un blocco di istruzioni, per N che varia da
Inizio a Fine spostandosi ogni volta di un valore pari al Passo. C'è anche la possibilità di
abbandonare l'iterazione prima della fine tramite l'istruzione Exit For.
Il costrutto Do ... Loop invece ripete un blocco di istruzioni finchè non diventa vera una
determinata condizione.
Do {While | Until [condizione]}
[istruzioni]
Loop {While | Until [condizione]}
Se si indica la condizione all'inizio del ciclo (Do), qualora la condizione non sia verificata
nemmeno all'inizio del ciclo stesso, non vi sarà alcuna esecuzione di istruzione. Se invece la
verifica della condizione viene posta alla fine del ciclo (Loop) allora comunque le istruzioni
all'interno del ciclo saranno eseguite almeno una volta. Qualora si utilizzi la parola chiave While
il ciclo sarà ripetuto finché la condizione rimane vera, altrimenti nel caso della parola chiave
Until l'iterazione si svolgerà finché la condizione rimane falsa e si fermerà non appena la
condizione diventa vera. Come nel caso precedente è possibile uscire immediatamente da un
ciclo di questo tipo tramite l'istruzione Exit Do.
Dichiarazione di Procedure e Funzioni
Entreremo meglio nel dettaglio della dichiarazione di procedure e funzioni nelle prossime
lezioni del Tutorial su Microsoft® Visual Basic® 6.0 . In questo momento ciò che conta è capire
come sia possibile costruire isole di codice richiamabili più volte dalle nostre procedure evento
per poter svolgere compiti ripetitivi. Per fare questo ci appoggeremo alla dichiarazione di
subroutine (blocchi di istruzioni che svolgono una determinata attività e non restituiscono alcun
valore a chi le ha invocate) e funzioni (procedure che restituiscono un particolare valore a chi
le invoca). La sintassi da usare è:
[{Public | Private}] Sub NomeProcedura ([argomenti])
[istruzioni]
End Sub
[{Public | Private}] Function NomeFunzione ([argomenti]) As TipoRestituito
[istruzioni]
End Function
Come si intuisce dalle dichiarazioni, la parola chiave Sub identifica la dichiarazione di una
subroutine (non restituisce valori) e la parola chiave Function indica la dichiarazione di una
funzione (restituisce una variabile di tipo TipoRestituito). Come argomenti vanno passate delle
variabili (capiremo meglio più avanti con che modalità) che permettano alle nostre subroutine
e funzioni di lavorare su dei dati in ingresso. Queste variabili saranno caratterizzate da un tipo
di dato.
La nostra prima Funzione
Concludiamo quindi questa lunga puntata con un esempio di funzione che restituisce un valore
dopo avere eseguito un ciclo nel quale si valutano delle espressioni.
Public Function ContaNumeroInteroLungo() As Long
'Questa funzione conta casualmente per 5 secondi
'a partire da quando viene chiamata,
'quindi restituisce il valore contato.
Dim lngValoreContato As Long
Dim vntInizioConteggio As Variant
vntInizioConteggio = Timer
Do While (Timer - vntInizioConteggio) <5
lngValoreContato = lngValoreContato + 1
'Se sto andando oltre i limiti di dimensione della
'variabile che ho scelto esco comunque dal ciclo
If lngValoreContato > 2147483645 Then
Exit Do
End If
Loop
'Restituisco al chiamante il valore contato
ContaNumeroInteroLungo = lngValoreContato
End Function
LA NOSTRA PRIMA FORM: LA FINESTRA DI BENVENUTO
La Form di benvenuto
All'interno di un progetto Microsoft® Visual Basic® possiamo inserire diversi elementi, tra questi
vi sono le Form che sono il principale strumento per la realizzazione di una interfaccia grafica.
La Form è l'equivalente di una qualsiasi finestra di Windows. Il tipico approccio allo sviluppo di
applicazioni desktop (destinate all'utente finale) orientato agli eventi in Microsoft® Visual Basic®
prevede la realizzazione della parte di interfaccia grafica e l'associazione agli elementi disegnati
di procedure evento (vedi Lezione 2).
In questa puntata ci concentreremo sugli elementi grafici che generalmente si inseriscono in
una finestra di benvenuto.
Controlli predefiniti
All'interno di Microsoft® Visual Basic® abbiamo una serie di controlli sempre disponibili di
seguito riepilogati.



Puntatore: serve per selezionare i controlli nella form.
Picture: permette di inserire elementi grafici nelle form, può contenere altri controlli al
suo interno (si dice controllo contenitore).
Label: serve per inserire etichette di testo nella form.















TextBox: consente di ricevere informazioni testuali dall'utente della nostra applicazione.
Frame: è un altro controllo contenitore che permette di delimitare l'area che contiene
con un titolo ed un riquadro tridimensionale.
CommandButton: si utilizzano per inserire pulsanti clickabili nelle finestre.
CheckBox: forniscono caselle di selezione dove l'utente può abilitare o meno valori,
permettono di rappresentare informazioni binarie (Vero/Falso). Spesso si inseriscono in
controlli contenitore per raggrupparli.
OptionButton: si utilizzano per porre all'utente domande a risposta multipla, di cui una
sola per volta può essere vera. Spesso si inseriscono in controlli contenitore per
raggrupparli.
ComboBox: è la classica casella a discesa tipica delle interfacce grafiche di oggi. Permette di fornire all'utente
un elenco di valori che si espande solo quando l'utente preme la freccia di espansione. Fornisce diversi stili di
interazione con l'utente.
ListBox: è la versione senza pulsante a discesa ma con barre di scorrimento del controllo precedente.
HScrollBar, VScrollBar: consentono di disegnare barre di scorrimento orizzontali (HScrollBar) e verticali
(VScrollBar). Generalmente si utilizzano per scorrere il contenuto di controlli contenitore.
Timer: ci permette di svolgere determinate attività ripetutamente (ogni N millisecondi) oppure dopo un certo
momento da quando decidiamo di eseguirle (eventi asincroni).
DriveListBox, DirListBox, FileListBox: consentono di creare elementi grafici di selezione del disco, della
cartella e dei file dal file system dell'utente finale della nostra applicazione. Si possono utilizzare per costruire
finestre di apertura/salvataggio files su disco. Conviene però appoggiarsi agli strumenti forniti dal sistema
operativo (Common Dialog) al fine di avere un'interfaccia consistente con il sistema in cui la nostra
applicazione viene eseguita.
Shape: permette di disegnare forme varie (cerchi, quadrati, ecc.) sulla Form.
Line: permette di disegnare linee sulla Form.
Image: si utilizza per caricare nel documento file grafici. Contrariamente al controllo Picture non si tratta di un
controllo contenitore.
Data Control: consente di collegare alcuni dei controlli precedenti ad una fonte dati, noi useremo la versione
OLEDB del Data Control e non questa che si appoggia ad una tecnologia di accesso ai dati (DAO = Data
Access Objects) ormai in disuso.
OLE Control: permette di collegare (OLE = Object Linking and Embeding) documenti da OLE server esterni
(Word, Excel, ecc.), ultimamente è poco utilizzato.
Disegnamo la Form di benvenuto
All'interno di Microsoft® Visual Basic® creiamo quindi un progetto di tipo Standard EXE nuovo.
Selezioniamo la Form che viene creata automaticamente (Form1) e gestiamone prima di tutto
l'aspetto grafico.
Una delle prime attività che conviene svolgere è rinominare il progetto (tasto destro del
mouse su Project1 -> Project1 Properties e quindi assegnare un valore sensato alla proprietà
Project Name nel nostro caso useremo Biblio_VBIUG). Quindi è una buona regola dare un
nome ragionevole anche alle form che si utilizzano. Assegnamo nome frmSplash alla nostra
finestra iniziale di benvenuto (tasto destro del mouse su Form1 -> Properties, quindi assegnare
il valore alla proprietà (Name) ). La rappresentazione del nostro progetto diventerà quindi la
seguente.
A questo punto siamo pronti per disegnare il contenuto della nostra finestra di benvenuto.
Per prima cosa caratterizzimo l'aspetto grafico della finestra stessa. Dalle proprietà della form
configuriamo la finestra come di seguito indicato:




Caption = Vuoto (è il titolo della finestra e di solito le finestre di benvenuto non hanno
titolo).
BorderStyle = 1 - Fixed Single (corrisponde ad un bordo sottile e non ridimensionabile).
ControlBox = False (nasconde il menù di sistema e l'icona della finestra in alto a
sinistra).
StartUpPosition = 2 - CenterScreen (fa in modo che la finestra si apra esattamente al
centro dello schermo corrente).
Selezioniamo dalla casella degli strumenti il controllo Frame e tracciamo un riquadro nella
finestra della dimensione che più ci aggrada. Anche di questo controllo svuotiamo la proprietà
Caption in modo tale che non abbia alcun titolo e si presenti solo come un riquadro.
Selezioniamo il Frame appena creato e disegnamo al suo interno un controllo Image, diamo a
questo ultimo nome imgSplashLogo (proprietà (Name) ). Per caricare un'immagine nel
controllo appena disegnato selezioniamo la proprietà Picture e facciamo doppio click sulla
stessa per scegliere un file grafico dal disco fisso (nel percorso "C:\Program Files\Microsoft
Visual Studio\Common\Graphics" o simile, a seconda di dove è stato installato Visual Basic,
troverete diverse immagini già pronte. Nella sotto cartella Icons\Writing selezioniamo il file
BOOKS05.ICO). Il controllo immagine appena disegnato si ridimensionerà per contenere
secondo le giuste proporzioni l'immagine appena assegnatagli. Per fare in modo che l'immagine
sia "stirabile" e si possa quindi ingrandire impostate a True la proprietà Stretch e quindi stirate
il controllo fino alla dimensione desiderata. Avremo una frmSplash simile alla seguente:
Inseriamo a questo punto un paio di etichette di testo (Label) per rappresentare le
informazioni sul prodotto (nome, versione, produttore) e una linea che separi queste
informazioni dalle informazioni sul Copyright.
Sono sufficienti quattro controlli Label così configurati:
1. (Name) = lblCompany
Autosize = True
Caption = "Visual Basic - Italian User Group"
Font = Verdana, 12, Regular
2. (Name) = lblProductName
Autosize = True
Caption = "Archivio Biblioteca"
Font = Verdana, 14, Bold
3. (Name) = lblProductVersion
Autosize = True
Caption = "1.0"
Font = Verdana, 14, Regular
4. (Name) = lblCopyRight
Autosize = True
Caption = "(C) VBIUG Tutorials - 2001"
Font = Verdana, 10, Italic
Inseriamo anche una riga (controllo Line) che divida le informazioni.
Il risultato sarà simile al seguente:
Se provate ad eseguire questo progetto (F5) vi renderete subito conto che manca qualcosa di
fondamentale ... un modo per fermare la finestra di benvenuto e continuare con la normale
esecuzione del programma.
Per fare questo utilizzeremo due diversi strumenti:


Un controllo Timer
Una procedura evento
Il controllo Timer possiamo inserirlo dove vogliamo nella form, si tratta infatti di un controllo
invisibile in fase di esecuzione e quindi non rovinerà l'aspetto grafico della nostra finestra.
Assegnamogli le seguenti proprietà:



(Name) = tmrUnload
Interval = 3000 (cioè 3 secondi, si tratta di millesimi di secondo)
Enabled = True (vogliamo che scatti!)
A questo punto facciamo doppio click sul controllo Timer appena configurato.
Ci troveremo nella finestra del codice associato alla procedura evento tmrUnload_Timer().
Scriviamo il seguente codice:
Public Sub tmrUnload_Timer()
'Questa procedura scarica la finestra di benvenuto e passa il controllo
alla normale esecuzione del programma
Unload frmSplash
End Sub
L'istruzione Unload frmSplash equivale a comunicare al VB che vogliamo scaricare la finestra
frmSplash dalla memoria e quindi vogliamo anche nasconderla. In questo modo, dopo 3
secondi dal caricamento della nostra finestra di benvenuto il Timer scatterà e la scaricherà
dalla memoria.
Salviamo prima di chiudere
Ricordiamoci di salvare il progetto prima di chiuderlo e confermiamo i nomi che abbiamo
associato agli oggetti creati sino a qui (Biblio_VBIUG per il progetto, frmSpalsh per la finestra
di benvenuto).
LA MASCHERA PRINCIPALE DI UN PROGETTO:
MENU' E BARRE DEI PULSANTI
Applicazioni SDI e MDI
Le interfacce utente dei software possono essere raggruppate in due grandi categorie:


Single Document Interface (SDI): applicazioni basate su un'unica finestra, che per ogni
documento richiedono una nuova istanza di programma (ad es. Notepad).
Multiple Document Interface (MDI): applicazioni che gestiscono più documenti
all'interno di un'unica istanza (ad es. Microsoft® Word 9x).
Per creare applicazioni SDI è sufficiente costruire dall'IDE di Microsoft® Visual
Basic® l'interfaccia grafica ed associare ai controlli inseriti nella form delle procedure evento
(Lezione 2, Lezione 3 e Lezione 4).
Lo sviluppo di applicazioni MDI richiede invece generalmente uno sforzo maggiore per gestire
barre dei pulsanti, barre dei menù contestuali al documento visualizzato e gestione degli eventi
di caricamento e scaricamento dei documenti.
Per questo motivo ci occuperemo in questa lezione dello sviluppo di interfacce MDI, in quanto i
concetti appresi saranno applicabili nello stesso modo anche alle applicazioni SDI seppur in un
contesto semplificato.
Creare una finestra MDI principale
I progetti basati su interfaccia MDI richiedono che sia inserita all'interno del progetto una form
"speciale" di tipo MDIForm che si comporterà da "contenitore" per tutte le altre form di
visualizzazione dei documenti. Per fare questo apriamo il progetto Biblio_VBIUG e dalla finestra
di progetto (CTRL+R) premiamo il tasto destro del mouse sul progetto e scegliamo la voce
Inserisci -> MDI Form come illustrato in figura.
Ogni progetto può contenere una sola finestra di tipo MDI che sarà il contenitore di tutte le
altre finestre di documento, che si diranno MDIChild.
Tutte le form tradizionali (non MDI) proprio per questo hanno tra le loro proprietà la voce
MDIChild che se impostata a True permette di inserirle all'interno della MDIForm contenitore.
Per impostare l'aspetto grafico della MDI Form in modo tale che presenti una barra dei pulsanti
ed una barra di stato occorre aggiungere al progetto dei riferimenti a controlli esterni. Si
prema il tasto destro del mouse sulla casella degli strumenti e si selezioni la voce
Componenti o si scelga la voce di menù Progetto -> Componenti. Si cerchi e si selezioni
"Microsoft Windows Common Controls 6.0" (MSCOMCTL.OCX).
Questo componente OCX fornisce alcuni controlli utili per disegnare interfacce utente con il
tipico aspetto delle applicazioni Windows. Premendo il pulsante Chiudi appariranno nella casella
degli strumenti dei nuovi controlli (come rappresentato in figura).
Quelli evidenziati in rosso sono gli strumenti che servono a noi per realizzare la nostra
interfaccia utente. Selezionare e trascinare la Barra Pulsanti sulla MDI Form appena inserita.
Fare altrettanto con la Barra di Stato e con la Lista di Immagini. Assegnare i seguenti nomi agli
elementi:




ToolBar: barra dei pulsanti
StatusBar: barra di stato
imgList: lista di immagini
frmMain: MDIForm
Premere il tasto destro del mouse sul controllo imgList e scegliere la voce di menù "Proprietà".
Selezionare una dimensione 16x16 per le immagini e visualizzare il pannello "Immagini", dal
quale è possibile caricare una lista di file grafici che dovranno corrispondere alle immagini dei
nostri pulsanti. Caricare una ad una le immagini dei pulsanti da inserire ed assegnare a
ciascuna immagine una Chiave. Usare le seguenti immagini (dal percorso su disco "\Program
Files\Microsoft Visual Studio\Common\Graphics\Bitmaps\ OffCtlBr\Large\Color\):



NEW.BMP => Chiave: New
OPEN.BMP => Chiave: Open
SAVE.BMP => Chiave: Save
Premere OK per salvare. Premere ora il tasto destro del mouse sulla barra dei pulsanti e
selezionare la voce di menù "Proprietà". Assegnare il valore imgList alla proprietà "ImageList".
Sarà ora possibile creare i pulsanti della barra bottoni associandovi le immagini
precedentemente inserite. Dal pannello "Bottoni" inserire tramite il tasto "Inserisci Bottone" i
pulsanti valorizzando le seguenti proprietà:



Chiave: è la chiave che useremo per riconoscere i bottoni da codice (usare New, Open e
Save rispettivamente).
ToolTipText: è il testo di aiuto che verrà visualizzato al passaggio del mouse sui bottoni
(opzionale ma utile).
Immagine: indica la chiave dell'immagine associata a ciascun bottone (usare le tre
chiavi inserite per le immagini nella lista New, Open e Save).
A questo punto la nostra barra pulsanti è pronta dal punto di vista grafico. Occorre quindi
creare la barra dei menu. Premere il tasto destro del mouse su un'area libera della MDI Form e
scegliere la voce "Menù Editor". Dalla finestra che compare caricare le voci di menù necessarie
considerando che:



Caption: è il testo che verrà visualizzato nella voce di menù. Per avere la prima lettera
di un menù sottolineata usare la & (e commerciale) prima della lettera da sottolineare.
Per inserire uno spazio (riga) tra diverse voci di menù usare come caption il segno
meno (-).
Nome: è il nome che verrà utilizzato da codice per riferirsi alla voce
Le freccette (vedi figura) servono per gestire la posizione delle voci di menù le une
rispetto alle altre.
Rimane ora da configurare la barra di stato. Per farlo è sufficiente premere un'ultima volta il
tasto destro del mouse sulla barra di stato disegnata nella MDI Form e scegliere "Proprietà".
Dal pannello "Pannelli" caricare i pannelli necessari tenendo presente che:




Chiave: ci servirà, ancora una volta, per valorizzare da codice i pannelli in termini di
contenuto
Stile: ci permette di scegliere se il pannello deve visualizzare del testo, lo stato dei
pulsanti Ins, CapsLock, BlocNum oppure informazioni su data e ora (Kana è per le
tastiere giapponesi, a noi non serve)
Allineamento: permette di impostare l'allineamento a destra, sinistra o centrato del
testo mostrato
AutoSize: permette di indicare alla statusbar quali pannelli si devono dimensionare
automaticamente. Di solito si usa per il pannello all'estrema sinistra che contiene le
informazioni di stato testuali scegliendo il valore sbrSpring che corrisponde ad occupare
tutto lo spazio a disposizione, lasciato quindi libero dagli altri pannelli.
Inseriamo 4 pannelli con le seguenti caratteristiche:




Chiave:
Chiave:
Chiave:
Chiave:
Status - Stile: sbrText - AutoSize: sbrSpring - Allineamento: sinistra
Ins - Stile: sbrIns - AutoSize: sbrNoAutoSize - Allineamento: centrato
Date - Stile: sbrDate - AutoSize: sbrNoAutoSize - Allineamento: centrato
Time - Stile: sbrTime - AutoSize: sbrNoAutoSize - Allineamento: centrato
Diamo infine un titolo alla finestra MDI Form tramite la proprietà Caption, usiamo il valore
"Archivio Biblioteca - VBIUG".
A questo punto abbiamo costruito una finestra principale che si presenterà in modo simile alla
figura seguente.
Rimane da gestire il codice associato agli eventi che il nostro utente può scatenare usando tale
interfaccia.
Associazione del codice all'interfaccia
Il codice da associare alla nostra interfaccia sarà comune tanto ai menù quanto ai pulsanti. E'
allora consigliabile creare delle procedure (Sub o Function) a livello di modulo Form o
all'interno di un modulo di codice BAS (Progetto -> Inserisci Modulo) al fine di richiamare le
stesse da diversi punti del programma (menù e bottoni per esempio). Inseriamo quindi un
modulo BAS e definiamo 4 procedure al suo interno, come segue:
Public Sub Main()
'Questa procedura si occupa dell'avviamento del programma
frmSplash.Show vbModal
frmMain.Show
End Sub
Public Sub NewFile()
'Questa è la procedura che gestirà la creazione di un nuovo file
End Sub
Public Sub OpenFile()
'Questa è la procedura che gestirà l'apertura di un file
End Sub
Public Sub SaveFile()
'Questa è la procedura che gestirà il salvataggio di un file
End Sub
Public Sub Quit()
'Questa è la procedura che gestisce la chiusura del programma
End
End Sub
Per associare queste procedure ai pulsanti ed alle voci di menù basta selezionare dalla
modalità di design le voci di menu. Comparirà il codice di ciascuna voce nel quale si dovrà
scrivere il nome della procedura da richiamare. Per i pulsanti si dovrà invece fare doppio click
sulla barra dei pulsanti e all'interno del codice della procedura evento che si presenterà(Private
Sub ToolBar_ButtonClick) riportare un costrutto Select Case basato sulla chiave del parametro
Button che viene passato ByVal alla procedura evento. Il codice della procedura evento della
barra pulsanti della nostra MDI Form sarà simile a quanto riportato nella figura seguente.
Ultime operazioni prima di chiudere
Dalla finestra delle proprietà del nostro progetto configuriamo come oggetto di avvio la
procedura Sub Main anziché la form frmSplash.
Chiamiamo il modulo di codice BAS creato modMain e salviamolo.
Salviamo la MDI Form con nome frmMain.
MASCHERE DI SECONDO LIVELLO
Form secondarie
Nella puntata precedente abbiamo visto come sia possibile realizzare una finestra principale in
grado di contenere una serie di finestre secondarie, una barra dei menu ed una barra dei
pulsanti. Ora ci occuperemo della creazione delle finestre secondarie da inserire all'interno
della form MDIForm principale. Innanzitutto occorre dire che una form secondaria si dice
MDIChild, cioè figlia, proprio per indicare che potrà vivere solo all'interno di una form MDIForm
principale. Contrariamente alle MDIForm principali che sono diverse dalle form normali, le form
MDIChild sono finestre canoniche (form) che hanno la proprietà MDIChild impostata a True.
Inseriamo quindi nel nostro progetto Biblio_VBIUG una nuova Form e nella finestra delle
proprietà assegnamo alla proprietà MDIChild il valore True. Diamole quindi nome (Name)
frmChild e impostiamo il suo titolo (Caption) con il valore "Documento". Al suo interno per ora
non carichiamo alcun oggetto. Vedremo nelle prossime lezioni come gestire tramite controlli
grafici l'accesso ai dati. Per ora occupiamoci dell'interazione tra la nostra MDIForm e la
frmChild.
Visualizzare le form MDIChild
Per mostrare una form MDIChild è sufficiente richiamare il metodo Show così come accade per
le form tradizionali. Proviamo quindi a scrivere nella Sub NewFile() il codice che mostra la
nostra finestra MDIChild.
Public Sub NewFile()
'Questa è la procedura che gestirà la creazione di un nuovo file
frmChild.Show
End Sub
Proviamo ad eseguire il nostro programma. Qual è il problema che si evidenzia subito ? Se
premiamo più volte il tasto "File->Nuovo" la finestra si apre solo la prima volta e non viene
creata una nuova finestra per ogni pressione del tasto o scelta della voce di menù
corrispondente. Questo è corretto se ci pensiamo perchè noi stiamo chiedendo, ad ogni
esecuzione della procedura, di mostrare la frmChild. Se frmChild è già visibile non succederà
nulla. Potremmo a questo punto pensare di dover creare N copie della nostra frmChild (ne
facciamo 10 ? 20 ? quante ?) per averle pronte da visualizzare, ma questo non sarebbe un
buon modo di lavorare, non possiamo vincolare il nostro utente finale ad aprire un numero
massimo di finestre Child in funzione di quante secondo noi dovevano essere aperte. Allora
quale può essere la soluzione al problema ?
Istanze multiple di una form
Quando noi creiamo una form all'interno di Visual Basic dall'interfaccia grafica del VB quello
che facciamo in realtà è creare un "modello" di form e non una form unica. Se provate a
scrivere dentro ad una qualsiasi finestra di codice del nostro programma Biblio_VBIUG
un'istruzione come la seguente:
Dim objForm As New frmChild
vedrete che da VB non avrete alcun errore, anzi potrete fare riferimento a tutte le
caratteristiche di frmChild, compresi i controlli eventualmente inseriti al suo interno, tramite la
variabile objForm. Attenzione però che quella che utilizzerete non sarà la frmChild che avete
disegnato voi, ma una copia identica della stessa. Cosa significa questo ? Significa che le form
che noi costruiamo in VB sono "modelli" di form, si chiamano in realtà classi e di queste
possiamo crearne diverse copie fra loro uguali come caratteristiche e comportamento (label,
textbox, pulsanti, codice delle procedure evento) ma diverse come valore delle singole
proprietà (la Caption, la posizione, ecc.). Allora proviamo a scrivere il codice seguente nella
procedura NewFile:
Public Sub NewFile()
'Questa è la procedura che gestirà la creazione di un nuovo file
Dim frmNewChild As frmChild
Set frmNewChild = New frmChild
nlDocumenti = nlDocumenti + 1
frmNewChild.Caption = "Documento " & nlDocumenti
frmNewChild.Show
End Sub
Ogni volta che la procedura verrà richiamata otterremo la creazione di una nuova copia della
frmChild che avrà titolo diverso dalle copie precedenti in virtù della variabile globale (definita
come Private nlDocumenti As Long in modMain.BAS). Il risultato sarà simile a quello
rappresentato in figura.
Ora rimangono ancora alcune questioni da risolvere:
1) come facciamo a distinguere tra loro le finestre MDIChild ?
2) come facciamo a gestire le MDIChild con codice univoco all'interno della MDIForm
principale ?
Scaricare una Form MDI Child
Ciascuna form MDIChild sarà individuabile tramite la proprietà ActiveForm delle MDIForm
principale. Nel nostro caso quindi scrivere:
MsgBox frmMain.ActiveForm.Caption
corrisponderà a visualizzare in una MsgBox il titolo della MDIChild attiva in questo momento.
In alternativa ciascuna MDIChild al suo interno potrà fare riferimento a se stessa tramite la
parola chiave Me. Infatti se provate ad inserire nella frmChild un CommandButton con il codice
seguente:
MsgBox frmChild.Caption
fornirà un risultato forse inaspettato, ma corretto: avrete sempre il titolo della frmChild così
come l'avete definita dall'IDE del VB.
Se invece scrivete nel codice della procedura evento click del CommandButton:
MsgBox Me.Caption
otterete ogni volta il titolo della frmChild corrente. Poter individuare una MDIChild fra tante è
fondamentale sia per poter gestire correttamente il diverso contenuto delle MDIChild sia per
poterne gestire la corretta chiusura/scaricamento. Pensate di voler aggiungere una voce di
menù "Chiudi" che permetta di scaricare la MDIChild corrente. Un primo modo di lavorare è
aggiungere una voce di menù alla frmMain e associare ad essa il seguente codice:
Unload frmMain.ActiveForm
In alternativa potete associare dei menù particolari a ciascuna MDIChild tenendo presente che
quando una MDIChild ha un menù associato, questo sovrascriverà il menù della MDIForm
principale ogni qualvolta la Child sarà la finestra attiva. Questo significa che in un progetto con
una MDIForm e due MDIChild, di cui una senza menù e l'altra con un menù personalizzato,
ogni volta che la MDIChild senza menù sarà la MDIChild attiva avremo in alto il menù della
MDIForm, mentre quando sarà attiva la MDIChild dotata di menù avremo in alto il menù di
questa ultima al posto di quello della MIDForm. Allora per renderci conto di questo inseriamo
nella frmChild un menù uguale a quello della frmMain ma con in più la voce "Chiudi" prima di
"Esci" e associamole il seguente codice:
Private Sub mnuClose_Click()
Unload Me
End Sub
Il risultato sarà proprio quello voluto: ogni volta che sceglieremo il menù "Chiudi" la sola
MDIChild corrente si chiuderà.
Durante la chiusura di una MDIChild o della MDIForm principale potremmo avere l'esigenza di
gestire il salvataggio dei dati contenuti. Pensate a cosa accade quando chiudete Microsoft Word
senza aver salvato il documento corrente. Il programma vi chiede se volete salvare o meno i
dati, oppure se volete annullare la chiusura del programma.
La stessa situazione possiamo gestirla anche noi con il codice delle procedure evento
Form_Unload e Form_QueryUnload delle MDIChild. Ogni volta che la MDIForm viene chiusa
prima di chiudersi e scaricare con se le MDIChild che contiene succede quanto segue:
1) Tutte le MDIChild vengono "pre-allertate" della chiusura tramite l'evento Form_QueryUnload
e se anche una sola di queste imposta l'argomento Cancel = True nel codice della procedura
evento, l'intero processo di Unload viene sospeso e tutte le form (MDIForm e MDIChild)
rimangono caricate
2) Se nessuna MDIChild ha detto Cancel = True nell'evento Form_QueryUnload allora la
MDIForm richiama per ciascuna MDIChild l'evento Form_Unload e scarica la MDIChild. Se
anche una sola delle MDIChild imposta Cancel = True a questo punto il processo di Unload si
ferma comunque, ma le MDIChild che avevano già ricevuto l'evento Form_Unload senza dire
Cancel = True, ormai sono già state scaricate.
Per provare questo comportamento nel codice del nostro progetto, che potete scaricare in
versione aggiornata, trovate un esempio concreto.
Gestire le form MDIChild dalla MDIForm
Cosa manca ancora al nostro progetto, dal punto di vista dell'interfaccia utente, che gli altri
programmi MDI hanno ?
La possibilità di gestire le finestre con il classico menù "Finestre" che permette di posizionare e
richiamare le MDIChild.
Questa ultima funzionalità è assolutamente banale e si ottiene semplicemente aggiungendo al
menù della MDIForm o delle MDIChild (non dimenticate che i menù delle MDIChild vincono su
quello della MDIForm !) una voce di menù che abbia l'attributo WindowList selezionato. Questo
ci permetterà di avere l'elenco delle MDIChild caricate, separato con una linea dal resto delle
voci di quel menù (vedi le figure).
Noi dovremo aggiungere a mano le voci di menù per allineare le MDIChild.
Il codice da associare alle singole voci di menù si basa sul metodo Arrange proprio di ciascuna
MDIForm che permette di gestire l'allineamento delle MDIChild.
Per i più curiosi è stata inserita anche una procedura che "scorre" tutte le MDIChild per ridurle
ad icona basandosi sulla parola chiave Forms che corrisponde alla collezione di tutte le form
caricate (Loaded) nel progetto corrente.
Tra queste a noi interessano solo quelle di tipo frmChild (TypeOf objForm Is frmChild). Ecco il
codice caricato nella nostra frmChild:
Private Sub mnuTileHorizontally_Click()
frmMain.Arrange vbTileHorizontal
End Sub
Private Sub mnuTileVertically_Click()
frmMain.Arrange vbTileVertical
End Sub
Private Sub mnuCascade_Click()
frmMain.Arrange vbCascade
End Sub
Private Sub mnuIconize_Click()
Dim objForm As Form
For Each objForm In Forms
If TypeOf objForm Is frmChild Then
objForm.WindowState = vbMinimized
End If
Next
End Sub
ACCESSO AI DATI CON OLEDB E
I CONTROLLI NATIVI DEL VISUAL BASIC
I Controlli Nativi
Microsoft Visual Basic è da sempre un linguaggio orientato alla produzione rapida di
applicazioni dotate di interfaccia utente. In particolare le applicazioni di accesso ai dati sono tra
le più tipiche realizzazioni Visual Basic grazie alla presenza di controlli di accesso ai dati e di
visualizzazione degli stessi dall'utilizzo immediato.
Tra questi controlli possiamo per esempio considerare:




Microsoft
Microsoft
Microsoft
Microsoft
ADO Data Control 6.0
DataGrid Control 6.0
DataList Control 6.0
DataRepeater Control 6.0
E' sufficiente quindi da un qualsiasi progetto VBP selezionare tramite la voce di menù Progetto>Componenti i precedenti controlli per poter scrivere (o il più delle volte disegnare con il
mouse) le nostre applicazioni di accesso ai dati.
Una form MDIChild di accesso ai Dati
Iniziamo quindi con il disegnare il nostro database dei libri per la nostra biblioteca.
Il database prevederà le seguenti tabelle:





tab_Libri
tab_Iscritti
tab_Prestiti
tab_Prenotazioni
tab_StoricoPrestiti
e pensiamo alla realizzazione di una form MDIChild per consultare la lista dei libri tramite una
griglia.
Inseriamo nel nostro progetto della biblioteca una form e impostiamo a True la sua proprietà
MDIChild. Assegnamo alla form il nome frmLibri e il titolo (caption) "Anagrafica Libri" e
salviamola.
Aggiungiamo al progetto i controlli:
- Microsoft ADO Data Control 6.0
- Microsoft DataGrid Control 6.0
ed inseriamoli nella form MDIChild come nell'immagine seguente.
Assegnamo alla DataGrid il nome grdLibri e all'ADO Data Control il nome datLibri.
Iniziamo quindi a configurare l'ADO Data Control indicandogli quale sia il database Access 2000
da cui deve leggere i dati e quale tabella vogliamo leggere.
Configurazione di ADODC
Per fare questo premiamo il tasto destro del mouse sul controllo e scegliamo la voce di menù
"Propietà ADODC".
Nella finestra di proprietà che viene visualizzata possiamo indicare all'ADODC la stringa di
connessione al database in diversi modi, scegliamo "Usa Stringa di Connessione" (la terza
opzione) e configuriamo graficamente la connessione alla base dati.
Scegliamo come Provider "Microsoft Jet 4.0 OLE DB Provider" per indicare all'ADODC che
vogliamo utilizzare il Jet Engine di Access 2000 (4.0), selezioniamo quindi il file di database
MDB e abilitiamo il salvataggio delle informazioni di sicurezza, come nell'immagine seguente e
- dopo aver eventualmente testato positivamente la connessione - premiamo il tasto "OK".
A questo punto spostiamoci nella sezione relativa alla sorgente dati (terzo pannello di
configurazione dell'ADODC) e indichiamo che vogliamo accedere ad una tabella di dati
(adCmdTable) di nome tab_Libri, come nella seguente immagine.
Premiamo OK e salviamo nuovamente la form.
Configurazione della Data Grid
A questo punto dobbiamo indicare alla Data Grid che il suo contenuto deve essere letto
dall'ADODC appena configurato. Ottenere questo è assolutamente banale, è sufficiente
selezionare la Data Grid e dalla finestra delle sue proprietà selezioniamo nella proprità
DataSource l'ADODC appena configurato, come da immagine.
Se a questo punto modifichiamo i menù della nostra MDIForm affinché vi sia una voce per
visualizzare la frmLibri potremo osservare che la nostra form è già pronta per l'uso.
Volendo potremmo personalizzare l'aspetto delle colonne di dati rappresentate nella griglia
entrando nelle proprità della Data Grid o, ancor meglio, selezionando una ad una le colonne di
nostre interesse nella tabella di dati.
E' infatti completamente inutile recuperare un'intera tabella da un database per poi sfruttarne
solo alcune colonne, conviene richiedere direttamente al motore di database le sole colonne di
nostro interesse.
Data Binding a singolo campo
Se volessimo poi rappresentare all'interno di una singola form dati non in forma tabellare
(griglia) ma tramite diversi controlli, per esempio TextBox, ComboBox, Option Button, ecc.
dovremo considerare le seguenti proprietà di configurazione:



DataSource: è il controllo ADODC da cui leggere i dati
DataField: è il campo della tabella o selezione dati correntemente ottenuta tramite
l'ADODC che si vuole visualizzare nel controllo
DataFormat: si tratta di informazioni sulla formattazione a schermo del dato da
visualizzare (data, valuta, numero, ecc.)
Impostando queste proprietà per ciascuno dei controlli da visualizzare nella form (vedi
immagine 8) è possibile costruire delle maschere che visualizzino un singolo record e che si
possono poi scorrere tramite i tasti cursore dell'ADODC come nel caso della nostra form di
visualizzazione degli utenti iscritti nell'anagrafica della BiblioVBIUG.
GESTIRE GLI EVENTI NEI COMPONENTI
Cosa sono gli eventi ?
I componenti che realizziamo con Microsoft® Visual Basic® ci permettono di esporre dei metodi
che le applicazioni client COM utilizzano per demandare ai nostri componenti lo svolgimento di
alcuni compiti.
Le chiamate a questi metodi sono però chiamate sincrone (vedremo la prossima volta che
possiamo fare anche altrimenti) e quindi dal momento in cui chiamiamo il metodo a quando
l'elaborazione dello stesso si conclude il nostro client non può fare altro che aspettare.
Questo oltre a non essere molto elegante non è nemmeno molto comodo.
Se pensiamo alla normale programmazione guidata dagli eventi (Click su un CommandButton),
gli oggetti nelle nostre Form possono informarci di cio' che sta accadendo.
Queste informazioni, che possono essere pensate come delle notifiche, non sono altro che
eventi che gli oggetti da noi utilizzati (in questo esempio il CommandButton) ci inviano quando
necessario.
Anche i componenti che realizziamo autonomamente possono avere questo comportamento.
Per farlo dobbiamo inserire nell'implementazione del nostro componente le informazioni
necessarie a far sì che questo possa esporre degli eventi e possa farli scattare.
Come si definiscono
Per definire un evento in una classe dobbiamo utilizzare la parola chiave Event e precisamente
dobbiamo esporre un evento pubblico che sia caratterizzato da un nome e da eventuali
parametri, come segue:
Public Event Notifica(ByVal sMessaggio As String)
Quello appena definito è un evento di nome Notifica che passerà al chiamante (il client COM)
un parametro di tipo stringa per valore. Se vogliamo notificare ad un client COM delle
informazioni senza la necessità di ricevere dallo stesso delle "risposte" possiamo appoggiarci a
costrutti di questo tipo, dove i parametri passati insieme all'evento sono forniti al client ByVal.
Se invece vogliamo permettere al client COM di fornirci delle informazioni in risposta all'evento
- per esempio vogliamo permettere al chiamante di interrompere un'elaborazione
eccessivamente lunga nel tempo - allora possiamo utilizzare parametri ByRef tramite una
definizione come quella in figura.
A questo punto quando sul client COM scatterà il nostro evento (da noi opportunamente
generato) potremo valutare se il client vuole fermare o meno l'elaborazione controllando il
valore del parametro passatogli per riferimento. In ogni caso per definire un evento, avendolo
quindi a disposizione nell'interfaccia della sua classe, è sufficiente definirlo con la dichiarazione
Public Event.
Ok così è definito! Ma come faccio a far scattare un evento ?
All'interno del codice della nostra classe sarà sufficiente ricorrere all'istruzione RaiseEvent per
far scattare un evento. Per esempio nel nostro caso possiamo pensare di inserire nella
procedura di elaborazione la seguente riga di codice:
RaiseEvent Notifica("Sto lavorando")
Questo comporterà dal lato del client lo scattare dell'evento Notifica qualora la variabile
oggetto che conterrà l'istanza delle nostra classe sia stata definita ad eventi, come segue:
Private WithEvents objMiaClasse As clsMiaClasse
Nella figura seguente è illustrato il caso in esame.
Nel caso degli eventi che passano parametri per riferimento, dal codice del client basterà
cambiare tali valori per far sì che il componente COM possa rendersene conto e possa agire di
conseguenza.
Per esempio per bFerma = True potremmmo decidere di eseguire l'istruzione Exit Do per
terminare un ciclo di elaborazione.
SVILUPPO DI COMPONENTI COM ASINCRONI
Il concetto di asincronicità
Per componente asincrono si intende un componente che sia in grado di lavorare mentre anche
il chiamante (client COM) può svolgere delle altre attività.
Pensiamo a Microsoft Word ed al correttore ortografico automatico. Mentre noi digitiamo i
nostri testi il correttore ortografico controlla la correttezza delle informazioni da noi digitate,
pero' questo non comporta per ogni parola l'interruzione della nostra attività di battitura testo.
Oppure pensiamo al controllo WebBrowser che è in grado di scaricare una pagina web - mentre
noi da codice facciamo altro - e ci avvisa con un evento della conclusione dello scaricamento
delle pagina web richiesta.
L'idea alla base dei componenti asincroni
In Microsoft® Visual Basic® non esiste alcun attributo da impostare per far sì che un
componente sia asincrono.
Per ottenere questo risultato dobbiamo lavorare via codice ed appoggiarci a qualche strumento
fornito internamente al VB.
L'idea alla base dei metodi asincroni nei componenti è quella di far tornare il più velocemente
possibile il controllo al client COM e poi eseguire il codice della procedura autonomamente,
notificando la conclusione dei lavori al client con un normale evento VB.
Per ottenere questo risultato dobbiamo appoggiarci ai timer in modo tale che possiamo dire al
sistema: appena viene chiamato il metodo attiva un timer e restituisci il controllo al
chiamante; poi allo scattare del timer verrà eseguito il vero lavoro del metodo, il quale alla sua
conclusione scatenerà un evento di notifica. In VB, vedremo meglio poi, conviene appoggiarsi a
finestre di codice che contengono l'oggetto timer.
Un metodo asincrono in pratica
Se vogliamo concretizzare queste idee con del codice possiamo pensare ad una classe simile
alla seguente:
Private frmTimer As FormTimer
Public Event NotificaEsecuzione(ByVal sStatus As String)
Public Sub EseguiAsync([Parametri])
Set frmTimer = New FormTimer
frmTimer.tmrAsync.Enabled = True
frmTimer.tmrAsync.Interval = 100
End Sub
In questa procedura si fa riferimento ad una classe FormTimer che dovrà corrispondere ad una
form definita nel nostro progetto e che conterrà un controllo timer di nome tmrAsync. Il codice
della form sarà simile al seguente:
Private Sub tmrAsync_Timer()
tmrAsync.Enabled = False
EseguiLavoroVero([Parametri])
End Sub
La procedura EseguiLavoroVero potrà essere collocata in un modulo di codice .BAS oppure se
vogliamo che scateni degli eventi dovrà essere nella classe che ha attivato il timer.
In questo secondo caso dovremo passare alla form un riferimento alla classe che l'ha chiamata
e lavorare con una procedura di CallBack.
Nel secondo caso la procedura - definita nella classe - avrà un aspetto simile al seguente:
Public Sub EseguiLavoroVero([Parametri])
Set frmTimer = Nothing
[... codice da eseguire ...]
RaiseEvent NotificaEsecuzione("Ho finito !")
End Sub
La form dovrà presentare una proprietà assegnabile per impostare un riferimento alla classe
chiamante e quindi dovrà poi richiamare la procedura che svolge il lavoro non per nome ma
come metodo della classe chiamante, nella forma
RiferimentoAllaClasse.EseguiLavoroVero([Parametri]).
Considerazioni sui Timer
Ritengo importante notare che nel caso precedentemente esposto dobbiamo appoggiarci al
controllo Timer del VB. Utilizzando le API di Windows si posso sfruttare i metodi SetTimer e
KillTimer. La soluzione delle API di sistema ci permetterebbe di evitare di avere delle form
all'interno del nostro componente. Tuttavia la funzione SetTimer richiede l'indirizzo di una
funzione di callback che deve risiedere in un modulo .BAS . Questo comporta qualche problema
nel caso in cui i nostri oggetti siano all'interno di un componente COM che utilizza un Poll di
Thread perché potremmo trovarci a condividere variabili a livello di modulo senza volerlo.
Quindi, benché sembri più elegante l'utilizzo dei timer tramite API di sistema, conviene
appoggiarsi ai controlli timer delle form.
ACCESSO AI DATI DA CODICE TRAMITE ACTIVEX DATA OBJECTS
Universal Data Access
ActiveX Data Objects (da qui in poi ADO) sarà lo strumento che useremo in Microsoft® Visual
Basic® 6.0 per accedere le basi di dati.
Alla base di questo strumento c'è il concetto che qualsiasi insieme di informazioni (relazionali o
meno) può e deve essere acceduto nello stesso identico modo.
Questa idea ha dato vita a quello che si chiama Universal Data Access
(http://www.microsoft.com/data/default.htm) e che si basa appunto sull'idea che sia possibile
avere un unico strumento per accedere qualsiasi tipo di informazione. Per ottenere questo
risultato sono stati create dei livelli software che ci separano dall'accesso ai dati diretto e che
sono rappresentati nella Figura seguente.
In sostanza vi sono tre livelli software che sono:



Data Providers: a questo livello si trovano gli insiemi di informazioni, relazionali o
meno (SQL Server, Oracle, Exchange, Active Directory, ecc.).
Service Components: a questo livello invece troviamo gli strumenti software che
virtualizzano l'accesso ai dati preoccupandosi di creare dei cursori per conto nostro sulle
basi di dati che vogliamo interrogare. Si basano su OLEDB e forniscono funzionalità di
ricerca e raggruppamento di dati.
Data Consumers: a questo ultimo livello ci siamo noi con le nostre applicazioni che
utilizzano ADO per comunicare con i Service Components, per arrivare quindi ai Data
Providers parlando un'unica lingua.
In questa lezione ci occuperemo delle regole di utilizzo di ADO per colloquiare correttamente
con i Service Components e quindi avere accesso ai dati, tra loro anche diversi, parlando
un'unica lingua.
Le regole che vedremo saranno applicabili a data base Access, SQL Server, Oracle, ecc. con la
sola differenza che dovremo, in ciascuno dei casi, comunicare ad ADO quale sia il Data
Provider con il quale vogliamo parlare.
Modello ad Oggetti ADO
ADO nella sua implementazione più semplice, escluse le classi più recenti (dalla versione 2.5 in
poi), si basa su tre classi fondamentali:


ADODB.Connection: gli oggetti di tipo Connection sono quelli che ci permettono di
accedere ad un Data Provider piuttosto che ad un altro. Sono gli oggetti Connection che
devono sapere il nome (OLEDB Provider) del Data Provider che vogliamo utilizzare.
ADODB.Recordset: gli oggetti di tipo Recordset sono invece insiemi di righe, tabelle
quindi, che ci forniscono la strada di accesso ai singoli record negli insiemi di dati che

stiamo accedendo.
ADODB.Command: gli oggetti di tipo Command infine sono degli strumenti molto
comodi per svolgere delle interrogazioni, eseguire delle stringhe di comando SQL e delle
chiamate a stored procedure e query definite all'interno dei nostri insiemi di dati.
L'aspetto interessante del modello ad oggetti di ADO è che ciascuna classe può vivere
indipendentemente dalle altre. Per chi tra voi ha già utilizzati altri modelli ad oggetti per
l'accesso ai dati questo risulterà evidente nel momento in cui andremo ad utilizzare questo
strumento concretamente. In Data Access Object (DAO) o in Remote Data Objects (RDO)
eravamo costretti ad istanziare ed utilizzare in un ben preciso ordine gli oggetti a nostra
disposizione. Con ADO potremo creare oggetti di tipo Recordset senza aver creato
precedentemente degli oggetti di tipo Connection verso la basi di dati che vorremo utilizzare.
Vediamo quindi come utilizzare questo strumento.
ADODB.Connection
Si tratta della classe che ci permette di aprire delle connessioni verso le basi di dati che
vogliamo utilizzare.
Tra le sue proprietà principali troviamo:


ConnectionString: identifica la stringa di connessione verso l'insieme di dati che si
vuole accedere. Può essere costruita utilizzando dei files UDL (Microsoft Data Link)
oppure fornendone esplicitamente il valore come stringa.
Provider: corrisponde al nome dell'OLEDB Provider che si vuole utilizzare per accedere
all'insieme di dati. Alcuni esempi sono: Microsoft.Jet.OLEDB.4.0 - SQLOLEDB.1 MSDAORA.1 rispettivamente per Access 2000, SQL Server, Oracle. Ve ne sono molti
altri.
I metodi significativi invece sono:






Open: apre una connessione precedentemente fornita nella proprietà ConnectionString
oppure apre una ConnectionString fornita come argomento al metodo stesso (si veda
l'esempio più avanti nella lezione). Durante la chiamata al metodo Open è possibile
fornire oltre alla stringa di connessione le credenziali per l'autenticazione dell'utente
(userid e password).
Close: questo metodo conclude una connessione precedentemente aperta verso una
base dati.
Execute: esegue un blocco di istruzioni SQL. Tramite questo metodo è possibile avere
in risposta un insieme di record (un Recordset quindi) da utilizzare per scorrere il
risultato della interrogazione/istruzione SQL.
BeginTrans: avvia una transazione sulla connessione correntemente attiva.
CommitTrans: chiude e conferma le attività svolte durante una transazione.
RollbackTrans: chiude e annulla le attività svolte durante una transazione.
Ecco un esempio di codice Microsoft® Visual Basic® 6.0 che utilizza l'oggetto Connection per
aprire una connessione verso un data base Access ed esegue un aggiornamento sulla tabella
degli Utenti:
'Dimensiono ed istanzio le variabili di accesso ai dati
Dim cnAccess As ADODB.Connection
Set cnAccess = New ADODB.Connection
'Apro la connessione verso Access (attenzione alle 4 virgolette sulla
'password che corrispondono a 2 virgolette nella stringa)
cnAccess.Open "Provider=Microsoft.Jet.OLEDB.4.0;Password="""";" & _
"Data Source=Database.mdb;Persist Security Info=True"
'Aggiorno con un'istruzione SQL dei record nella tabella Utenti
cnAccess.Execute "UPDATE Utenti SET Attivo = -1 WHERE Attivo = 0"
'Chiudo la connessione
cnAccess.Close
'Scarico dalla memoria gli oggetti
Set cnAccess = Nothing
Oppure per accedere un data base SQL Server possiamo utilizzare il seguente codice:
Dim cnSQLServer As ADODB.Connection
Set cnSQLServer = New ADODB.Connection
'Qui vi è l'unica DIFFERENZA con il codice precedente:
'la stringa di connessione !
cnSQLServer.Open "Provider=SQLOLEDB.1;Password="""";" & _
"Persist Security Info=True;User ID=sa;Initial Catalog=Utenti;" & _
"Data Source=(local)"
cnSQLServer.Execute "UPDATE Utenti SET Attivo = -1 WHERE Attivo = 0"
cnSQLServer.Close
Set cnAccess = Nothing
Già tramite questi due esempi è possibile notare che, a parte la stringa di connessione, il
nostro comportamento nei confronti di Access o di SQL Server è rimasto analogo.
Questa considerazione, con basi di dati dotate di strutture normali, è così vera che potremo
spostare i nostri insiemi di informazioni tra motori diversi preoccupandoci solo di aggiornare le
stringhe di connessione OLEDB da utilizzare, senza dover rivedere ogni volta il nostro codice
sorgente quindi, ma agendo solo su un parametro (o su di un file UDL) che contiene la stringa
di connessione da noi scelta.
ADODB.Recordset
Gli oggetti di tipo Recordset sono insiemi di record che ci forniscono il vero e proprio accesso
alle informazioni nel data base. Tramite gli oggetti Recordset possiamo accedere i singoli
record di una tabella di dati, sfogliandoli e modificandoli, piuttosto che aggiungendone di
nuovi. Vedremo nel corso della lezione e del tutorial in generale che non si deve assumere per
questo motivo che l'oggetto Recordset sia sempre lo strumento più corretto da utilizzare per
accedere i dati in lettura/scrittura. In particolare grazie alle ultime versioni dei motori di data
base e di ADO conviene infatti utilizzare altri strumenti per l'accesso in scrittura sui data base,
limitando l'uso degli oggetti di tipo Recordset alla visualizzazione ed allo scambio di dati. Le
proprietà fondamentali degli oggetti di tipo Recordset sono:

CursorLocation: indica al Recordset dove deve risiedere il cursore, cioè dove devono
stare i record mentre vengono sfogliati. I valori possibili sono adUseClient (stanno nella
memoria del client) o adUseServer (stanno sul server). Un recordset lato client impiega
più tempo ad arrivare sul client (perchè deve essere trasferito per intero dal server al
client) ma quando è stato trasferito completamente allegerisce il server in quanto non











richiede più ulteriori attività sul server stesso. Eventualmente sarà necessario fare degli
aggiornamenti asincroni (UpdateBatch) sul server una volta che si sia finito di utilizzare
i dati sul client.
LockType: indica il tipo di lock cioè di bloccaggio sui record quando si accedono i dati
in lettura/scrittura. Le configurazioni possibili sono adLockReadOnly (sola lettura),
adLockPessimistic (il record o la pagina di record viene bloccata non appena si accede
un qualsiasi campo in modifica), adLockOptimistic (il record o la pagina di record
vengono bloccati solo al momento del salvataggio delle modifiche, potrebbero esservi
dei conflitti se più utenti hanno iniziato a modificare i dati), adLockBatchOptimistic (si
usa nel caso di cursori disconnessi lato client ... ne parleremo più avanti nel tutorial).
CursorType: permette di decidere che tipo di notifiche vogliamo avere dall'esterno
sulle modifiche apportate ai nostri dati così come ci permette di stabilire in quali
direzioni vogliamo sfogliare i dati (si veda la tabella seguente per maggiori dettagli). I
valori possibili sono:
-adOpenForwardOnly: permette di scorrere i dati solo in avanti un record alla volta, dal
primo all'ultimo e non vede le modifiche apportate dall'esterno ai record che scorre.
-adOpenKeyset: permette di scorrere i dati in avanti ed indietro e vede le modifiche
apportate dall'esterno ai soli record che scorre (non si accorge se ne vengono aggiunti o
modificati altri).
-adOpenDynamic: permette di scorrere avanti ed indietro i record e si accorge di
qualsiasi tipo di modifica sui record.
-adOpenStatic: si tratta di una copia dei dati presenti sul server che si può scorrere in
qualsiasi direzione ma che non si accorgerà mai di modifiche apportate sul server ai dati
che contiene.
Direzione
Modifiche Esterne
adOpenForwardOnly
Solo Avanti
Non le vede
adOpenKeyset
Avanti/Indietro
Solo sui propri record
adOpenDynamic
Avanti/Indietro
Su tutti i record
adOpenStatic
Avanti/Indietro
Non le vede
AbsolutePosition: indica la posizione corrente, cioè il numero del record corrente.
RecordCount: indica il numero complessivo di record (vale solo in alcuni casi).
ActiveConnection: identifica un riferimento all'oggetto Connection utilizzato dal
Recordset per ottenere i dati.
Sort: permette di ordinare i dati contenuti nel Recordset.
Filter: permette di filtrare i dati contenuti nel Recordset.
BOF: ci informa del fatto che siamo arrivati all'inizio del Recordset e non ci sono più
record da scorrere qualora dovessimo ancora andare indietro nel Recordset (vale
True/False).
EOF: ci informa del fatto che siamo arrivati alla fine del Recordset e non ci sono più
record da scorrere qualora dovessimo ancora andare avanti nel Recordset (vale
True/False).
Fields: si tratta di una proprietà di tipo collezione che fornisce accesso ai singoli campi
del record corrente. E' la proprietà di default di un Recordset. Per accedere il campo
[Nome] del record corrente di un Recordset di nome rsData si puo' quindi scrivere:
rsData.Fields("Nome").Value
oppure in modo equivalente si può scrivere:
rsData("Nome")
I metodi significativi invece sono:









Open: vuole un massimo di 5 argomenti che sono la sorgente da aprire (una stringa
SQL, un oggetto Command, una tabella, ecc.), la connessione da utilizzare (può essere
un oggetto Connection o una ConnectionString scritta esplicitamente, oppure nulla), il
tipo di cursore (CursorType) ed il tipo di lock (LockType) ed infine delle opzioni. Sono
tutti argomenti opzionali che dobbiamo fornire o meno a seconda di come stiamo
utilizzando l'oggetto Recordset.
Close: chiude un Recordset precedentemente aperto.
AddNew: aggiunge un nuovo record al Recordset, qualora la modalità di accesso lo
permetta.
Delete: cancella un record dal Recordset, qualora la modalità di accesso lo permetta.
Update: aggiorna un record modificato, qualora la modalità di accesso lo permetta. Si
verifica in automatico quando si modifica un record e poi ci si sposta su di un altro.
MoveFirst: si sposta in testa al Recordset (appena dopo BOF).
MoveLast: si sposta in fondo al Recordset (appena prima di EOF).
MoveNext: si sposta avanti di un record nel Recordset.
MovePrevious: si sposta indietro di un record nel Recordset.
Ecco un esempio di codice che apre un Recordset ed aggiorna tutti i record al suo interno,
quindi aggiunge un nuovo record e cancella il primo record.
'Dimensiono ed istanzio le variabili oggetto di accesso ai dati
Dim cnSQLServer As ADODB.Connection
Dim rsData As ADODB.Recordset
Set cnSQLServer = New ADODB.Connection
Set rsData = New ADODB.Recordset
'Apro la connessione verso il motore di data base
cnSQLServer.Open "Provider=SQLOLEDB.1;Password="""";" & _
"Persist Security Info=True;User ID=sa;Initial Catalog=Utenti;" & _
"Data Source=(local)"
'Richiedo al server la lista di tutti gli utenti
Set rsData = cnSQLServer.Execute("SELECT * FROM Utenti")
'Scorro con un ciclo tutti gli utenti
'finchè non arrivo ad EOF = True, cioè alla fine
Do While Not rsData.EOF
'ed imposto il campo Attivo a -1
rsData("Attivo") = -1
rsData.MoveNext
Loop
'Aggiungo un nuovo record e lo valorizzo
rsData.AddNew
rsData("Nome") = "Paolo"
rsData("Attivo") = -1
rsData.Update
'Mi sposto in testa alla tabella e cancello il primo record
rsData.MoveFirst
rsData.Delete adAffectCurrent
'Chiudo il Recordset e la Connection
rsData.Close
cnSQLServer.Close
'Scarico completamente dalla memoria gli
'oggetti Recordset e Connection
Set rsData = Nothing
Set cnAccess = Nothing
ADODB.Command
Gli oggetti di tipo Command permettono di richiamare delle stored procedure, piuttosto che di
eseguire delle istruzioni o dei comandi SQL, eventualmente che restituiscono un insieme di
righe (Recordset) che saranno eseguiti dal server di dati. Le proprietà fondamentali sono:






ActiveConnection: indica un riferimento all'oggetto Connection tramite il quale si
vuole eseguire il comando. Può essere un oggetto di tipo Connection oppure una
Connection String scritta esplicitamente.
CommandText: stringa SQL contenente le istruzioni da eseguire o il nome della stored
procedure che si vuole mandare in esecuzione.
CommandType: comunica al server il tipo di istruzione SQL che si sta richiedendo di
eseguite (adCmdStoredProc=stored procedure; adCmdText=stringa SQL; ecc.).
CommandTimeout: indica un tempo massimo di attesa per l'esecuzione della query.
Prepared: informa il motore di data base, qualora sia in grado di recepire
l'informazione, che il piano di esecuzione della stringa SQL deve essere mantenuto in
memoria per successive esecuzioni.
Parameters: identifica la collezione dei parametri di una stored procedure o di una
stringa SQL parametrica.
I metodi interessanti sono:


Execute: esegue il codice SQL richiesto ed eventualmente restituisce un Recordset
come valore di ritorno.
CreateParameter: crea un oggetto di tipo Parametro che è possibile aggiungere alla
collezione dei parametri Parameters.Append [...] .
Ecco un esempio di codice SQL che apre una connessione verso SQL server ed esegue una
stringa SQL tramite un Command.
'Dimensiono ed istanzio le variabili oggetto di accesso ai dati
Dim cnSQLServer As ADODB.Connection
Dim cmdData As ADODB.Command
Dim rsData As ADODB.Recordset
Set cnSQLServer = New ADODB.Connection
Set cmdData = New ADODB.Command
Set rsData = New ADODB.Recordset
'Apro la connessione verso il motore di data base
cnSQLServer.Open "Provider=SQLOLEDB.1;Password="""";" & _
"Persist Security Info=True;User ID=sa;Initial Catalog=Utenti;" & _
"Data Source=(local)"
'Configuro il Command e richiedo al
'server la lista di tutti gli utenti
With cmdData
Set .ActiveConnection = cnSQLServer
.CommandText = "SELECT * FROM Utenti"
.CommandType = adCmdText
.Prepared = True
Set rsData = .Execute
End With
'*****************************************
'Qui potrei scorrere i dati ... come prima
'*****************************************
'Chiudo il Recordset e la Connection
rsData.Close
cnSQLServer.Close
'Scarico completamente dalla memoria gli
'oggetti Recordset, Command e Connection
Set rsData = Nothing
Set cmdData = Nothing
Set cnAccess = Nothing
Regole di sopravvivenza
Quando si lavora con ADO e si accedono basi di dati conviene tenere presenti alcune regole:





E' possibili utilizzare il pool di connessioni fornito da OLEDB ed è quindi inutile
mantenere connessioni aperte durante tutta l'esecuzione del programma. Conviene
aprire e chiudere le connessioni (mordi e fuggi) man mano servono.
I parametri di una stored procedure possono essere forniti alla stessa tramite il metodo
Refresh della collezione Parameters di un oggetto Command, ma è molto più efficiente
creare a mano (CreateParameter) i parametri e poi aggiungerli (Parameters.Append)
alla collezione dei parametri.
I Recordset con cursori adOpenDynamic sono comodi ma sono molto dispendiosi.
I Recordset non dovrebbero essere utilizzati per fare aggiornamenti massicci sui dati.
Conviene invece creare delle stored procedure che saranno decisamente migliori in
termini di rapidità ed efficienza di esecuzione.
I Recordset dovrebbero essere utilizzati per scorrere i dati e passarli tra diversi livelli
software (magari come recordset disconnessi XML ... ne parleremo ...) e non per
aggiornamenti massivi sui dati.
Per maggiori informazioni vedere:
http://www.visualbasic.it