Sei sulla pagina 1di 20

Capitolo 14

Introduzione
Sviluppare
ai moduli di classe

Proprietà, metodi
312
moduli di classe
ed eventi 315

Creare una classe 317

Struttura
delle classi 324

Questo capitolo introduce il concetto delle classi. In questo


capitolo imparerai cosa sono le classi e gli oggetti, e il motivo
per cui i due termini non vanno confusi. Imparerai inoltre come
creare le classi in Microsoft Visual Basic for Applications (VBA)
e come definirne le proprietà, i metodi e gli eventi.

Che cos’è un oggetto?


Un oggetto è la rappresentazione logica di una cosa. La cosa può
essere un’entità fisica, come una persona, un fiore, una macchi-
na o un luogo, oppure può essere un’entità logica, come un
rapporto, un ordine o una transazione. La cosa può anche rap-
presentare un entità del computer, come un pulsante, una cel-
la, un foglio di lavoro o un modulo.

Che cos’è una classe?


Una classe è un modello dal quale si crea un oggetto. Questo
modello comprende sia variabili che codice, condensati in una
singola entità. Un oggetto rappresenta una singola istanza di una
classe, che può essere modificata dal tuo programma.
Sei un po’ confuso? Pensa alla classe come a un tipo di dati, come
Integer o String. Prima di poter usare un Integer o String, devi
dichiarare una variabile di quel tipo. Così come è possibile ave-
re diverse variabili definite come Integer o String, è anche possi-
bile avere diverse variabili definite come istanze di un’unica classe.
In Visual Basic for Applications, le classi sono implementate
attraverso i moduli di classe. Ciascun modulo di classe contie-
ne esattamente una classe e comprende tutte le proprietà i
metodi e gli eventi associati con l’interfaccia della classe, oltre
a tutte le altre variabili locali, funzioni e subroutine necessarie
a far funzionare correttamente la classe.

311
Parte 4: VBA avanzato

Che cosa sono le proprietà?


proprietà?
Le proprietà sono attributi della cosa che un oggetto rappresenta. Per esempio, un fiore avrà attri-
buti come il nome, il colore, le dimensioni, e così via. Gli attributi di una persona saranno per esempio
il nome, l’indirizzo, il numero del documento d’identità e la data di nascita.
Un oggetto può anche contenere riferimenti ad altri oggetti. Un ordine potrebbe avere un riferimento al
cliente, o un modulo potrebbe contenere un pulsante. Ai fini di questa trattazione, questi riferimenti ad
oggetti possono anche caratterizzati come proprietà. Un oggetto può anche rappresentare un gruppo di
cose simili. Per esempio, l’oggetto Impiegati potrebbe contenere un gruppo di singoli oggetti Impiegato.
Capitolo 14

suggerimento Gli aggettivi descrivono i nomi

È possibile pensare agli oggetti come nomi e alle proprietà come aggettivi, per esempio il fiore rosso
o la persona alta due metri. Questo concetto non è perfetto, perché alcuni attributi sono piuttosto
specifici, ad esempio un camion con 60.500 km, ma quest’idea può essere utile nei primi tempi del
tuo lavoro con gli oggetti.

Che cosa sono i metodi?


I metodi sono azioni compiute dall’oggetto. Per esempio, l’oggetto di un rapporto può comprende-
re un metodo di stampa che invia il rapporto a una stampante. Un altro modo di immaginare i metodi
è pensare che i metodi descrivono le operazioni compiute con le informazioni contenute nelle pro-
prietà dell’oggetto.

suggerimento I verbi descrivono le azioni

Puoi caratterizzare i metodi come verbi che compiono un’operazione o un’attività con le proprietà
dell’oggetto.

Che cosa sono gli eventi?


Pur non essendo esattamente una parte del modello di programmazione degli oggetti, gli eventi sono
un utile strumento che permette a un oggetto di scambiare informazioni con il programma che ha
creato l’oggetto. In altri termini, un evento è una subroutine residente nel programma che ha crea-
to l’oggetto, ed è chiamata dall’oggetto.
Un evento è una tecnica utile che elimina la necessità del programma di monitorare costantemente
le modifiche di un oggetto. In questo modo, l’oggetto chiama l’evento per informare il programma
di una modifica allo stato dell’oggetto.

Introduzione ai moduli di classe


I moduli di classe sono tra gli strumenti più importanti per il programmatore in VBA. Un modulo
di classe ti permette di creare degli oggetti e di modificarli, come se fossero oggetti già forniti con

312
Capitolo 14: Sviluppare moduli di classe

Microsoft Excel. E proprio come gli oggetti disponibili in Excel, un modulo di classe può avere pro-
prietà, metodi ed eventi.

Accedere agli oggetti


Accedere
C’è una grande differenza tra una variabile semplice e una variabile oggetto. La variabile oggetto non
è che un puntatore all’interno della memoria. Dovrai creare esplicitamente un oggetto e salvare la
sua posizione nella variabile oggetto. Questo processo si chiama creare una nuova istanza di un og-
getto o istanziare un oggetto.

Capitolo 14
Poiché gli oggetti sono diversi dalle variabili, Visual Basic for Applications utilizza una speciale istru-
zione chiamata istruzione Set.
L’istruzione Set ha due forme. Ecco la prima:

Set VariabileOggetto = New NomeClasse

In questa forma, l’istruzione Set crea un nuovo oggetto basato su NomeClasse. Ciò significa che Visual
Basic allocherà memoria per l’oggetto e salverà la posizione in memoria nella classe VariabileOggetto.

Set VariabileOggetto = EspressioneOggetto

Nella seconda forma, l’istruzione Set fa due cose: prima di tutto l’istruzione rilascia l’oggetto a cui
puntava, quindi salva un puntatore a un oggetto già esistente in VariabileOggetto.

Quando vengono davvero creati gli oggetti?


La parola chiave New in un’istruzione Dim, Public o Private non crea una nuova istanza di un og-
getto. Invece, Visual Basic aggiunge del codice davanti a ogni riferimento all’oggetto per vedere
se è stata creata una nuova istanza della classe. Se non è stata creata una nuova istanza della clas-
se, l’oggetto sarà creato automaticamente prima di essere utilizzato.

Nella maggior parte dei casi non c’è una grossa differenza nell’usare un’istruzione Dim o un’istru-
zione Set per creare una nuova istanza della classe. Tuttavia, usare l’istruzione Set New è legger-
mente più efficiente che usare l’istruzione Dim New, perché Visual Basic non genera il codice
supplementare per verificare che sia stata creata una nuova istanza della classe.

Usare un’istruzione Set New anziché Dim New permette anche di evitare alcuni problemi di debug.
Supponi di trovarti in una situazione in cui credi di aver creato una nuova istanza di una classe, ma
per qualche motivo non è stato creato l’oggetto. Usando Dim New, l’oggetto sarà creato automa-
ticamente e il tuo programma potrebbe cercare di utilizzare l’oggetto aspettandosi che questo
contenga delle informazioni, ma non è così perché l’oggetto è stato appena creato.

Creare l’oggetto con Set New implica che l’oggetto non può essere creato al momento, e nel tuo
programma si verificherebbe un errore di run-time se cercasse di accedere a un oggetto che non è
ancora stato creato. L’errore di run-time, pur essendo fastidioso, ti indicherebbe che in qualche punto
del tuo codice c’è un problema. Altrimenti, potresti non accorgerti neppure della presenza di un bug.

313
Parte 4: VBA avanzato

Dichiarare gli oggetti


Dichiarare
Puoi dichiarare un oggetto usando un’istruzione Dim, Public o Private, in due forme diverse. Ecco
la prima:

Dim VariabileOggetto As NomeClasse

Questa istruzione riserva semplicemente lo spazio per VariabileOggetto, e la variabile ora ha un tipo
di NomeClasse

Dim VariabileOggetto As New NomeClasse


Capitolo 14

Questa seconda forma fa le stesse cose della prima, ma creerà automaticamente un nuovo oggetto
la prima volta che VariabileOggetto sarà referenziata.

Oggetti e Nothing
Visual Basic for Applications contiene un valore speciale chiamato Nothing. Questo valore può es-
sere usato solo con gli oggetti. Nothing è il valore associato con una variabile oggetto che non punta
al momento a un’istanza di una classe. Una variabile oggetto dichiarata con un’istruzione Dim sarà
inizialmente impostata a Nothing.
È possibile determinare se è stata creata una nuova istanza di classe usando Is Nothing in un’istru-
zione If come questa:

If VariabileOggetto Is Nothing Then

attenzione
L’espressione VariabileOggetto Is Not Nothing, pur avendo senso in lingua inglese, non viene ca-
pita da Visual Basic for Applications. Se devi verificare che una variabile oggetto si riferisce a un’istan-
za di un oggetto, dovresti usare l’espressione Not VariabileOggetto Is Nothing. La verifica Is Nothing
dà come risultato un valore booleano e può essere usata ovunque si possa utilizzare un’espressio-
ne booleana.

La seguente istruzione può essere usata per distruggere un oggetto:

Set VariabileOggetto = Nothing

Quest’istruzione libererà il riferimento all’oggetto e imposterà la variabile oggetto al suo stato non
inizializzato. Assumendo che ci sia solo una variabile oggetto che punta all’oggetto, questa istruzione
distruggerà anche l’oggetto e libererà tutte le risorse associate a esso.
Tuttavia, se diverse variabili oggetto puntano a questo oggetto, occorre impostarle tutte a Nothing
prima che l’oggetto venga distrutto. Per esempio, nel seguente frammento di codice, l’oggetto cre-
ato dalla classe MiaClasse continua a esistere, anche se VariabileOggetto1 viene impostata a Nothing.

314
Capitolo 14: Sviluppare moduli di classe

Set VariabileOggetto1 = New MiaClasse


Set VariabileOggetto2 = VariabileOggetto1
Set VariabileOggetto1 = Nothing

Oggetti con più variabili oggetto


È importante ricordare che un oggetto non è la stessa cosa di una variabile oggetto. Per esempio, il
seguente codice crea un oggetto con due variabili che puntano a esso:

Set OggettoA = New MiaClasse

Capitolo 14
Set OggettoB = OggettoA

La prima istruzione Set crea una nuova istanza di MiaClasse, mentre la seconda istruzione Set crea
semplicemente un secondo puntatore allo stesso oggetto creato dalla prima istruzione.
Ciò significa che le seguenti dichiarazioni faranno lo stesso, dal momento che sia OggettoA che
OggettoB puntano allo stesso oggetto:

OggettoA.Nome = "Rose"
OggettoB.Nome = "Rose"

Se questo non ti confonde troppo, eseguire la seguente istruzione non distruggerà l’oggetto:

Set OggettoA = Nothing

Poiché OggettoB punta ancora all’oggetto, questo rimarrà in memoria finché anche OggettoB sarà
impostato a Nothing.

Proprietà, metodi ed eventi


Esiste una serie di proprietà, metodi ed eventi associati a ogni oggetto, che servono per scambiare
informazioni tra l’oggetto e la routine che ha creato l’oggetto.

Proprietà, metodi ed eventi Public e Private


Proprietà,
Le singole parti di una classe possono essere etichettate come Public o Private. Tutto ciò che è con-
trassegnato come Public è visibile a chiunque usi le classi, mentre ciò che è marcato come Private è
accessibile solo dal codice all’interno della classe.

suggerimento Non affidar


affidar ti alle impostazioni pr
fidarti edefinite
predefinite

Contrassegna sempre esplicitamente tutto ciò che è contenuto in una classe come Public o Priva-
te, in modo da non doverti preoccupare se l’impostazione predefinita fosse Public o Private.

315
Parte 4: VBA avanzato

Proprietà
Proprietà
All’interno di una classe troverai molte cose diverse. Puoi definire delle variabili a livello di classe,
che sono accessibili da qualsiasi punto della classe. Se una variabile a livello di classe è contrassegnata
come Public, diventa disponibile a chiunque usi la classe, ed è quindi una proprietà della classe.
Oltre alle variabili a livello di classe, le proprietà potrebbero anche avere del codice a loro associato.
Ogni proprietà in cui vuoi usare del codice è organizzata in due routine, che restituiscono il valore
al programma chiamante o modificano il valore nella classe. La routine Get restituisce il valore al
chiamante, mentre le routine Let o Set permettono al chiamante di assegnare un valore alla proprietà.
Capitolo 14

Ricorda che puoi definire una proprietà soltanto con una routine Get oppure con una routine Let o
Set. Se utilizzi solo una routine Get, la proprietà diventa di sola lettura e il suo valore non può essere
modificato dal programma usando l’oggetto. Similmente, se inserisci solo una routine Let o Set, la
proprietà diventa di sola scrittura, e il suo valore non può essere visto dal programma chiamante.

Metodi
Insieme alle variabili di livello classe e alle routine di proprietà, una classe può anche contenere una
serie di subroutine e funzioni regolari. Se una funzione o una subroutine è contrassegnata come
Public, viene chiamata metodo. I metodi possono essere invocati dal codice che risiede all’interno o
al di fuori della classe.

Eventi
Gli eventi sono subroutine che esistono al di fuori del codice associato con la classe, che possono essere
chiamate da istruzioni all’interno della classe. Gli eventi forniscono alla classe un modo per inter-
rompere il programma che ha creato un’istanza dell’oggetto dalla classe, permettendo quindi al
programma di eseguire le proprie operazioni in risposta a una situazione incontrata dall’oggetto.
Ricorda che il codice associato a un evento in realtà risiede al di fuori della classe. Le uniche infor-
mazioni memorizzate all’interno della classe sono la definizione dell’evento con i parametri che
saranno passati al programma esterno.

nota Le classi che contengono eventi richiedono che nella dichiarazione dell’oggetto ci sia la parola chiave
WithEvents. Se nella dichiarazione non c’è questa parola chiave, gli eventuali eventi che si verifi-
cano saranno ignorati dal programma esterno.

Tutte queste proprietà pubbliche, metodi ed eventi di una classe formano l’interfaccia dell’oggetto.
L’interfaccia isola il codice all’interno della classe dal codice che utilizza l’oggetto creato da questa classe.
Quest’isolamento è molto utile per vari motivi. Innanzitutto, ti permette di verificare le classi indipen-
dentemente dal resto dell’applicazione. Quando ritieni che la classe sia stabile, potrai trattarla come
una scatola nera che funziona. In secondo luogo, facilita il lavoro di più persone su un’unica applica-
zione. Una persona può lavorare alla classe mentre altri lavorano al codice che utilizza la classe. Inol-
tre, è possibile modificare il codice all’interno della classe senza necessariamente avere un impatto sulle
applicazioni che utilizzano la classe. In questo modo si possono implementare nuovi algoritmi o ag-
giungere nuove caratteristiche alla classe senza cambiare i programmi che utilizzano la classe.

316
Capitolo 14: Sviluppare moduli di classe

Creare una classe


Il modulo di classe contiene tutte le proprietà, metodi ed eventi associati con l’interfaccia della classe,
insieme a tutte le variabili locali, le funzioni e le subroutine usate dalla classe.

Crear
Crear e un modulo di classe
eare
Puoi aggiungere un modulo di classe al tuo programma in VBA scegliendo Inserisci, Modulo di classe
dal menu principale di Visual Basic. Il nome iniziale della classe è formato aggiungendo un nume-
ro unico alla parola Classe. Così, la prima classe che creerai sarà Classe1, e la seconda sarà Classe2.

Capitolo 14
Dal momento che un nome come Classe1 non è molto descrittivo, dovresti sempre dare alla classe
un nome più significativo. Per modificare il nome di una classe, seleziona la classe nella finestra
Gestione progetti, quindi vai alla finestra Proprietà e modifica la proprietà Name associata a questa
classe (vedi figura 14-1).

Figura 14-1. Usa la finestra Proprietà per modificare la proprietà Name associata alla classe.

Definire pr
Definire oprietà semplici
proprietà
Ci sono due diversi tipi di proprietà: variabili di livello classe pubbliche e routine di proprietà. Le
variabili di livello classe devono essere definite prima di qualsiasi subroutine, funzione o proprietà.
In termini pratici, ciò significa che tutte le variabili di livello classe dovrebbero trovarsi all’inizio del
modulo di classe.

317
Parte 4: VBA avanzato

Per esempio, la seguente riga definisce una proprietà semplice:

Public CodiceArticolo As Long

attenzione
Le proprietà semplici non possono essere usate per restituire una matrice, una stringa a lunghezza fis-
sa, una costante o una struttura complessa creata con un istruzione Type. Se ti occorre una proprietà
che restituisca una di queste cose, crea la variabile di livello classe privata adeguata e quindi crea una
routine Property che esegua la stessa azione. Per esempio, puoi creare una routine di proprietà che accetti
Capitolo 14

una serie di parametri che permettano alla routine di sembrare una matrice. Similmente, puoi creare una
routine di proprietà che accetti e restituisca stringhe a lunghezza fissa o strutture complesse.

Definire rroutine
Definire outine di proprietà
proprietà
Ci sono tre diversi tipi di routine di proprietà: Get, Set e Let. La routine Property Get restituisce sempre
un valore. Ecco un semplice esempio che si riferisce a una variabile di livello classe privata che è stata
chiamata IlNomeDelProdotto.

Public Property Get NomeProdotto As String

NomeProdotto = IlNomeDelProdotto

End Property

Le routine Property Let e Property Set sono chiamate per salvare un valore nella proprietà. L’istru-
zione Property Let è utilizzata quando la proprietà è una normale variabile, mentre l’istruzione
Property Set è usata quando la proprietà è un oggetto.
La routine Property Let corrispondente alla proprietà NomeProdotto sarebbe simile a questa:

Public Property Let NomeProdotto(valore As String)

IlNomeDelProdotto = valore

End Property

nota L’unica differenza tra un’istruzione Property Set e un’istruzione Property Let è che Property Set si utilizza
quando si lavora con gli oggetti, mentre normalmente si assegnerebbero i valori usando l’istruzione
Set. Similmente, si utilizza Property Let quando si restituisce un qualsiasi altro valore. Le routine di
proprietà possono anche avere uno o più parametri. Di solito si utilizzano parametri con una routine
di proprietà per simulare una matrice. Per esempio, il seguente frammento di codice dichiara una
variabile di livello classe privata chiamata Nomi, che è una matrice di 100 String. Il frammento di codice
comprende anche due routine di proprietà che fanno sembrare la proprietà una matrice.

318
Capitolo 14: Sviluppare moduli di classe

Private Nomi (99) As String

Public Property Get NomeMatrice(indice As Long) As String

NomeMatrice = Nomi(indice)

End Property

Public Property Let NomeMatrice(indice As Long, valore as String)

Capitolo 14
Nomi = valore

End Property

nota Puoi specificare quanti parametri vuoi per le routine di proprietà. Tuttavia, essi devono essere identici
tra le routine Get e Let/Set, eccezion fatta per l’ultimo parametro della routine Let/Set, che con-
tiene il valore della proprietà.

Una persona che utilizza la classe può accedere alla proprietà così:

Oggetto.NomeMatrice (10) = "Elemento 10 nella matrice"

Oppure così:

Variabile = Oggetto.NomeMatrice (10)

suggerimento Routine di pr oprietà e parametri


proprietà

Pur essendo possibile specificare un elenco di parametri per una routine di proprietà, dovresti limi-
tare l’uso dei parametri in una routine di proprietà a quei parametri che rendono la routine di pro-
prietà somigliante a una matrice. Se ti occorre utilizzare parametri piuttosto che subscript, dovresti
prendere in considerazione di creare uno o più metodi con i parametri che ti servono.

319
Parte 4: VBA avanzato

Usare le istruzioni di proprietà


con i tipi definiti dall’utente
Se hai definito un insieme di routine di proprietà per manipolare una struttura complessa creata con
un’istruzione Type, potresti riscontrare dei problemi quando cerchi di assegnare un valore diretta-
mente a uno degli elementi nella struttura in un’unica istruzione. Supponi che la tua classe con-
tenga le seguenti istruzioni:

Public Type CoordinateMappaType


Latitudine As Single
Capitolo 14

Longitudine As Single
End Type

Private MiaCoordinateMappa As CoordinateMappaType

Public Property Get CoordinateMappa As CoordinateMappaType

CoordinateMappa = MiaCoordinateMappa

End Property

Public Property Let CoordinateMappa (valore as CoordinateMappaType)

CoordinateMappa = valore

End Property

Ora, assumendo che tu abbia istanziato la classe come MicrosoftWay, puoi fare riferimento al va-
lore Latitudine in questo modo:

TempLatitudine = MicrosoftWay.CoordinateMappa.Latitudine

Poiché questa funziona, potresti essere tentato di usare le seguenti istruzioni:

MicrosoftWay.Coordinate.Latitudine = 47.63
MicrosoftWay.Coordinate.Longitudine = 122.13

Tuttavia, se le usi, scoprirai che MicrosoftWay.CoordinateMappa.Latitudine è zero!

Sebbene questo possa sembrare un bug di Visual Basic, in realtà non lo è. Visual Basic funziona
correttamente. Quando fai riferimento all’elemento Latitudine nella prima istruzione, Visual Basic
crea una variabile temporanea CoordinateMappaType e imposta il valore Latitudine a 47.63. Poi-
ché la variabile temporanea è riempita con gli zeri quando viene allocata e non c’è un valore asse-
gnato esplicitamente a Longitudine, questo contiene un valore di zero. Così, quando viene chiamata
la routine Let Coordinate, con la variabile temporanea creata da Visual Basic, l’elemento Latitudi-
ne sarà impostato a 47.63 e l’elemento Longitudine sarà impostato a zero.

320
Capitolo 14: Sviluppare moduli di classe

Usar
Usaree le istr uzioni di pr
istruzioni oprietà con i tipi definiti dall’utente (continua)
proprietà

La stessa situazione si verifica quando esegui la seconda istruzione. Poiché non è stato assegnato
un valore a Latitudine nella variabile temporanea, il valore precedente di 47.63 sarà sovrascritto
da zero, e questo annulla la modifica fatta nella prima istruzione.

Ci sono un paio di modi per evitare questo problema. Il primo modo, e probabilmente il migliore,
è creare una classe anziché usare un’istruzione Type. Tuttavia, se desideri proprio usare un’istru-
zione Type, dovresti creare una tua variabile temporanea, assegnare i valori alla struttura e asse-
gnare la struttura alla proprietà in questo modo:

Capitolo 14
Dim TempVar As CoordinateMappaType
TempVar.Latitudine = 47.63
TempVar.Longitudine = 122.13
MicrosoftWay.CoordinateMappa = TempVar

Definire metodi
Definire
I metodi sono semplicemente funzioni e subroutine pubbliche. Essi sono liberi di accettare qualsi-
asi insieme di parametri e restituire qualsiasi tipo di valore. Possono inoltre accedere a qualunque
variabile di livello classe, sia pubblica che privata, e a qualunque routine di proprietà. Per esempio,
supponi che la classe contenga informazioni su un prodotto particolare di The Garden Company.
Potresti creare una funzione che calcoli il prezzo scontato in questo modo:

Public Function PrezzoScontato (Sconto As Currency) As Currency

If Sconto >= 0 and Sconto < 1.0 Then


PrezzoScontato = PrezzoListino * (1 - Sconto)

Else
PrezzoScontato = PrezzoListino

End If

End Function

Questa routine verifica che il parametro di input sia valido controllando che sai un valore compre-
so tra 0 e 1 e calcoli di conseguenza il prezzo scontato. Se il valore scontato non è valido, viene resti-
tuito il prezzo di listino dell’articolo.

suggerimento Rispar miar


Risparmiar
miaree cicli

Potendo scegliere tra usare una routine di proprietà o una variabile di livello classe privata, opta
per la variabile di livello classe privata. In questo modo, evitando i maggiori cicli del processore e
la memoria richiesta dalla routine di proprietà, l’applicazione sarà più veloce.

321
Parte 4: VBA avanzato

Definire eventi
Definire
Gli eventi possono essere molto utili in una classe, ma non puoi dare per scontato che tutti coloro
che usano la tua classe useranno gli eventi. Perciò, se decidi di usare gli eventi nella tua classe, devi
assicurarti che la classe continui a funzionare anche se l’utente non risponde a nessuno degli even-
ti.
Per definire un evento si usa l’istruzione Event. Agli scopi pratici, è in effetti una istruzione di
subroutine meno il codice. La definizione è necessaria perché identifica i parametri che saranno
passati all’evento. La definizione di evento è usata dal compilatore Visual Basic per garantire che il
numero e il tipo dei parametri e corrisponda alla definizione.
Capitolo 14

nota Sebbene sia possibile specificare quasi tutti i tipi di parametro che si possono usare in una subroutine,
gli eventi non possono avere argomenti denominati, parametri facoltativi o argomenti ParamArray.

Un esempio di definizione di esempio può essere come questo:

Event ErroreSconto (value As Currency, Msg As String)

All’interno della classe, puoi usare un’istruzione RaiseEvent per generare un evento nel programma
utente. L’istruzione RaiseEvent è seguita dal nome dell’evento e da un elenco di valori che saranno
passati al programma utente. Per esempio, questa istruzione ripassa due valori al programma chia-
mante.

RaiseEvent ErroreSconto(Sconto, "Cifra scontata non valida. ")

Per usare gli eventi in un’applicazione, deve essere inserita la parola chiave WithEvents quando si
definisce l’oggetto. Senza la parola chiave WithEvents, tutti gli eventi saranno ignorati. La seguente
istruzione mostra come dovresti dichiarare un oggetto con eventi:

Dim WithEvents Oggetto As GardenCompany

Definire variabili, subr


Definire outine e funzioni private
subroutine
Sebbene non sia necessario contrassegnare le subroutine o le funzioni come Private in una classe,
nota che senza la parola chiave Private, qualsiasi subroutine o funzione sarà Public per impostazio-
ne predefinita. In molte situazioni, questo potrebbe non essere un grosso problema, specialmente
se sei l’unico a utilizzare la classe. Tuttavia, se intendi condividere la tua classe con altri, potresti
scoprire che questi si affidano a una routine in cui hai accidentalmente omesso la parola chiave
Private, e non potresti cambiare la definizione della routine senza avere un impatto su tutti i pro-
grammi che la usano.

322
Capitolo 14: Sviluppare moduli di classe

Eventi speciali per le classi


VBA definisce due eventi speciali per tutte le classi: l’evento Initialize e l’evento Terminate.
L’evento Class_Initialize contiene un codice che sarà eseguito quando verrà creato un oggetto basa-
to su questa classe.
Questo evento è utile per inizializzare le variabili di livello classe ed eseguire tutte le istruzioni Set
New necessarie a creare tutti gli oggetti richiesti da quest’oggetto.

Set VariabileOggetto = New Class

Capitolo 14
L’evento Class_Terminate contiene un codice che verrà avviato appena prima che un oggetto venga
distrutto. Questo evento è un luogo ideale per distruggere oggetti che sono locali alla classe, impo-
standoli a Nothing con un codice simile a questo:

Set VariabileOggetto = Nothing

nota Gli eventi Class_Initialize e Class_Terminate sono attivati solo quando l’oggetto vero e proprio è
creato o distrutto. La semplice impostazione di una variabile oggetto a un’altra non avvierà l’evento
Class_Initialize. Se due o più variabili puntano allo stesso oggetto, la semplice impostazione di una
variabile oggetto a Nothing non avvierà l’evento Class_Terminate.

Risolvere i riferimenti
Risolvere
A volte ti troverai in una situazione in cui avrai una variabile locale e una variabile a livello di classe
con lo stesso nome. Questo spesso capita quando vuoi dare a un parametro in un metodo lo stesso
nome di una proprietà. Per differenziare una variabile di livello classe da una variabile o un para-
metro locale, puoi aggiungere il prefisso Me. Alla variabile di livello classe, come nel seguente esempio:

If Me.Nome <> Nome Then

In questa istruzione, la variabile Me.Nome si riferisce a una variabile a livello di classe, mentre la
variabile Nome non qualificata si riferisce a una variabile o a un parametro locale.

suggerimento Identificar
Identificaree ciò che appar tiene a Me
appartiene

La parola chiave Me può essere usata anche per qualificare un qualsiasi elemento pubblico o pri-
vato di una classe contenuto nel codice all’interno della classe, tra cui variabili di livello classe,
subroutine, funzioni e routine di proprietà.

323
Parte 4: VBA avanzato

Struttura delle classi


Ora che sai che cos’è una classe e come è possibile costruirne una, vale la pena di esporre brevemente
alcuni suggerimenti pratici per la costruzione delle classi.

Una classe semplice


È abbastanza ragionevole creare una classe che contenga soltanto proprietà e nessun metodo (vedi
figura 14-2).
Capitolo 14

Figura 14-2. Puoi costruire facilmente una classe semplice nell’editor di Visual Basic.

Puoi creare questa classe attenendoti a questi passaggi:

1 Seleziona Inserisci, Modulo di classe dal menu principale di VBA.


2 Seleziona la nuova classe nella finestra Gestione progetti e modifica la proprietà Name nella
finestra Proprietà in Pianta.
3 Inserisci le seguenti istruzioni:

Public NomeComune As String


Public NomeScientifico As String
Public Descrizione As String
Public PrezzoDettaglio As Currency
Public PrezzoIngrosso As Currency
Public CodiceProdotto As Long

324
Capitolo 14: Sviluppare moduli di classe

Estendere una classe semplice


Estendere
Uno dei vantaggi dell’usare una classe per contenere dei dati collegati tra loro è che puoi estendere
facilmente la classe usando molte tecniche diverse. Per esempio, puoi aggiungere un sinonimo per
una proprietà esistente con un paio di routine di proprietà in questo modo:

Public Property Get Nome() As String

Nome = NomeComune

End Property

Capitolo 14
Public Property Let Nome(valore As String)

NomeComune = valore

End Property

Queste routine sono usate per restituire e modificare una variabile di livello classe pubblica, permet-
tendo così all’utente di manipolare lo stesso valore usando due nomi diversi.
Un’altra utile tecnica è aggiungere un metodo che ti permetta di inizializzare tutte le proprietà del-
la classe con un’unica chiamata. Nota che la seguente routine si avvale della parola chiave Me in modo
che chiunque utilizzi questo metodo sappia quali parametri hanno effetto su quale proprietà.

Public Sub Inizializza(NomeComune As String, _


NomeScientifico As String, _
Descrizione As String, _
PrezzoDettaglio As Currency, _
PrezzoIngrosso As Currency, _
CodiceProdotto As Long)

Me.NomeComune = Nome
Me.NomeScientifico = NomeScientifico
Me.Descrizione = Descrizione
Me.PrezzoDettaglio = PrezzoDettaglio
Me.PrezzoIngrosso = PrezzoIngrosso
Me.CodiceProdotto = CodiceProdotto

End Sub

Una classe Collection


Spesso è utile creare una classe di raccolta per racchiudere un gruppo di oggetti. Questa operazio-
ne è notevolmente semplificata utilizzando l’oggetto Collection di Visual Basic per immagazzinare i
dati. Il seguente codice dichiara una variabile oggetto Collection che è locale nella classe. La prima
volta che la classe è istanziata viene creato l’oggetto Collection, e quando l’oggetto viene distrutto si
distrugge anche l’oggetto Collection.
325
Parte 4: VBA avanzato

Private MyPiante As Collection

Private Sub Class_Initialize()

Set MyPiante = New Collection

End Sub

Private Sub Class_Terminate()


Capitolo 14

Set MyPiante = Nothing

End Sub

Un oggetto viene aggiunto alla classe di raccolta usando il seguente codice. Il codice assume che l’og-
getto che si aggiunge abbia una proprietà Nome di tipo String. La routine inizia usando l’istruzione
On Error Resume Next per disattivare l’intercettazione degli errori. Tutti gli eventuali errori forze-
ranno Visual Basic a eseguire l’istruzione seguente. Per scoprire se si è verificato un errore, si utiliz-
za l’oggetto Err.

Public Sub Aggiungi(Elemento As Pianta)

Dim i As Long
Dim s As String

On Error Resume Next

i = 0
s = Elemento.Nome
MyPiante.Aggiungi Elemento, s
Do While Err.Number <> 0
i = i + 1
Elemento.Nome = s & "(" & FormatNumber(i, 0) & ")"
Err.Clear
MyPiante.Add Elemento, Elemento.Nome

Loop

End Sub

Il contatore i è inizialmente impostato a zero, e il nome del nuovo oggetto è salvato nella variabile
temporanea s. Quindi si usa il metodo Add dell’oggetto Collection per aggiungere il nuovo oggetto
all’oggetto Collection.

326
Capitolo 14: Sviluppare moduli di classe

Se si verifica un errore nel metodo Add, il contatore i è incrementato. Un nuovo Nome per l’oggetto
viene costruito usando il nome originale seguito da una parentesi aperta, il numero del contatore i
e una parentesi chiusa. Quindi la routine tenta ancora di aggiungere un nuovo oggetto alla raccolta.
Se il metodo Add fallisce di nuovo, il ciclo si ripete finché il nome dell’oggetto è unico.
Un elemento viene rimosso dalla raccolta chiamando il metodo Remove e specificando la posizione
relativa dell’oggetto o il valore della proprietà Name. In qualsiasi caso, il metodo Remove dell’oggetto
Collection è usato per rimuovere l’elemento dalla raccolta che sta alla base.

Public Sub Rimuovi(chiave As Variant)

Capitolo 14
MyPiante.Rimuovi chiave

End Sub

Allo stesso modo, il metodo Conta restituisce il numero di elementi della raccolta chiamando il
metodo Conta sottostante associato all’oggetto Collection.

Public Function Conta() As Long

Conta = MyPiante.Conta

End Function

Il metodo Cancella è utile se vuoi cancellare tutti gli oggetti della raccolta. Questa routine distrugge
solamente l’oggetto Collection alla base e quindi crea una nuova istanza dell’oggetto Collection.

Public Sub Cancella()

Set MyPiante = Nothing


Set MyPiante = New Collection

End Sub

Il metodo Item restituisce un singolo elemento della raccolta. Come nei metodi Remove e Count,
quest’elemento chiama semplicemente il metodo Item dell’oggetto Collection.

Public Function Elemento(chiave As Variant) As Pianta

Set Elemento = MyPiante.Elemento(chiave)

End Function

La seguente routine è una macro che si reitera in tutta la classe di raccolta che è appena stata creata.
La macro inizia creando un nuovo oggetto Piante chiamato MyPiante, che contiene una raccolta di
oggetti Pianta. Quindi il codice chiama il metodo AggiungiDati, che semplicemente aggiunge alcu-
ni oggetti di esempio alla raccolta.

327
Parte 4: VBA avanzato

Sub Test()

Dim MyPiante As Piante


Dim p As Pianta
Dim i As Long

Set MyPiante = New Piante


MyPiante.AggiungiDati
Capitolo 14

For i = 1 To MyPiante.Conta
Set p = MyPiante.Elemento(i)
MsgBox p.Nome

Next i

Set p = Nothing
Set MyPiante = Nothing

End Sub

Successivamente utilizza un ciclo For Next per reiterarsi in tutti gli elementi della raccolta. La variabile
oggetto p è impostata all’elemento corrente della raccolta, e la proprietà Nome è visualizzata in una
finestra di messaggio.
Nota che il primo elemento della raccolta comincia con 1, e il numero di elementi della raccolta è
recuperato dalla proprietà Conta della raccolta.

Da dove prendo i miei dati?


Le classi sono un modo ideale per raccogliere dei dati da un’origine esterna. Raccogliendo i dati in
una classe di raccolta Collection, puoi consentire al tuo programma di accedere ai dati indipenden-
temente dal modo in cui i dati sono fisicamente memorizzati.

In questo modo, se modifichi il tipo di memorizzazione dei dati, non dovrai cambiare il modo per
accedere ai dati. Fornendo un metodo chiamato CaricaDati, chiunque utilizzi la classe può carica-
re i dati dall’origine. Poi, se sposterai i dati da un foglio di lavoro a un database di Access, cambie-
rà soltanto il metodo di caricamento. Il codice che accede alla classe Collection non cambierà, a meno
che non modifichi i parametri dal metodo CaricaDati.

Similmente, puoi fornire un metodo standard chiamato SalvaDati, che aggiornerebbe i dati ovun-
que fossero memorizzati. Con un po’ di lavoro potresti addirittura rendere il metodo abbastanza
intelligente da aggiornare solo gli oggetti che sono già stati modificati, anziché aggiornare tutti i
dati compresi quelli non aggiornati dall’utente.

328
Capitolo 14: Sviluppare moduli di classe

Una classe con rregole


egole di convalida
È anche possibile estendere una classe aggiungendo alcune regole di convalida di base. Per esempio,
il seguente metodo convalida le informazioni dell’oggetto Pianta. Questo codice semplicemente
controlla ogni proprietà nella classe con condizioni potenziali di errore e restituisce True se non trova
errori e False se ne trova.

Public Function Valido() As Boolean

If Len(Nome) = 0 Then

Capitolo 14
Valido = False

ElseIf Len(NomeScientifico) = 0 Then


Valido = False

ElseIf CostoIngrosso < 0 Then


Valido = False

ElseIf PrezzoDettaglio < CostoIngrosso Then


Valido = False

ElseIf CodiceProdotto < 0 Then


Valido = False

Else
Valido = True

End If

End Function

La procedura Valido potrebbe essere modificata per restituire un messaggio di errore nel testo op-
pure addirittura una matrice String contenente un elenco di errori trovati nei dati.
Un altro modo per trovare gli errori è usare le routine di proprietà. Per esempio, potresti creare una
routine Property Let come questa.

Public Property Let PrezzoDettaglio(valore As Currency)

If valore > CostoIngrosso Then


MyPrezzoDettaglio = valore

329
Parte 4: VBA avanzato

Else
RaiseEvent ErrorePianta(1, _
"Prezzo al dettaglio minore del costo all’ingrosso.")

End If

End Property

La classe comprende una variabile a livello di classe privata chiamata MyPrezzoDettaglio che con-
tiene il valore della proprietà PrezzoDettaglio. Se il nuovo valore di PrezzoDettaglio è maggiore di
Capitolo 14

CostoIngrosso, il nuovo prezzo al dettaglio sarà salvato nella variabile MyPrezzoDettaglio.


Tuttavia, se qualcuno tenta di impostare il prezzo al dettaglio più basso del costo all’ingrosso, l’evento
ErrorePianta si attiverà, passando i dettagli dell’errore al programma che contiene l’oggetto.
In questo capitolo hai imparato le differenze tra una classe e un oggetto. Inoltre, hai imparato come
creare le tue classi personalizzate e come definire le proprietà, le routine di proprietà, i metodi e gli
eventi.
Sono stati discussi alcuni suggerimenti di progettazione per riconoscere oggetti, proprietà e metodi.
Infine, hai imparato come progettare diversi tipi di classi, tra cui la classe semplice e la classe di rac-
colta Collection, e come estendere le classi, inizializzare le classi e implementare regole di convalida.

330