Sei sulla pagina 1di 345

MANUALE VBA X EXCEL

VBA : informazioni generali ..........................................................................................................................2


Associazione Macro ..............................................................................................................................3
Casella Strumenti ...................................................................................................................................5
Colori e ColorIndex (tabella)................................................................................................................9
Cosa il VBA.........................................................................................................................................10
Cosa una macro...............................................................................................................................11
Editor di Visual Basic.............................................................................................................................12
Identifica celle e Intervalli...................................................................................................................15
Lunghezze procedure .........................................................................................................................16
Limitazioni relative ai progetti. ............................................................................................16
Limitazioni relative ai controlli..............................................................................................16
Numero massimo di controlli ...............................................................................................16
Limitazioni relative a controlli specifici ...............................................................................16
Limitazioni relative al codice...............................................................................................17
Routine, tipi a variabili ..........................................................................................................17
Tabella di dichiarazioni DLL .................................................................................................17
Tabella di importazione .......................................................................................................17
Limitazioni relative ai dati. ...................................................................................................17
Routine, tipi a variabili ..........................................................................................................18
Tipi definiti dall'utente...........................................................................................................18
Spazio dello stack .................................................................................................................18
Posizionare le Istruzioni.........................................................................................................................19
Registrazione Macro ............................................................................................................................22
VBA : Esempi ed esercizi in ordine alfabetico ..........................................................................................23
Aprire Applicativi (programmi) da Excel..........................................................................................24
Aprire file (o cartelle di Excel) .XLS ....................................................................................................27
Aprire tutti i files .xls contenuti in una cartella. ..................................................................27
Controllare se un files .xls gi aperto. ............................................................................27
AGGIORNAMENTO 09/01/04 ..............................................................................................28
AGGIORNAMENTO 09/10/03 ..............................................................................................29
Calcolare Valori nelle celle ................................................................................................................31
Calcolo date in VBA ............................................................................................................................33
Calcolo con le date in VBA 2.............................................................................................................40
Calcolo sulle date in VBA 3 ................................................................................................................45
Calendario perpetuo ..........................................................................................................................48
Cambiare i Fonts sul foglio di lavoro. ................................................................................................50
Caricare una ListBox ............................................................................................................................52
Cerca e seleziona ................................................................................................................................54
Un esercitazione interessante : Ricerca tra due date con totale dei
valori correlati. ......................................................................................................................................60
Ricerca di tre valori..............................................................................................................................65
Trovare un dato (vettore) in una tabella, con restituzione di un dato
correlato. ...............................................................................................................................................67
Cercare File(s) sull'Hard-Disk. ..............................................................................................................69
Controllo comunicazioni MSCOMM32.OCX per comunicare col
Modem e/o chiamare numeri telefonici. ........................................................................................72

http://ennius.interfree.it/ Pagina 1
MANUALE VBA X EXCEL

VBA : informazioni generali

http://ennius.interfree.it/ Pagina 2
MANUALE VBA X EXCEL
Associazione Macro

Una volta creata una macro inserita in un Modulo, dobbiamo poterla attivare alla bisogna. Potremo
usare uno dei seguenti metodi:
Dal men Strumenti/Macro cliccare su Macro, si aprir una finestra dove vengono elencate le macro
presenti nella cartella di lavoro, indi selezionata la macro desiderata, premere il pulsante "Esegui",
oppure premere il pulsante"Opzioni", e nella finestra che si apre, assegnare una lettera come "tasto di
scelta rapida" : CTRL + lettera da voi scelta e dare OK. In questo modo con la combinazione CTRL +
lettera attiverete la macro.
Dal men Visualizza/Barre degli strumenti e mettere un segno di spunta alla voce "Visual Basic",
apparir sul foglio di lavoro una piccola finestra come quella indicata dalla freccia rossa nella foto
sottostante. In questa finestra ci sono alcuni comandi: il primo da sinistra (un triangolo), se cliccato far
apparire la finestra delle macro, baster seguire la modalit del punto precedente. (in questa finestrina
appaiono altri comandi utili per le macro: il registratore, l'editor, ecc.

L'inconveniente legato a questi metodi palese: bisogna ripetere l'operazione tutte le volte che
vogliamo attivare una macro nel primo caso, mentre con l'assegnazione di "tasti di scelta rapida"
bisogner ricordarsi, in caso di pi macro presenti, quale la lettera giusta per una determinata
macro. La soluzione che consiglio quella di crearsi un pulsante (ottenibile comunque dall'inserimento
sul foglio degli "strumenti di controllo" (vedi foto sopra), usando invece la modalit "disegno". Se
Clicchiamo sulla barra degli strumenti, sull'icona "Disegno" (vedi foto sottostante) indicata con la
freccia del mouse (parte alta a destra), apparir sul piede del foglio (freccia rossa) gli oggetti
utilizzabili con questa modalit: le Word Art.

http://ennius.interfree.it/ Pagina 3
MANUALE VBA X EXCEL

Selezionando la forma "rettangolo" (vedi foto sotto), o la "casella di testo" (2 icone a destra)

e spostando il cursore del mouse in un punto qualsiasi del foglio, e tenendo premuto il pulsante del
mouse, disegnare un rettangolo di cui potremo variare le dimensioni a piacere. Cliccando sul bordo
del rettangolo col pulsante destro del mouse, apparir un men contestuale, dal quale, col sinistro del
mouse, sceglieremo "ASSEGNA MACRO", si aprir una finestra con le macro presenti e selezioneremo la
prescelta dando OK. In questo modo avremo creato un comodo avvio per la nostra macro, che
potremo attivare quando lo vorremo, infatti quando andremo col mouse sul pulsante associato, il
cursore assumer la forma di una mano, cliccheremo e la macro scatter.

Per completare l'opera, tornando sul bordo del pulsante, in basso a destra, col destro del mouse,
potremo scegliere "Aggiungi testo" e dare un nome per identificare a quale macro associata, e da
"Formato forme" per il "rettangolo" o da "formato casella di testo" per quest'ultima, potremo scegliere il
colore di fondo, per evidenziare il pulsante.
Un' ulteriore maniera quella di assegnare una macro ad un "CommandButton", selezionabile dalla
casella degli strumenti, ed in "modalit progetto", assegnare all'evento click del commandbutton la
suddetta macro. Ma questo lo vedremo nella sezione "Strumenti di controllo".

http://ennius.interfree.it/ Pagina 4
MANUALE VBA X EXCEL
Casella Strumenti

Una caratteristica di molti linguaggi di programmazione, e il VBA uno di questi, la "programmazione


ad oggetti". Per oggetti si intendono quelli strumenti che facilitano o migliorano la gestione del foglio di
lavoro e dei dati in esso contenuti, attraverso l'inserimento dell'oggetto stesso sul foglio di lavoro: sono
oggetti : commandbutton, casella combinata, casella di testo, option button, una form,ecc. Ogni
oggetto possiede delle propriet, dei metodi, e degli eventi . Le propriet sono le caratteristiche
che l'oggetto possiede e che possono essere modificate nelle impostazioni. Ogni oggetto ha le sue
proprie propriet, non necessariamente comuni ad altri oggetti. Per usare gli oggetti,una volta inseriti in
un foglio, dovremo lavorare in "modalit progettazione" (si attiva automaticamente quando inseriamo
l'oggetto, o si richiama cliccando sull'icona "squadra" nella casella degli strumenti); in questa modalit,
con un doppio click sull'oggetto, entreremo nell'editor di visual basic che ci mostrer nella finestra
inferiore a sinistra, le propriet dell'oggetto stesso. Sulla pagina destra troveremo invece la zona dove
inserire eventuali istruzioni da far eseguire scegliendo un evento dell'oggetto stesso. Per esempio,
usando un commandbotton, potremo sfruttare l'evento click, selezionandolo dalla finestrina in alto a
destra, e ci che vedremo sar cos:

Private Sub CommandButton1_Click()


qui inseriremo l'istruzione (macro)
End Sub

continuando: l'oggetto "CommandButton" o "pulsante di comando", ha la propriet "Caption"


impostata a "CommanButton1" (la propriet Caption la scritta che vediamo sul pulsante) Possiamo
modificare l'impostazione, scrivendo nel relativo campo delle propriet, le parole che ci ricordano
cosa avviene premendo il pulsante, per esempio "Aggiungi Dati". Ora, quando vedremo il pulsante, ci
troveremo scritto "Aggiungi Dati". Il metodo l'azione che l'oggetto "pu" compiere e l' evento
l'azione che attiva il metodo.
Vi consiglio di consultare la guida in linea, attivabile anche con F1, per familiarizzarsi con questi
concetti.
Vediamo, passo passo, come lavorare con questi strumenti: dal Men Visualizza/Barre degli strumenti,
selezionare la voce "Strumenti di Controllo" (o "Casella degli Strumenti" per le versioni pi vecchie di
Excel). vedi immagine sotto.

Apparir una piccola finestra come quella nelle foto sotto: la finestra degli strumenti: passando il
mouse sulle icone, appare la descrizione dell'oggetto. Nella foto sotto, a destra, evidenziata l'icona
http://ennius.interfree.it/ Pagina 5
MANUALE VBA X EXCEL
della "Modalit Progettazione". questa modalit dovr essere selezionata ogni qualvolta vorremo
intervenire sulle propriet dell'oggetto che avremo inserito sul foglio di lavoro. (la "Modalit
Progettazione si attiva in automatico allorch, selezionando un oggetto, lo "incolleremo" sul foglio di
lavoro).

Vediamo ora un esempio di come inserire e dialogare con un oggetto: la casella combinata. Nella
"Finestra degli oggetti", clicchiamo sull'icona "Casella Combinata", spostiamoci col mouse sul foglio di
lavoro e in corrispondenza della zona che avremo scelto per ospitare l'oggetto, clicchiamo col sinistro
del mouse e trasciniamo: apparir l'oggetto che potremo dimensionare a piacere agendo sui punti di
selezione (i circoletti). In questa fase saremo gi in "Modalit progettazione". Foto sotto: la casella
combinata

Ora dovremo passare alla visualizzazione delle propriet dell'oggetto per inserire le istruzioni che
faranno al caso nostro: il reperimento di una colonna di dati e la casella di destinazione dove vorremo
che il dato prescelto nella casella stessa, appaia. Doppio click sull'oggetto casella combinata, e si
aprir l'editor di visual basic. Vedi foto sotto a sinistra. Nella zona inferiore sinistra di questa foto
vediamo la finestra delle propriet relative al "ComboBox1", nome inglese della "casella combinata". Il
N 1 viene aggiunto dal codice per identificare che questa la casella combinata prima inserita, e,
poich ne potremo inserire altre, ad ognuna verr assegnato un numero di identificazione
progressivo.Nella foto sotto a destra vediamo invece le propriet che invece ci interessano da vicino:
"LinkedCell" e "ListFillRange". La prima identifica la cella che vorremo indicare per riportare i dati che
selezioneremo sul foglio di lavoro nella casella combinata, la seconda indica la zona dove la casella
combinata andr a trovare i dati che la stessa ci mostrer sul foglio di lavoro. Nell'esempio che
trattiamo, la lista dei nomi da cercare si trover nella colonna A, dalla riga 1 alla 8. Per il momento
trascuriamo di illustrare le altre propriet che saranno consultabili attraverso la guida in linea.

http://ennius.interfree.it/ Pagina 6
MANUALE VBA X EXCEL

Ritorniamo sul foglio di lavoro, clicchiamo sull'icona della "squadra" che identifica la "Modalit
progettazione" per uscire da questa modalit, e ci che vedremo sar quello illustrato nella foto sotto:

Nella casella combinata ora appare un elenco di nomi (quello che avevamo collegato con
"ListFillRange") , con un click su un nome, vedremo la cella C1 (quella collegata con "LinkedCell")
riempirsi del nome selezionato. Soprassiedo per il momento a ci che avremmo potuto fare sfruttando i
metodi e gli eventi .
Un ultimo accorgimento: poich la finestra degli strumenti resterebbe "a spasso" per il foglio di lavoro, si
pu chiuderla usando la famosa "X", ma meglio se si inserisce, cos l'avremo sempre a portata di mano,
in alto, sotto i men, cercando uno spazio tra le finestra gi inserite. E' sufficiente trascinare la finestra
dgli strumenti con il mouse, e rilasciare quando gli avremo trovato la giusta collocazione. Vedi foto
sotto:

http://ennius.interfree.it/ Pagina 7
MANUALE VBA X EXCEL

http://ennius.interfree.it/ Pagina 8
MANUALE VBA X EXCEL
Colori e ColorIndex (tabella)

Spesso ci necessita evidenziare con un colore diverso una o pi celle del nostro foglio di lavoro o il
carattere (Font) quando si verifica una determinata condizione, per esempio quando in una cella
appare o inseriamo un determinato valore, per esempio 100, oppure quando appare o scriviamo un
determinato giorno, per esempio "domenica", ecc. ecc. Dovremo, usando il codice Vba, utilizzare la
propriet CororIndex applicata all'oggetto Font o all'oggetto Interior (per la cella). Per esempio:
Questo esempio imposta a rosso il colore dei caratteri nella cella A1 del Foglio1.

Worksheets("Foglio1").Range("A1").Font.ColorIndex = 3

Questo esempio utilizza la propriet Interior per restituire l'oggetto Interior e imposta su rosso il colore
della parte interna della cella A1:

Worksheets("Foglio1").Range("A1").Interior.ColorIndex = 3

Ma al di l del tipo di istruzione utilizzata, (si pu usare la Funzione RGB che ci permette di disporre di
una gamma molto pi ampia di colori, e in questo caso l'istruzione va compilata come nel seguente
esempio:

Worksheets("Foglio1").Range("A1").Font.Color = RGB(255, 0, 0) per


avere il font rosso)

un problema nasce quando vogliamo sapere quale numero corrisponde ad un determinato colore;
ecco qu una tabella con i Codici Colore (ColorIndex) realizzata dal sottoscritto, con i colori ordinati
come nella tabella colori di excel, ed i nomi colore:

http://ennius.interfree.it/ Pagina 9
MANUALE VBA X EXCEL
Cosa il VBA

Per "CODICE", in Excel, intendiamo un linguaggio con il quale si scrivono istruzioni che Excel in grado
di capire e di eseguire, questo linguaggio si chiama : VBA (Visual Basic for Application). Esistono libri su
questo linguaggio, che pur essendo simile concettualmente ad altri linguaggi, usa tuttavia regole sue
che necessariamente dovranno essere gestite, ecco perch chi vuole reperire informazioni sul VBA
dovr munirsi dei libri specifici. (per esempio, della Jackson Libri, "Excel 2002 VBA", scritto dal "Maestro"
Gianni Giaccaglini, oppure della Apogeo, "Excel 2002 Macro" dell'altrettanto esimio Paolo Guccini).
Excel, per nostra grande fortuna, ha la capacit di compilare automaticamente del codice, quando
noi glielo chiediamo. Come?. Semplicemente dicendogli di registrare una "Macro". Dal menu:
Strumenti\macro\ selezionare: Registra nuova macro, apparir una finestra che ci chiede con quale
nome vogliamo chiamare la macro e, datogli il nome, premiamo su OK, apparir ora una piccola
finestrina con un pulsante che servir ad interrompere la registrazione. Il funzionamento semplice,
proprio come un normale registratore, solo che Excel registrer tutto ci che faremo sul foglio o sui fogli
di lavoro, (da selezione cella a immissione di una formula, da spostamenti a celle o colonne diverse, a
immissione di nuovi fogli, ecc.) e CONVERTIRA' in CODICE tutto ci che abbiamo fatto, registrandolo in
una zona opportuna, che noi non vediamo, ma che presente: premendo i tasti ALT + F11 oppure dal
men "Strumenti/Macro/Visual Basic Editor" si aprir la pagina dove si trova il codice. ALT + F6 per
richiudere la pagina. In questo modo potete cominciare a capire ci che avete fatto, collegandolo
con il codice che stato scritto da Excel. (Excel pone la registrazione di una macro in "Visual basic
editor", all'interno di un "Modulo", che troverete in alto sulla sinistra, nella finestrina degli "Oggetti".
Doppio click su "Moduli" e si apriranno "modulo1", "modulo2", ecc. Click su questi, e nella pagina sulla
destra compare il codice che Excel ha compilato.)
A lato trovate dei suggerimenti per argomenti correlati.

http://ennius.interfree.it/ Pagina 10
MANUALE VBA X EXCEL
Cosa una macro

La MACRO un' istruzione scritta in linguaggio Visual Basic che Excel usa per compiere determinate
azioni descritte nell'istruzione stessa. L'insieme delle istruzioni si definisce CODICE. Il Codice
compilabile, cio possiamo scriverlo, aggiungerlo, modificarlo come si farebbe con qualunque testo,
solo che necessario usare una forma di scrittura che Excel sia in grado di comprendere : il suo
linguaggio, il Visual basic for Application. Excel stesso in grado di compilare una Macro, cio del
codice : basta usare il "Registratore di Macro". (vedi sezione "Cosa il VBA"). Quello che segue un
piccolo esempio di codice( o macro. Da notare: ogni macro ha bisogno di un nome che la identifichi.
NON si pu usare lo stesso nome 2 volte):

Macro di esempio (o codice) Significato delle istruzioni


Nome della macro(Prova) (e inizio
Sub Prova()
istruzioni)
Range("A3").ClearContents
Pulisci la cella A3 dal contenuto
Range("A3").Formula = "=10*RAND()"
Nella cella A3 genera un numero casuale
End Sub
Fine istruzioni (esce dalla macro)

La stessa istruzione poteva essere svolta da una funzione : CASUALE() da scriversi nella cella A3. Es.:
=CASUALE()*10 (avrebbe generato un numero casuale compreso tra 0 e 10), per:
Considerazioni
Excel possiede quindi DUE possibilit di eseguire istruzioni:
la prima, e pi immediata, l'immissione di comandi attraverso le FORMULE o le FUNZIONI, che devono
essere inserite sul foglio di lavoro, scritte nelle celle interessate, e che quindi possiamo definire
"RESIDENTI", agiscono cio sempre e comunque (errori a parte). NON possono essere attivate su
comando, e molto spesso, ci costringono ad usare altre celle per scambi di istruzioni e non basta, pena
il famoso messaggio "Impossibile calcolare la formula, riferimento circolare", o si verificano solo ad
apertura Foglio.

la seconda, la creazione di codice che esegua, su COMANDO, un'istruzione di qualunque genere,


compreso ovviamente formule o funzioni, ma attivabili nel momento in cui eseguiamo il comando. In
questo caso avremo un'istruzione NON RESIDENTE, che ci consente una migliore gestibilit del nostro
lavoro, e la ripetitivit agendo di nuovo sul comando. Resta inoltre la versatilit di un linguaggio
(codice) capace di impostare istruzioni che con le formule o le funzioni non possibile eseguire (per
esempio i cicli For ...Next, o altre amenit del genere).

Il consiglio che vivamente suggerisco, quello, per colui che voglia avventurarsi nel mondo del
"CODICE", di munirsi di libri specifici sull'argomento, oltre a quello di dare sempre un "occhiata" alla
guida in linea, raggiungibile dalla pagina dell'editor di visual basic, premendo il tasto F1. (la guida
diversa se si preme F1 in visualizzazione Foglio di lavoro)

http://ennius.interfree.it/ Pagina 11
MANUALE VBA X EXCEL
Editor di Visual Basic

Raggiungere l'Editor di Visual Basic o Visual basic Editor (secondo le versioni di Excel) semplice, dal
Men Strumenti/macro/visual basic editor (vedi immagine sotto), oppure premendo i tasti ALT + F11.

Con l'editor aperto dovreste avere una pagina come l'immagine sottostante

In questa pagina, oltre al men, troviamo tre finestre :


la prima in alto a sinistra la finestra degli OGGETTI che compongono la cartella di lavoro
(ThisWorkbook) e sono i Fogli che compongono la cartella di default (3). Nella stessa finestra
compariranno i MODULI, se inseriti.
Nella finestra a sinistra, immediatamente sotto, c' la finestra delle Propriet degli oggetti presenti nella
finestra soprastante.
Nella terza finestra, quella grande sulla destra, la zona dove si pu scrivere il codice. Nella parte
superiore di questa finestra, ci sono due "men a tendina". Ogni foglio ha una propria pagina dove
poter scrivere il codice che riguarda istruzioni da eseguire all'interno della pagina stessa, il primo
sottomen sulla sinistra ci offre due possibilit di scelta (vedi immagine sottostante)

http://ennius.interfree.it/ Pagina 12
MANUALE VBA X EXCEL

Generale : verranno inserite istruzioni che avranno validit su tutto il foglio, come dimensionamento di
variabili, di funzioni personalizzate, ecc.
Worksheet : verranno inserite istruzioni "locali" che non si influenzeranno le une con le altre, cio se
dichiareremo una variabile, la stessa sar attiva solo all'interno della propria routine (Sub Pippo() ....End
Sub). Nel sottomen sulla destra, appare la scelta della selezione degli "EVENTI", cio delle cause che
attiveranno l'esecuzione di una o delle macro (vedi immagine sottostante).

Gli eventi sono scritti in inglese, come d'altra parte tutto il codice, ma sono facilmente comprensibili nel
significato: se scegliamo per esempio, l'evento "Change", diremo ad Excel che tutte le volte che nel
foglio avviene un cambiamento, si attiver la macro e svolger il compito assegnatole. In questo
modo, sempre per esempio, automatizzeremo l'esecuzione delle istruzioni: baster cambiare il valore in
una cella, per avere un evento "Change" che attiver l'esecuzione della macro. Ovviamente ci sono
controindicazioni, per questo opportuno valutare l'evento da scegliere per evitare effetti indesiderati.
Consideriamo per esempio, che il semplice inserimento di un numero in una nuova cella, causerebbe
l'esecuzione della macro, anche se in quel momento a noi la macro non servisse. Aiutatevi con la
guida in linea per avere le spiegazioni relative ad ogni evento. Un possibile accorgimento per usare
istruzioni eseguibili su Eventi del foglio quello di inserire istruzioni legate alla formattazione delle celle, o
dei caratteri (font) o di un colore di fondo, o di selezione di un area di stampa, ecc. insomma per
istruzioni di carattere generale o parziale, che non tocchino formule o celle con valori che vorrete
modificare su vostro comando. L'intestazione della macro, comunque, inizier cos :

Private Sub Worksheet_Change(ByVal Target As Range) (Nome e inizio


della Macro o Routine )
in questo spazio va inserito il codice
End Sub (Fine della macro e uscita)

Quando non vogliamo usare un EVENTO abbinato ad un foglio per attivare una macro, perch
vogliamo decidere noi quando attivarlo, potremo usare un MODULO e scrivere il codice nel modulo,
dando un nome alla routine (macro) per poi associarla ad un pulsante usando il nome assegnato in
precedenza (vedi: Associazione Macro). L'inserimento di un Modulo semplicissima: dal men
scegliamo Inserisci/Modulo (vedi immagine sottostante).

http://ennius.interfree.it/ Pagina 13
MANUALE VBA X EXCEL

Nella finestra degli oggetti, apparir il simbolo di una cartella con il nome "Moduli". DoppioClick sulla
cartella e si aprir mostrando il contenuto: "Modulo1", "Modulo2", e cos via. Va precisato che in un
modulo, si possono inserire pi macro, non occorre quindi creare un modulo per ogni macro; queste
infatti saranno riconosciute dal nome assegnato, non dalla residenza in un modulo piuttosto che un
altro. Attenzione a non affollare comunque troppo il modulo (quando il modulo viene letto per cercare
la macro richiesta, vengono lette comunque tutte le macro presenti nel modulo stesso). La finestra che
si aprir sulla destra conterr, nei sotto men in alto, solo "GENERALE" e "DICHIARAZIONI", zona che
servir ad assegnare variabili utilizzabili in tutte le macro presenti nel Modulo. L'inserimento della macro
semplice, basta scrivere il nome che vogliamo, preceduto da Sub e seguito da () parentesi aperta e
chiusa, e alla fine del codice, scrivere "End Sub". Esempio.

Sub Ciccio()
in questa zona scrivere le istruzioni
End Sub

Un altro modo di inserire il codice lo vedremo nella sezione "Casella degli strumenti" ora detta
"Strumenti di controllo", anche se simile al precedente.

http://ennius.interfree.it/ Pagina 14
MANUALE VBA X EXCEL
Identifica celle e Intervalli

http://ennius.interfree.it/ Pagina 15
MANUALE VBA X EXCEL
Lunghezze procedure

Lunghezze e max dimensioni procedure in vb.

In risposta ad una domanda, Michele (Mike page) ha trovato una documentazione che, per i suoi
contenuti, potr interessare diversi "pellegrini", sull'argomento in oggetto, e come tale la riportiamo
quasi integralmente.

Limitazioni relative ai progetti.


Un singolo progetto pu contenere fino a 32.000 identificatori, tra cui form, controlli, moduli, variabili,
costanti, routine, funzioni a oggetti. I nomi di variabili possono essere composti da un massimo di 255
caratteri, i nomi di form, controlli, moduli a classi da un massimo di 40 caratteri. Non esiste alcun limite
al numero di oggetti per un progetto.

Limitazioni relative ai controlli


Ciascun controllo di tipo non grafico, ovvero tutti i controlli tranne linee, forme, immagini ed etichette,
utilizza una finestra. Ciascuna finestra utilizza a sua volta risorse di sistema. II numero massimo di finestre
che possibile utilizzare contemporaneamente risulta pertanto limitato a dipende dalle risorse di
sistema disponibili a dal tipo di controlli utilizzati.
Per limitare il consumo di risorse di sistema, consigliabile creare o visualizzare gli elementi grafici
utilizzando i controlli forma, linea, etichetta a immagine anzich i controlli casella immagine.

Numero massimo di controlli


II numero massimo di controlli consentito in un singolo form dipende dal tipo di controlli utilizzati a dalle
risorse di sistema disponibili. Esiste tuttavia un limite fisso di 254 nomi di controlli per form. Una matrice di
controlli viene considerata un solo controllo, in quanto a tutti i controlli in essa contenuti a assegnato to
stesso nome.
In tutte le versioni il limite degli indici di una matrice di controlli a compreso try 0 e 32.767.
Nel caso di controlli nidificati, ad esempio quando vengono inseriti alcuni controlli cornice all'interno di
altre cornici, non a possibile nidifrcare piu di sei livelli di controlli.

Limitazioni relative a controlli specifici


Nella tabella seguente sono elencate le limitazioni relative alle propriet applicate ad alcuni controlli
specifici di Visual Basic

Propriet Si applica a Limitazione


List e Controlli casella di II numero massimo di voci
ListCount riepilogo a casella a pari a 32 KB. 11 limite
combinata delle dimensioni di
ciascuna voce a pari a 1
KB (1.024 byte).
Text Controllo casella di testo Le dimensioni massime
sono pari a
64 KB.
Caption Controllo etichetta Le dimensioni massime
sono pari a 1.024 byte
Controllo pulsante di Le dimensioni massime
comando casella di sono pari a 255 caratteri.
controllo cornice e Le didascalie che

http://ennius.interfree.it/ Pagina 16
MANUALE VBA X EXCEL
pulsante di opzione superano questo limite
risulteranno troncate. Le
dimensioni massime per le
didascalie di controlli
aggiuntivi sono pari a 32
KB
Controllo menu Le dimensioni massime
sono pari a 255 caratteri
Tag Tutti i controlli Le dimensioni massime
dipendono dalla memoria
disponibile
Name Tutti i controlli Le dimensioni massime
sono pari a 40 caratteri

Nota : In Visual Basic, i nomi delle propriety dei controlli non devono essere composti da piu di 30
caratteri.

Limitazioni relative al codice.


II numero massimo di righe di codice che possibile caricare in un form, una classe o un modulo
standard a pari a 65.534 righe. Una singola riga di codice pu equivalere a un massimo di 1.023 byte. II
testo di una riga pub essere preceduto da un massimo di 256 spazi, mentre in una singola riga logica si
possono includere fino a nove caratteri di continuazione riga (_).

Routine, tipi a variabili


Non esiste alcun limite al numero di routine, tipi a variabili che possibile inserire in un modulo.
Ciascuna routine pu includere fino a 64 KB di codice. Se si supera questo limite, verr generato un
errore di compilazione che possibile risolvere suddividendo le routine di grandi dimensioni in routine
piu piccole o spostando le dichiarazioni a livello di modulo in altri moduli.
I nomi degli identificatori utilizzati nel codice, ovvero variabili, routine, costanti a cosi via, vengono
registrati in tabelle. Le dimensioni massime di ciascuna tabella sono pari a 64 KB.

Tabella di dichiarazioni DLL


Ciascun form e ciascun modulo utilizza una tabella contenente una struttura che descrive una voce
della DLL. Ciascuna struttura utilizza circa 40 byte a pu avere dimensioni massime pari a 64 KB,
corrispondenti a circa 1.500 dichiarazioni per modulo.
Tabella dei nomi del progetto
L'intera applicazione utilizza una singola tabella contenente tutti i nomi inclusi nel progetto, ovvero:
Nomi di costanti
Nomi di variabili
Nomi di tipi definiti dall'utente
Nomi di modulo
Nomi delle dichiarazioni delle routine DLL
Non esiste alcun limite alle dimensioni totali della tabella dei nomi del progetto. Esiste invece un limite
di 32 KB per voci univoche della tabella in cui la distinzione tra maiuscole e minuscole rilevante. Se si
raggiunge questo limite, sar possibile riutilizzare gli identificatori privati in altri moduli.

Tabella di importazione
Con ciascun riferimento agli identificatori inclusi in altri moduli viene creata una voce nella tabella di
importazione. Le dimensioni di ciascuna voce devono essere comprese tra un minimo di 24 byte a un
massimo di 64 KB, equivalenti a circa 2.000 riferimenti per modulo.
Tabella delle voci di moduli
Questa tabella accetta fino a 125 byte per modulo, con un limite massimo di 64 KB, equivalenti a 400
moduli per progetto.

Limitazioni relative ai dati.


Le limitazioni descritte di seguito sono relative alle variabili del linguaggio Visual Basic.
Dati di moduli di form, standard a di classe
http://ennius.interfree.it/ Pagina 17
MANUALE VBA X EXCEL
Ciascun modulo di form, standard a di classe ha un proprio segmento di dati che pu avere
dimensioni massime pari a 64 KB. 11 segmento contiene i seguenti dati:
Variabili locali dichiarate con Static.
Variabili a livello di modulo diverse da matrici a da stringhe di lunghezza variabile.
4 byte per ciascuna matrice a livello di modulo e stringhe a lunghezza variabile.

Routine, tipi a variabili


Quando in una routine o in un modulo viene superato il limite massimo di 64 KB di codice, viene
generato un errore di compilazione. Per risolvere questo errore, possibile suddividere le routine di
grandi dimensioni in routine piu piccole o spostare le dichiarazioni a livello di modulo in altri moduli.

Tipi definiti dall'utente


Le variabili dei tipi definiti dall'utente non devono essere superiori ai 64 KB. La somma delle stringhe di
lunghezza variabile in un tipo definito dall'utente, tuttavia, pu superare questo limite. Ciascuna stringa
occupa infatti solo 4 byte in un tipo definito dall'utente, in quanto 1'effettivo contenuto viene registrato
separatamente. I tipi definiti dall'utente possono essere definiti in rapporto ai tipi definiti da altri utenti.
La somma totale dei tipi non deve essere tuttavia superiore a 64 KB.

Spazio dello stack


Gli argomenti e le variabili locali nelle routine occupano spazio dello stack in fase di esecuzione. Le
variabili statiche e a livello di modulo invece non occupano alcuno spazio dello stack in quanto sono
assegnate al segmento di dati di form o moduli, Lo spazio dello stack viene utilizzato anche durante
1'esecuzione di routine DLL.
Parte dello spazio dello stack viene inoltre utilizzato da Visual Basic stesso, ad esempio per la
registrazione di valori intermedi durante la valutazione di espressioni.

http://ennius.interfree.it/ Pagina 18
MANUALE VBA X EXCEL
Posizionare le Istruzioni

Considerazioni su DOVE inserire il codice (Le Istruzioni in codice VBA).


Abbiamo visto che cos' una Macro : una o pi istruzioni compilate in linguaggio VBA e come
associare una macro per attivare le istruzioni in essa contenute. Vorrei per riepilogare meglio i
concetti di QUANDO e DOVE posizionare le istruzioni, cercando di spiegare PERCHE'.
E' necessario ribadire che il VBA un linguaggio di programmazione a "OGGETTI" - In una cartella di
lavoro di Excel, sono "oggetti" i fogli di lavoro (Foglio1, Foglio2, ecc), la stessa cartella (WorkBook), e,
trascurando per ora di parlare dell'oggetto "Range", sono "oggetti" anche tutti gli strumenti che
possiamo inserire in un foglio di lavoro, quali ad esempio, un Commandbutton, un Combobox, un
Pulsante di Opzione, una UserForm, un textbox, ecc.. Tralasciando di parlare in questo paragrafo delle
"Propriet" degli "oggetti", fisseremo la nostra attenzione sugli "EVENTI" che OGNI "Oggetto" possiede.
Per "EVENTO" si intende l'"AZIONE" che si deve compiere per ATTIVARE le istruzioni abbinate all'"Oggetto"
di cui l'evento fa parte.
Precisiamo che esistono due modi per attivare le istruzioni (che da ora chiameremo "codice"):

attivazione in automatico
attivazione su comando

Per l'attivazione di codice in Automatico, useremo gli oggetti WorkBook, ed i Fogli, sfruttando gli eventi
ad essi collegati: se per esempio, vogliamo che un'istruzione si attivi ad ogni apertura della cartella di
lavoro, sceglieremo l'evento "Open" dell'oggetto "WorkBook", scrivendo il codice tra inizio e fine della
routine che Excel stesso, se selezioneremo l'oggetto WorkBook nell'editor di visual basic, provvede ad
inizializzare:

Private Sub Workbook_Open()


in questa zona va scritta l'istruzione
End Sub

Oppure, secondo esempio, se vogliamo che l'istruzione si attivi ad ogni variazione in un foglio di lavoro,
possiamo scegliere l'evento "Change" dell'oggetto "Foglio1" ripetendo quando detto nell'esempio
precedente:

Private Sub Worksheet_Change(ByVal Target As Range)


MsgBox ("Ciao !")
End Sub

Appare evidente che, selezionando l"Evento" pi appropriato, tra quelli disponibili per l"oggetto" scelto,
potremo pilotare l'esecuzione di codice come pi ci necessita, compreso rendere l'automatismo
dell'evento ancora pi flessibile, inserendo un'istruzione opportuna, per esempio:

Private Sub Worksheet_SelectionChange(ByVal Target As Range)


If Range("A1") = "" Then exit Sub
MsgBox ("Ciao !")
End Sub

(la differenza tra i due eventi sopra, che sembrano simili, questa: l'evento "Change" si verifica
quando, selezionando una cella, inseriamo un valore o modifichiamo quello gi presente, premendo
invio, altrimenti non si ha l'evento "Change". L'evento "SelectionChange" si verifica anche quando
selezioniamo o clicchiamo su una cella diversa da quella attualmente selezionata, e quindi
praticamente sempre, compreso un inserimento valore o modifica valore, perch dovremo
http://ennius.interfree.it/ Pagina 19
MANUALE VBA X EXCEL
deselezionare la cella in questione per attivare la modifica, selezionandone un altra, compreso l'uso
del tasto "invio" che sposta il focus sulla cella sottostante e quindi genera un cambio di selezione.)
L'esempio sopra, nonostante sia abbinato all'evento "SelectionChange" (cambio di selezione di cella) e
quindi praticamente ad ogni modifica che facciamo su un Foglio, "usa" un "interruttore di consenso"
rappresentato da una cella (A1 per esempio): l'istruzione dice: "Se la cella A1 vuota, esci da questa
routine" : cio non viene pi eseguito tutto ci che si trova sotto. Infatti l'esecuzione di qualunque
istruzione contenuta tra inizio e fine routine, avviene sempre eseguendo le istruzioni riga dopo riga,
partendo da inizio istruzioni e fino alla fine. Potremo quindi scrivere in A1 "Si" o qualunque altra cosa e
l'istruzione verr eseguita fino in fondo, o lasciare la stessa cella vuota per evitare di attivare la stessa
istruzione.
Il vantaggio di esecuzione di codice in automatico appare quindi evidente: non dovremo premere
nessun pulsante, o richiamare nessuna macro, perch sar sufficiente il verificarsi di un "evento" .
Ci sono istruzioni che per vorremo attivare direttamente noi, e non lasciarle gestire da "eventi"
collegati ad un foglio di lavoro, sono quelle definite "Attivazione su comando". Questo tipo di istruzioni si
possono inserire in due modi:
Inserimento in un Modulo
Inserimento in un "Evento" associato ad un oggetto preso dalla Casella degli Strumenti
L'inserimento in un modulo forse il metodo pi conosciuto e lo stesso usato da Excel quando si fa uso
del "Registratore di Macro". Manualmente si ottiene recandosi nell'editor di visual basic e, da "Inserisci",
scegliamo "Modulo"; appare nella finestra degli "Oggetti" una nuova cartella "Moduli" e cliccandoci si
apre mostrandoci "Modulo 1". Nella parte destra si dovr inserire il codice, avendo cura di dare un
nome alla routine, per esempio "Sub conteggi()". Excel predisporr "End Sub". All'interno tra inizio e fine
scriveremo il nostro codice. Esempio, facciamo eseguire due semplici operazioni, la somma di due
celle (A1+A2) e la divisione della somma per 2, il risultato lo vogliamo in C1:

Sub conteggi()
Range("C1") = (Range("A1") + Range("A2")) / 2
End Sub

Il vantaggio di questa soluzione e che disporremo di un codice che potremo attivare a nostro
piacimento. Come? Associando il codice (macro) ad un pulsante ottenuto usando un "Formato forme"
degli strumenti "Disegno", magari un "rettangolo". Al "rettangolo" possiamo cambiare la dimensione,
aggiungere del testo, cambiare il colore di sfondo e del font, posizionarlo sul foglio dove pi ci piace,
ecc. ecc. Una volta associato il "pulsante" ad una macro, tutte le volte che ci cliccheremo sopra,
attiveremo il codice contenuto nella stessa macro. Un altro modo quello di lavorare con la finestra
"Moduli" ottenibile da "Visualizza/Barre degli Strumenti/Moduli". Appare una finestra con una serie di
icone che rappresentano degli oggetti simili a quelli che sono nella finestra "Strumenti di Controllo":
ATTENZIONE: non sono "OGGETTI", infatti non possiedono "Propriet" n "Eventi". Assomigliano molto di
pi alle "Forme" ottenibili da "Disegno" anche se il loro aspetto decisamente pi consono.
L'associazione al codice ancora pi diretta: cliccando sull'icona "pulsante" e trascinando sul foglio,
apparir un bel pulsante e contemporaneamente una finestra per associazione alla macro, basta
selezionare quella giusta. Trascuro di parlare dell'attivazione macro attraverso il percorso che passa dal
men "Strumenti/ Macro/Macro/Nome Macro/ Esegui" , secondo me troppo lungo e noioso. La
differenza sostanziale che notiamo in queste soluzioni che non sfrutteremo pi nessun "EVENTO".
Come contropartita, oltre ad inserire pulsanti sul nostro foglio di lavoro, (spesso lo spazio a disposizione
non ci lascia troppe chances), avremo un' esecuzione codice che attiveremo solo se interveniamo noi.
Esistono tuttavia casi nei quali vorremmo che l'attivazione del codice si verificasse in automatico, ma
SOLO se interveniamo noi modificando uno o pi dati del foglio di lavoro. Un p come avviene con le
formule inserite in un foglio di lavoro: basta cambiare un dato in una cella richiamata in una formula, e
il risultato si aggiorna automaticamente senza bisogno di codice. (ricordo per che il codice NON pu
risiedere sul foglio di lavoro e quindi v attivato, in una maniera o nell'altra). Questi casi si affrontano
utilizzando gli "Eventi" degli "OGGETTI" "STRUMENTI" presi dalla "Finestra degli Strumenti" o "Strumenti di
Lavoro" , che sono la stessa cosa , ma vengono chiamati diversamente a secondo la versione di Excel
che abbiamo. Se inseriamo in un foglio di lavoro, per esempio, un "combobox" detta in italiano "casella
combinata", potremo sfruttare gli "eventi" che possiede (Change, Click, Dblclick, LostFocus, Keypress,
ecc. ecc), scegliendo l'evento che meglio si adatta per attivare il codice, che ovviamente andr
http://ennius.interfree.it/ Pagina 20
MANUALE VBA X EXCEL
inserito tra inizio e fine routine che si genera appena scelto l'evento da noi selezionato. Continuando
con l'esempio, ipotiziamo di avere collegato la propriet "ListFillRange" dell'oggetto combobox1 alla
colonna A del Foglio1, dove dalla 5 alla 20a riga abbiamo inserito un elenco di nomi (ListFillRange
A5:A20), e di avere scelto l' evento "Click", vedremo che la routine inizier con

Private Sub ComboBox1_Click()


Qui inseriremo l'istruzione
End Sub

Tornati sul foglio di lavoro, e usciti da modalit progettazione con un click sull'icona "Squadra" della
finestra degli strumenti, vedremo che la nostra "casella combinata" porta tutti i nomi presenti nel range
di celle che gli avevamo assegnato nella propriet ListFillRange. Baster selezionare un nome, tra quelli
inseriti, (per selezionare usiamo un Click del mouse), per vedere attivato il nostro codice. L'evento
"Click" si verifica tutte le volte che cliccheremo nella "zona bianca" della casella, NON se clicchiamo sul
triangolino nero che attiva il "men a discesa (zona bianca o, se preferite, la lista dei nomi)". Se questo
evento pu generare errori per "cliccaggi" imprecisi, potrete usare l'evento "Change" che si verifica
tutte le volte che si "cambia", selezionandolo dal men a discesa, un nominativo.
Ritengo che l'attivazione di codice attraverso un "evento" collegato ad un "oggetto" sia di gran lunga
da preferire, quando possibile, ad altri sistemi, compreso l'uso di un semplice "commandutton", in cui,
nell'evento Private Sub CommandButton1_Click() inseriremo il nostro codice anzich usare i
moduli. (in questo caso non occorrer dare un nome alla macro perch il nome esiste gi)

http://ennius.interfree.it/ Pagina 21
MANUALE VBA X EXCEL
Registrazione Macro

Registratore di macro.
Il modo pi veloce per compilare codice quello di affidarsi al "Registratore di Macro". Come spiegato
in questa sezione su "Cosa il VBA" . Qualunque azione compiamo nella nostra cartella di lavoro, verr
scrupolosamente REGISTRATO, SCRITTO E CONVERTITO in codice VBA, visibile poi usando il Visual Basic
Editor. L'utilit di questo strumento, il registratore, importantissima per chi, spinto dal desiderio di
approfondire le proprie conoscenze sul VBA, voglia cominciare a comprendere COME si compila del
codice. E' sufficiente avviare il registratore di macro (vedi immagine a sinistra), apparir prima una
finestra dove ci verr chiesto con quale nome vogliamo salvare la nostra macro, scelto un nome e
confermato con OK, apparir una piccola finestra con un quadratino blu: il pulsante di fine
registrazione (vedi immagine a destra - la finestrina spostabile, tramite mouse, all'interno del foglio),

Cominciamo ad eseguire sul foglio di lavoro le operazioni che normalmente faremmo, per esempio:
selezione della cella in cui vogliamo inserire una formula. (esempio la cella A10)
Inserimento nella cella A10 della formula (con relativo segno = (uguale) all'inizio) esempio
=SOMMA(A1:A9) cio in A10 voglio il totale dei valori contenuti dalla cella A1 alla cella A9 comprese.
Clicchiamo sul pulsante di fine registrazione, che si chiuder automaticamente: bene la macro
compilata e registrata. Ora dal Men Strumenti/Macro selezioniamo Visual Basic Editor e vedremo che
se non c'era, nella casella degli oggetti e comparsa una nuova cartella Moduli, apriamo la cartella e
troveremo "Modulo 1", doppio click su quest'ultimo e sulla destra apparir la nostra macro: la
riconosceremo perch comincer con la data di creazione della macro e il nome della macro

Sub Nome da noi scelto()


Range("A10").Select
ActiveCell.FormulaR1C1 = "=SUM(R[-9]C:R[-1]C)"
Range("A11").Select
End Sub

Tutto ci che compreso tra Sub - End Sub E' IL CODICE scritto nel famigerato VBA.
Coloro che volessero cominciare a capirne il significato, potranno usare la guida in linea, dove c'
tutto, ovviamente diviso per voce e per argomenti, oppure acquistarsi un libro sull'argomento "Excel e il
codice VBA"
Va da se, che continuando a registrare macro su nuove azioni, cominceremo a crearci un esperienza
delle varie compilazioni relative alle nuove azioni. Chi ben comincia....... o, se preferite, aiutati che
Iddio.......

http://ennius.interfree.it/ Pagina 22
MANUALE VBA X EXCEL

VBA : Esempi ed esercizi in ordine alfabetico

http://ennius.interfree.it/ Pagina 23
MANUALE VBA X EXCEL
Aprire Applicativi (programmi) da Excel

Quando vogliamo aprire da Excel, un file realizzato con un altro programma, (per esempio un file di
Word, un database di Access, una presentazione di PowerPoint, ecc.) dobbiamo per prima cosa aprire
l'Applicativo che ha generato il file, e nell'Applicativo aperto, far aprire poi il file. L'istruzione da
compilare (una macro) dovr necessariamente prevedere l'indirizzo completo (PathName) dove
risiedono sia l'eseguibile (.exe) dell'Applicativo, sia in file da aprire. Per richiamare un file faremo ricorso
alla Shell di sistema inserendo i percorsi suddetti. Per fare un esempio, ipotizziamo di aprire il file
Pippo.doc che si trover nella cartella Documenti, l'istruzione quindi sar (gli manca "qualcosa", ma
solo per vedere come costruire la stringa):
Shell ("C:\Programmi\Microsoft Office\Office\WINWORD.EXE C:\Documenti\Pippo.doc", 1)
Come vedete, abbiamo inserito il percorso, prima dell'eseguibile, poi, preceduto da uno spazio,
l'indirizzo dove risiede il file, poi una virgola, indi il numero 1 che serve a far aprire il file in primo piano.
Ricordo che per indicare un "percorso" si deve primo, indicare l'unit (cio Hard-disk. Floppy, o CD-
Rom) seguito dalla cartella ed ev. dalle sottocartelle dove risiede il file da aprire. (l'unit si indica
sempre con Una Lettera, (C o D ecc.) seguita da due punti ( : ) e la barra rovesciata ( \ ). Associando
ad un pulsante, la macro, con un click otterremo l'apertura di Word che aprir il file Pippo.doc, e la
finestra di Word apparir sopra quella di Excel che non viene chiuso. (L'istruzione sopra descritta, cos
com, non funziona; per renderla funzionale bisogna togliere la virgola e in numero 1, cos modificata,
aprirebbe Word ma non ci metterebbe il focus, cio Word sarebbe aperto, ma SOTTO la finestra di
Excel). Per avere Word in vista, l'istruzione v modificata con l'aggiunta di una variabile, cos:

Dim myval
myval = Shell ("C:\Programmi\Microsoft Office\Office\WINWORD.EXE
C:\Documenti\Pippo.doc", 1)

Questa istruzione funziona, ma presenta due inconvenienti : il primo che l'istruzione pu diventare
"chilometrica", il secondo che non tutti si rinvengono nel trovare il percorso dell'eseguibile. Per fortuna
esiste un alternativa, l'utilizzo del metodo "Start" abbinato alla Shell, che ci consente di risparmiare
spazio, ma soprattutto lascia alla Shell il compito di trovare il giusto percorso dell'eseguibile. La cosa
funziona solo con tutti gli eseguibili di quei programmi che, in fase di installazione, si "registrano" nel
Registro di Windows. Vediamo quindi questa istruzione, la prima per aprire solo il programma (Word per
esempio), la seconda per aprire Word e il file che ci interessa:

Shell ("Start Winword.exe")


oppure
Shell ("Start Winword.exe C:\Documenti\Pippo.doc")

Una precisazione l'utilizzo del metodo Start, funziona con tutte le versioni di Windows98, 98SE, ME, ma
non funziona con Windows XP (non ho ancora capito perch, anzi se qualcuno riesce a fornirmi il
motivo, avr la mia gratitudine, e sar citato come "salvatore della patria"). Con XP necessario usare
un altro tipo di istruzione (per aprire un' altra Applicazione Microsoft da Excel), che per consente di
aprire solo l'eseguibile, ed questa:

Application.ActivateMicrosoftApp xlMicrosoftWord
(E SOSTITUISCE QUESTA: Shell ("Start Winword.exe"))
Gli Applicativi richiamabili, sono:
xlMicrosoftWord
xlMicrosoftPowerPoint
xlMicrosoftMail

http://ennius.interfree.it/ Pagina 24
MANUALE VBA X EXCEL
xlMicrosoftAccess
xlMicrosoftFoxPro
xlMicrosoftProject
xlMicrosoftSchedulePlus

In data 01/04/03 Giuliano Gialli giulianoyellows@inwind.it ci fornisce una soluzione al problema Start
con WindowsXP e Windows2000, sembra l'uovo di Colombo, ma bisognava pensarci, e Giuliano lo ha
fatto. Questa la sua proposta, che funziona : bastava togliere Start e fare riferimento solo alla Shell,
cos:

Shell ("Winword.exe"), 1

oppure se si deve aprire un file predefinito, far seguire al nome dell'applicativo il percorso del file da
aprire con l'applicativo stesso:

Shell ("Winword.exe C:\Documenti\Pippo.doc"), 1

Un sentito grazie a Giuliano. Le varianti sotto riportate potranno essere quindi modificate con l'utilizzo
della soluzione appena esposta:

Queste sono 2 varianti per aprire Word ed il file, necessario il path completo anche di WordXP che su
WindowsXP diverso dalle altre versioni:

Dim myVal
myVal = Shell("C:\Programmi\Microsoft Office\Office10\WinWord.exe
C:\Documents And Settings\Nome Utente\Documenti\Pippo.doc", 1)
Variante Giuliano:
Shell("WinWord.exe C:\Documents And Settings\Nome
Utente\Documenti\Pippo.doc"), 1

Seconda variante in due mosse:


la prima consiste in una variabile fissa (X) che porta il path completo, simile alla precedente:
Dim X
X = "C:\Programmi\Microsoft Office\Office10\WinWord.EXE C:\Documents
And Settings\Nome Utente\Documenti\Pippo.doc")
myVal = Shell(X, 1)

Variante1 Giuliano:
Dim X
X = "C:\Documents And Settings\Nome Utente\Documenti\Pippo.doc"
Shell ("WinWord.exe " & X & ""), 1

La seconda, pi interessante perch consente di poter variare sia il nome dell'eseguibile, sia il nome del
file da aprire, legge i percorsi posti in due celle del foglio di lavoro.
Mettiamo in A1 il path di Word e in A2 il path del file: cambiando inA2 il percorso possiamo mirare a
qualunque file .doc , in qualsiasi cartella si trovi

http://ennius.interfree.it/ Pagina 25
MANUALE VBA X EXCEL
Dim X
X = Range("A1").Value & " " & Range("A2").Value
myVal = Shell(X, 1)

Variante2 Giuliano:
Dim X
X = (Range("A1").Value) & " " & (Range("A2").Value)
Shell (X), 1
il numero 1 che vediamo nell'istruzione serve per mettere il focus su
Word

http://ennius.interfree.it/ Pagina 26
MANUALE VBA X EXCEL
Aprire file (o cartelle di Excel) .XLS
Aprire tutti i files .xls contenuti in una cartella.

Controllare se un files .xls gi aperto.

Sul sito esistono gi suggerimenti per l'apertura di file .xls, anche nella sezione "le vs domande", ma visto
che continuano ad arrivare richieste specifiche, dedichiamo una pagina all'argomento.
L'istruzione che serve all'uopo, molto semplice:

Workbooks.Open Filename:="percorso e nome file", ReadOnly:=False

dove in "percorso e nome file" dovrete indicare in sequenza: l'unit, la cartella (directory), eventuali
sottocartelle, nome del file completo di estensione, ed inserito come una stringa, tra doppi apici, ad
esempio: "C:\Documenti\Ufficio\Clienti.xls"
Come si nota, il percorso che mira al file inserito direttamente nell'istruzione e consente di aprire
sempre e soltanto quel file. Come fare allora quando vogliamo cambiare il file da aprire ?
Imposteremo una variabile che di volta in volta rappresenti il nome di un file, e richiameremo la
variabile nell'istruzione vista sopra.

Per assegnare il nome del file da aprire alla variabile, potremo usare vari sistemi, vediamone alcuni, i
pi semplici:
usare una cella del foglio di lavoro dove scrivere il SOLO nome (senza estensione, che sar gi
presente nell'istruzione, dato che vorremo aprire solo file .xls). In questo modo, cambiando il nome, si
aprir quel file.
usare una InputBox nella quale digitare il nome del file da aprire.
creare una tabella con i nomi dei file che ci interessa aprire, assegnare al ListFillRange di una
ComboBox i riferimenti alle celle che delimitano la tabella, ed assegnarle una cella di destinazione
(LinkedCell) che restituisce di volta in volta il nome selezionato nella ComboBox (sto riferendomi alla
ComboBox ActiveX presa NON da Moduli ma da Strumenti di controllo o Casella degli strumenti).
La LinkedCell sar assegnata alla variabile.
Vediamo gli esempi:

Sub apritisesamo()
Dim X As String
X = "C:\Documenti\" & Range("A1").Value & ".xls"
Workbooks.Open Filename:=X, ReadOnly:=False
End Sub

Commenti: dichiariamo la variabile X come stringa (testo), poi assegniamo alla X (tra doppi apici, rossi)
il percorso del file, dove il solo nome del file viene "preso" dal valore contenuto in una cella
(nell'esempio la A1) usando il concatenamento di stringa, cio doppio apice(" verde), spazio, e
commerciale(&), spazio, riferimento alla cella come valore, spazio, e commerciale (&), spazio, doppio
apice(" verde). A questo punto, dopo .Open FileName:= si scrive il nome della variabile X senza doppi
apici, in quanto X gi comprensiva di doppi apici. Questo esempio valido sia per il primo che per il
terzo punto sopra citati. Ora vediamo con l'InputBox :

Sub apritifile()
Dim X As String
nome = InputBox("Scrivi il nome del file da aprire")
If nome = "" Then Exit Sub

http://ennius.interfree.it/ Pagina 27
MANUALE VBA X EXCEL
X = "C:\Excelweb\" & nome & ".xls"
Workbooks.Open Filename:=X, ReadOnly:=False
End Sub

Commenti: in questo caso usiamo due variabili, la X di cui dichiariamo il Tipo, e "nome", che senza
dimensionamento viene assunta come variabile di tipo Variant, e che serve a reperire il nome del file
che scriveremo nella inputbox. Le altre cose che cambiano sono: l'aggiunta di una riga con la
condizione che se non scriviamo niente nella inputbox, si esca senza generare errori, e la
concatenazione della variabile "nome" al posto del riferimento ad una cella.

Queste istruzioni servono nel caso che i vari file a cui vogliamo accedere, siano tutti all'interno di una
stessa cartella. Se dovessimo aprire file che possono essere su cartelle diverse, dovremo creare una
variabile anche per il nome della cartella, con lo stesso sistema in modo da poter variare sia il nome
cartella sia il nome file, e quindi, con l'uso di due celle, per reperire nome cartella (A1) e nome file (B1),
diventa:

Sub apritisesamo2()
Dim X As String
X = "C:\" & Range("A1").Value & "\" & Range("B1").Value & ".xls"
Workbooks.Open Filename:=X, ReadOnly:=False
End Sub

o con le inputbox:

Sub apritifile2()
Dim X As String
cartella = InputBox("Scrivi il nome della cartella")
If cartella = "" Then Exit Sub
nome = InputBox("Scrivi il nome del file da aprire")

If nome = "" Then Exit Sub


X = "C:\" & cartella & "\" & nome & ".xls"
Workbooks.Open Filename:=X, ReadOnly:=False
End Sub

AGGIORNAMENTO 09/01/04

Ora vediamo invece come eseguire un controllo se un file .xls gi aperto : se aperto, lo attiviamo, in
caso contrario, lo apriremo. Usiamo quindi un ciclo For Each che controlli i nomi di tutte le cartelle Excel
(Workbook) in quel momento aperte. Per la ricerca useremo il solo Nome della cartella completo di
estensione, ma senza percorso. Se la certella aperta, anche se non attiva in quel momento, la
attiveremo ed usciremo dalla routine, viceversa useremo una delle istruzioni viste sopra per aprirla:

Sub CercaApri()
For Each wb In Workbooks
If wb.Name = "Nomecartella.xls" Then

http://ennius.interfree.it/ Pagina 28
MANUALE VBA X EXCEL
wb.Activate
Exit Sub
End If
Next
..e qui vanno le istruzioni per aprire il file se non gi aperto,
va bene anche questa:
Workbooks.Open Filename:="percorso e nome file completo di estensione",
ReadOnly:=False

End Sub

AGGIORNAMENTO 09/10/03
Quando si desideri, lavorando su un foglio, disporre di un comando per aprire contemporaneamente
pi cartelle di Excel contenute in una determinata Cartella dell'hard-disk (o Directory che dir si voglia),
possiamo usare la seguente routine messa a punto su una richiesta ricevuta. In questo esempio
sfruttiamo l' "oggetto" FileSearch (che restituisce il numero di file trovati e il nome di ciascuno di essi) e la
sua propriet LookIn per la ricerca di files all'interno di un percorso predefinito. La ricerca pu essere
fatta sia per nome di file, sia per estensione del file, che per solo una parte del nome, usando il
carattere Jolly asterisco ( * ). Per determinare il nome o il tipo del file (estensione) possiamo usare due
propriet del FileSearch:
la propriet FileName, alla quale assegneremo il nome o l'estensione del o dei files da cercare, es:
.FileName = "*.xls" e saranno cercati tutti ( * ) i file di Excel

.FileName = "Fat*.xls" e saranno cercati tutti i files Excel che iniziano per Fat ( * )
la propriet FileType, alla quale necessario assegnare una costante MsoFileType (vedi guida in linea,
digitando "FileType" e selezionando "Propriet FileType"), che per le cartelle di Excel la seguente.

.FileType =
msoFileTypeExcelWorkbooks

Sub ApriTutteCartelle()
Set fs = Application.FileSearch 'impostiamo con la variabile "fs" il
FileSearch
With fs 'con la variabile "fs"
.LookIn = "C:\Temp" 'indicare il percorso della cartella in cui
cercare
'.Filename = "*.xls" 'alternativa se si sceglie di usare FileName
.FileType = msoFileTypeExcelWorkbooks 'in questo esempio uso la
costante
If .Execute() > 0 Then 'se la ricerca dei file superiore al numero
zero
'si fornisce un messaggio con il numero dei files trovati nel percorso
scelto. Questa 'istruzione pu essere omessa, se non interessa.
MsgBox "Trovati " & .FoundFiles.Count & " file(s) xls."
'si inizia un ciclo For Next che a partire dal primo file trovato e
fino all'ultimo, (file contati 'con
.FoundFiles.Count)
For i = 1 To .FoundFiles.Count

http://ennius.interfree.it/ Pagina 29
MANUALE VBA X EXCEL
'si aprono di seguito tutte le cartelle trovate, usando
Workbooks.Open
Workbooks.Open .FoundFiles(i)
Next i
Else 'altrimenti si avvisa col messaggio che non ci sono i files
richiesti
MsgBox "Non ci sono file xls"
End If
End With
End Sub
E' evidente che in questa routine il percorso dove cercare i file un percorso fisso, inserito nelle
istruzioni. Se si volesse decidere di volta in volta la cartella dove "pescare" i files .xls, basta rendere
variabile il percorso assegnato al .FileName usando uno degli esempi presenti su questa pagina.

http://ennius.interfree.it/ Pagina 30
MANUALE VBA X EXCEL
Calcolare Valori nelle celle
Uno dei vantaggi del vba quello di poter usare delle istruzioni per modificare, ricalcolandolo, un
valore presente in una cella ottenendo nella cella stessa il nuovo valore. Classico esempio quello di
volere applicare un aumento ai prezzi di un listino, ma potrebbe trattarsi di altre necessit, come voler
dividere per un certo valore, i valori contenuti in una tabella, e presenti in una o pi colonne.
L'importante NON applicare le modifiche a celle contenenti formule, pena la perdita delle stesse, e
comunque non avrebbe senso in quanto il valore ottenuto in una cella per effetto di una formula ivi
residente, sempre influenzato dai valori delle celle richiamate nella formula stessa: basta cambiare
quei valori.
Vediamo come procedere, seguendo l'esempio dell'aumento di un listino:
Identificare l'area su cui vogliamo effettuare il ricalcolo.
L'area possiamo definirla in vari modi:
Usare i riferimenti precisi dell'area : Set zona = ActiveSheet.Range("A1:A500")
Usare il riferimento a tutta una colonna: Set zona = ActiveSheet.Range("A:A")
Usare il riferimento alla cella iniziale della Colonna (A nell'esempio) e alla cella finale (con End)
dell'area : Set zona = Range(Cells(1, 1), Cells.End(xlDown))
Usare il riferimento a tutta l'area che contiene dati sfruttando la propriet UsedRange del foglio di
lavoro : Set zona = ActiveSheet.UsedRange

Ognuno sceglier la forma pi appropriata, tenendo presente che scegliere il riferimento a tutta la
colonna comporta il fatto che verranno calcolate tutte le celle della colonna, compreso le celle
vuote, ottenendo in questo caso un rallentamento (sono 65536 righe) e lo zero come risultato in quelle
vuote. In questo caso baster usare un istruzione ("Se la cella vuota passa alla successiva..").
Vediamo gli esempi secondo l'ordine su esposto:

Sub multi1()
Dim cella As Range
Set zona = ActiveSheet.Range("A1:A500")
For Each cella In zona
cella = cella + ((cella * 10) / 100)
Next
End Sub

Sub multi2()
Dim cella As Range
Set zona = ActiveSheet.Range("A:A")
For Each cella In zona
cella = cella + ((cella * 10) / 100)
Next
End Sub

ora l'esempio sopra ma con l'esclusione delle celle vuote:

Sub multi2i()
Dim cella As Range
Set zona = ActiveSheet.Range("A:A")
For Each cella In zona

http://ennius.interfree.it/ Pagina 31
MANUALE VBA X EXCEL
If cella.Value = "" Then GoTo 10
cella = cella + ((cella * 10) / 100)
10:
Next
End Sub

Sub multi3()
Dim cella As Range
Set zona = Range(Cells(1, 1), Cells.End(xlDown))
For Each cella In zona
cella = cella + ((cella * 10) / 100)
Next
End Sub

Sub multi4()
Dim cella As Range
Set zona = ActiveSheet.UsedRange
For Each cella In zona
cella = cella + ((cella * 10) / 100)
Next
End Sub
Come vedete, le istruzioni cambiano solo nel metodo di identificazione dell'area. Se invece si volesse
modificare il tipo di calcolo da eseguire, baster modificare l'istruzione della riga dove si esegue il
calcolo sul valore della "cella".
Alcuni esempi:
cella = cella - ((cella * 10) / 100) - per sottrarre una percentuale (10 nell'esempio)
cella = cella / 100 - per dividere per 100 (o un'altro valore) il valore della cella
cella = cella + ((cella * Range("H1").Value) / 100) - per calcolare un incremento in percentuale con il
valore rappresentato da ci che inseriremo in una cella esterna (H1). Potremo quindi rendere variabile
la percentuale.
cella = cella / Range("H1").Value - per dividere il valore di una cella per un valore rappresentato da
ci che inseriremo in una cella esterna (H1). Potremo quindi rendere variabile il divisore.

I tipi di calcoli applicabili sono lasciati al libero arbitrio, inutile esemplificarli tutti.

http://ennius.interfree.it/ Pagina 32
MANUALE VBA X EXCEL
Calcolo date in VBA
Abbiamo gi detto che in Excel esistono due modi per poter lavorare : inserendo formule e funzioni
direttamente nelle celle del foglio di lavoro, oppure attraverso l'inserimento di opportune istruzioni
sfruttando il codice, il VBA, usando l'Editor di Visual Basic. Parlando di date, necessario vedere le
differenze tra i due modi di operare.
Premesso che Excel pone come inizio calendario la data del 01/01/1900, e che vede una data inserita
in una cella come UN NUMERO che rappresenta la differenza DEI GIORNI tra la data immessa e l'inizio
calendario, parlando di gestione date, necessario capire che esistono due modi di interpretazione
delle date in Excel:
Excel considera come primo giorno la data 01/01/1900
il VBA invece parte dal 30/12/1899
In questa sezione ci occuperemo delle date viste dal VBA, va precisato comunque che in
programmazione, la conversione tra i due sistemi non impegna il programmatore: se si inserisce tramite
una textbox (in una UserForm) una variabile di tipo "Date" nella cella del foglio di lavoro, la data che ivi
apparir sar quella giusta.
Per memorizzare una data o un orario, e necessario definire una variabile di tipo Date e ricorrere per
assegnare un valore alla variabile, ad una sintassi particolare che prevede di inserire la data tra due
caratteri "cancelletto" (#): per esempio, il 10 agosto 2002, pu essere scritto:

Private Sub CommandButton1_Click()


Dim Mydate As Date
Mydate = #08/10/2002# 'Mese/Giorno/Anno
TextBox1 = Mydate
WorkSheets(1).Range("A1") = TextBox1
End Sub

Come si pu notare il formato prevede l'inserimento della data alla maniera inglese, invertito rispetto
alla maniera italiana, cio Mese/Giorno/Anno, questo perch, lo ripeto, le istruzioni in codice vba
devono essere compilate in inglese. Ci penser lo stesso VisualBasic a convertire immediatamente nel
formato standard, per cui nella TextBox1 noi vedremmo la data scritta all'italiana : 10/08/2002 e lo
stesso nella cella A1 del foglio di lavoro. (la visualizzazione del formato data con anno a 4 cifre,
dipende dalle impostazioni di settaggio contenute in "Pannello di Controllo/Impostazioni
Internazionali/Data, voce:"Formato data breve": se impostato gg/MM/aa tutte le visualizzazioni delle
date saranno con l'anno a due cifre (le ultime due), se impostato gg/MM/aaaa invece l'anno sar
visualizzato a quattro cifre. Questo come visualizzazione standard in tutti i programmi; le celle di un
foglio di Excel consentono di scegliere il formato data voluto, indipendentemente dalle impostazioni di
sistema. Gli ultimi S.O. sono normalmente settati con anno a quattro cifre).
Vorrei richiamare l'attenzione su un particolare: nell'esempio sopra, la parola "Date" stata usata per
definire il tipo di variabile (Dim Mydate una Data), ma la parola "Date" anche una Funzione e
un'istruzione, e pu essere usata per definire la data di sistema (data del giorno in cui si lavora).
Vediamo l'esempio sopra modificato in questo senso:

Private Sub CommandButton1_Click()


TextBox1 = Date
WorkSheets(1).Range("A1") = TextBox1
End Sub

E nella textbox1 e in A1 vedremmo la data del giorno nel formato italiano. Questa istruzione ci
consente di evitare di scrivere la data in tutte le occasioni in cui la registrazione di una data
corrisponde alla data del giorno. (nel vba l'istruzione Date equivale alla Funzione =OGGI() inserita in
una cella del foglio di lavoro).

http://ennius.interfree.it/ Pagina 33
MANUALE VBA X EXCEL
Ritornando al primo esempio (usato per definire la sintassi del formato data), notiamo che l'istruzione
non ci consente di gestire liberamente l'inserimento di una data, in quanto la data fissata via codice;
(questo andrebbe bene se dovessimo inserire sempre una stessa data, e avremmo potuto fare a meno
della textbox1, bastava infatti scrivere : WorkSheets(1).Range("A1") = Mydate ), come fare allora per far
capire che stiamo inserendo una data e al tempo stesso usare la textbox per inserire date a nostro
piacere? Possiamo usare usare due metodi : il primo sar quello di assegnare una variabile di tipo Date
alla textbox interessata, il secondo di impostare la formattazione della textbox in "formato data
(Format)" prima della scrittura sul foglio di lavoro. Vediamo i due metodi:
primo metodo:

Private Sub CommandButton1_Click()


Dim Mydate As Date
Mydate = TextBox1
WorkSheets(1).Range("A1") = Mydate
End Sub

Con l'istruzione sopra otterremo il riconoscimento da parte di Excel della data come tale, e verr
rispettato anche l'eventuale formato cella preimpostato: abbiamo scelto per A1 il formato cella :
categoria Data, e come tipo : Data 14 marzo 2001 (cio con la data scritta col nome del mese e
l'anno a 4 cifre), avremmo questo risultato anche se nella textbox abbiamo scritto la data usando il
formato classico:

Non solo, ma l'istruzione precedente passa la data (immessa nella textbox1) ad Excel COME DATA, ed
Excel l'avrebbe riconosciuta come tale, anche se avessimo lasciato la cella A1 con il formato cella
impostato a "Generale", che il Formato cella di default di tutte le celle. Sarebbe solo stata scritta con
il formato data tradizionale, cio 15/10/02, MA, sottolineo, come DATA, e non come diversamente
potrebbe avvenire, come TESTO; visivamente avremmo visto lo stesso in A1 scritto 15/10/02, ma a
sinistra nella cella (come un testo) e cosa pi importante, sarebbero sorti problemi se avessimo utilizzato
il dato contenuto in A1 per conteggi su date. Definirei l'istruzione sopra, come l'istruzione TIPO da usare
quando si usino textbox per trasferire DATE al foglio di lavoro. Se poi vorremo un tipo di Formato data
personalizzato, lo IMPOSTEREMO non via codice (Format), ma come Formato cella. Nel caso si avesse
pi di una textbox dove si immettono date e si user un unico comando per trasferire le date sul foglio
di lavoro, sar sufficiente dimensionare la variabile una volta sola (Dim), assegnandogli pi variabili
(X,Y,Z), ,una per ogni textbox usata. Vediamo un esempio:

Private Sub CommandButton1_Click()


Dim X, Y, Z As Date
X = TextBox1
Y = TextBox2

http://ennius.interfree.it/ Pagina 34
MANUALE VBA X EXCEL
Z = TextBox3
WorkSheets(1).Range("A1") = X
WorkSheets(1).Range("A2") = Y
WorkSheets(1).Range("A3") = Z
End Sub

secondo metodo:
Introduciamo esempi in cui si fa uso della Funzione "Format". E' infatti possibile definire il Formato di date
personalizzato utilizzando la parola Format e, tra parentesi, il valore da formattare (textbox1), seguito
dal tipo di formato dati inserito tra doppi apici. Vista la molteplicit dei formati, riporto di seguito una
tabella completa e loro significato:

Carattere Descrizione
Separatore di ora. In alcune impostazioni internazionali, possono
essere utilizzati come separatori di ora altri caratteri. Il separatore
di ora separa ore, minuti e secondi quando vengono formattati i
(:)
valori di ora. Il carattere effettivo utilizzato come separatore di
ora nell'output formattato determinato dalle impostazioni del
sistema in uso.
Separatore di data. In alcune impostazioni internazionali
possono essere utilizzati come separatori di data altri caratteri. Il
separatore di data separa giorno, mese e anno quando
(/)
vengono formattati i valori di data. Il carattere effettivo utilizzato
come separatore di data nell'output formattato determinato
dalle impostazioni del sistema in uso.
Visualizza la data come ddddd e l'ora come ttttt, nell'ordine.
Visualizza solo informazioni relative alla data se nel numero
c seriale della data non presente una parte frazionaria; visualizza
solo le informazioni relative all'ora se non presente alcuna
parte intera.
d Visualizza il giorno come numero senza zero iniziale (1 31).
dd Visualizza il giorno come numero con zero iniziale (01 31).
ddd Visualizza il giorno abbreviato (dom sab).
dddd Visualizza il giorno per esteso (domenica sabato).
Visualizza una data completa (comprendente giorno, mese e
anno), formattata in base alle impostazioni relative al formato di
ddddd
data breve del sistema in uso. Il formato di data breve
predefinito d/m/yy.
Visualizza il numero seriale di una data come data completa
(comprendente giorno, mese e anno), formattata in base alle
dddddd
impostazioni relative alla data estesa del sistema in uso. Il
formato di data estesa predefinito dd mmmm, yyyy.
Equivale a dddd, ma corrisponde alla versione localizzata della
aaaa
stringa.
Visualizza il giorno della settimana come numero (1 per
w
domenica-7 per sabato).
ww Visualizza la settimana di un anno come numero (1 54).
Visualizza il mese come numero senza zero iniziale (1 12). Se m
m segue immediatamente h o hh, viene visualizzato il valore
relativo ai minuti anzich il mese.
Visualizza il mese come numero con zero iniziale (01 12). Se m
mm segue immediatamente h o hh, viene visualizzato il valore
relativo ai minuti anzich il mese.
mmm Visualizza il mese abbreviato (gen dic).
mmmm Visualizza il mese con il relativo nome per esteso (gennaio
http://ennius.interfree.it/ Pagina 35
MANUALE VBA X EXCEL
dicembre).
q Visualizza il trimestre dell'anno come numero (1 4).
y Visualizza il giorno dell'anno come numero (1 366).
yy Visualizza l'anno come numero di due cifre (00 99).
yyyy Visualizza l'anno come numero di quattro cifre (100 9999).
h Visualizza l'ora come numero senza zero iniziale (0 23).
Hh Visualizza l'ora come numero con zero iniziale (00 23).
N Visualizza i minuti come numero senza zero iniziale (0 59).
Nn Visualizza i minuti come numero con zero iniziale (00 59).
S Visualizza i secondi come numero senza zero iniziale (0 59).
Ss Visualizza i secondi come numero con zero iniziale (00 59).
Visualizza un'ora come ora completa, ovvero vengono indicati
l'ora, i minuti e i secondi, formattata con il separatore di ora
definito dal formato di ora impostato nel sistema in uso. Viene
ttttt
visualizzato uno zero iniziale se selezionata l'opzione Zero
iniziale e l'ora antecedente alle 10.00. Il formato di ora
predefinito h:mm:ss.
Utilizza il formato 12 ore e visualizza AM in maiuscolo accanto
AM/PM alle ore precedenti mezzogiorno e PM in maiuscolo accanto alle
ore comprese fra mezzogiorno e le 23.59.
Utilizza il formato 12 ore e visualizza am in minuscolo accanto alle
am/pm ore precedenti mezzogiorno e pm in minuscolo accanto alle ore
comprese fra mezzogiorno e le 23.59.
Utilizza il formato 12 ore e visualizza una A maiuscola accanto
A/P alle ore precedenti mezzogiorno e una P maiuscola accanto
alle ore comprese fra mezzogiorno e le 23.59.
Utilizza il formato 12 ore e visualizza una a minuscola accanto
a/p alle ore precedenti mezzogiorno e una p minuscola accanto
alle ore comprese fra mezzogiorno e le 23.59.
Utilizza il formato 12 ore e visualizza la stringa di caratteri AM
definita dal sistema in uso accanto alle ore precedenti
mezzogiorno e la stringa di caratteri PM definita dal sistema in
uso accanto alle ore comprese fra mezzogiorno e le 23.59. AM e
AMPM
PM possono essere sia in maiuscolo che in minuscolo, tuttavia le
maiuscole e minuscole della stringa visualizzata vengono
adeguate alla stringa definita dalle impostazioni del sistema in
uso. Il formato predefinito AM/PM.

Formati predefiniti di data e ora (come Funzione Format)


Visualizza una data e/o un'ora. Per i numeri reali visualizza
una data e un'ora (ad esempio 3/4/93 17.34); se la parte
frazionaria non presente visualizza solo una data (ad
General Date esempio 3/4/93); se la parte intera non presente
visualizza solo l'ora (ad esempio 17.34). La visualizzazione
della data determinata dalle impostazioni del sistema in
uso.
Visualizza una data in base al formato di data estesa del
Long Date
sistema in uso.
Visualizza una data utilizzando il formato di data breve
adeguato della versione dell'applicazione host.(Qualsiasi
Medium Date applicazione che supporta l'utilizzo di Visual Basic,
Applications Edition. Ad esempio, Microsoft Excel,
Microsoft Project e cos via.)
Visualizza una data utilizzando il formato di data breve del
Short Date
sistema in uso.
Long Time Visualizza un'ora utilizzando il formato di ora estesa del

http://ennius.interfree.it/ Pagina 36
MANUALE VBA X EXCEL
sistema in uso. Include le ore, i minuti e i secondi.
Visualizza l'ora nel formato breve di 12 ore, indicando le
Medium Time
ore, i minuti e l'identificatore AM/PM.
Visualizza l'ora utilizzando il formato di 24 ore (ad esempio
Short Time
17.45).

gli esempi :

Private Sub CommandButton1_Click()


TextBox1 = Format(TextBox1, "mm/dd/yy")
WorkSheets(1).Range("A1") = TextBox1
End Sub
va bene anche :
Private Sub CommandButton1_Click()
X = Format(TextBox1, "dd/mmm/yy")
WorkSheets(1).Range("A1") = X
End Sub
Con le due istruzioni sotto, se si dichiara una variabile (X) come Date e gli si assegna un Formato, il
Formato NON viene considerato e passa solo il formato Date della variabile che quello classico
12/03/02, a meno che non si sia predisposto il Formato cella diversamente.

Private Sub CommandButton1_Click()


Dim X As Date
X = Format(TextBox1, "dd/mmm/yy")
WorkSheets(1).Range("A1") = X
End Sub

Oppure

Private Sub CommandButton1_Click()


Dim X As Date
X = Format(TextBox1, "General Date")
WorkSheets(1).Range("A1") = X
End Sub
Dal momento che si comincia a fare confusione, e non credo per colpa mia, ho riassunto nella tabella
sotto i risultati che si ottengo usando sia l'istruzione che ho definito TIPO (con dimensionamento come
Date), sia l'istruzione Format (senza dimensionamento come Date) e proveremo a trarre delle
conclusioni. Nella colonna A ci sono i risultati delle date scritte nella textbox1, sempre scritti col formato
classico: 12/02/02 ecc., nella colonna B, se stata usata la Variabile Date o la formattazione e di che
tipo, nella colonna C si trova il "formato cella" impostato in A, e nella colonna D , dove stato
impostato il formato cella a Data, il tipo di formato data. Nella colonna A le date riconosciute da excel
come data, sono scritte a destra nella cella, le altre scritte sulla sinistra, vengono impostate come TESTO
(senza triangolino verde in alto a sinistra nella cella) e dove appare il triangolino, Excel rileva che
necessaria una precisazione: confermare un formato data, considerarlo errore, ignorare e lo considera
testo. La colonna C, dove si legge "generale > data", vuol dire che il formato cella, prima
dell'inserimento della data, era impostato a "generale", dopo l'inserimento viene aggiornato da excel il
formato cella in "data" e quindi si desume che la formattazione via codice stata riconosciuta giusta.

http://ennius.interfree.it/ Pagina 37
MANUALE VBA X EXCEL

Non mi sono dilungato a proporre tutti i formati, per non diventare scemo. Chi vuole si far tutte le
prove che vorr. Questa una panoramica su uno degli aspetti di Excel che giudico molto
confusionari, ma tant'.
Rimane ancora una cosa da vedere : fino ad ora abbiamo visto come impostare il codice per il
trasferimento di una data dalla textbox al foglio di lavoro, ma cosa dobbiamo fare se vogliamo che
anche la data inserita nella textbox assuma il formato voluto? Dovremo usare l'istruzione Format
inserita in un evento della textbox. Non possibile ottenere una formattazione durante la digitazione, e
gli unici eventi utilizzabili sono l'evento AfterUpdate oppure l'evento Exit (simile a LostFocus del Vb).
Ecco due esempi:

Private Sub TextBox1_AfterUpdate()


TextBox1 = Format(TextBox1, "dd-mm-yy")
End Sub

Private Sub TextBox1_Exit(ByVal Cancel As MSForms.ReturnBoolean)


TextBox1 = Format(TextBox1, "dd-mmmm-yy")
End Sub

Entrambi gli eventi si verificano quando si toglie il focus dalla textbox1: o spostandoci su un'altra
textbox, oppure nell'istante in cui si preme sul commandbutton. ATTENZIONE!! Questo tipo di
formattazione serve solo per la visualizzazione della data nella textbox, per cui NON bisogna usare il
sistema inglese (Mese/Giorno/Anno), ma il nostro sistema (Giorno/Mese/Anno). Esiste un altro evento
che potremo per utilizzare SOLO se usiamo una textbox per mostrarci delle date presenti in una cella :
l'evento Change della textbox, quindi useremo un'istruzione per caricare la textbox con il contenuto
della cella A1, usando l'evento Activate della UserForm,

Private Sub UserForm_Activate()


TextBox1 = Worksheets(1).Range("A1").Value
End Sub
e nell'evento Change della textbox1 metteremo l'istruzione per visualizzare la data nel formato che
avremo scelto e che pu essere diverso dal formato data presente in A1:

Private Sub TextBox1_Change()

http://ennius.interfree.it/ Pagina 38
MANUALE VBA X EXCEL
TextBox1 = Format(TextBox1, "dd-mmmm-yy")
End Sub

Volendo evitare di scrivere due istruzioni, potremo saltare l'evento Change e usare la formattazione
nell'evento Activate dell'UserForm, cos:

Private Sub UserForm_Activate()


TextBox1 = Worksheets(1).Range("A1").Value
TextBox1 = Format(TextBox1, "dd-mmmm-yy")
End Sub

ComboBox e le date
Ancora una precisazione: Quando si lavora usando delle ComboBox prese da "Strumenti di Controllo"
(o casella degli strumenti), essendo oggetti che fanno parte delle ActiveX e quindi tipici del VisualBasic
piuttosto che di Excel, necessario provvedere alla "formattazione" dei dati che ricevono dal foglio di
lavoro. Trattando di date, una ComboBox il cui ListFillRange va a "pescare" dati in una colonna di date,
mostrer nel men a tendina, le date cos come sono scritte nelle celle del foglio di lavoro, MA, nel
momento in cui selezioniamo una di queste date per averla nella cella collegata (LinkedCell), le date
presenti nel men si trasformano in numeri : sono i numeri seriali con i quali excel "vede" le date, anche
se sul foglio noi vediamo le date scritte con il giusto formato, e come tali le passa alla combobox. Per
ovviare a questo comportamento, sono necessarie delle istruzioni che consentano il mantenimento del
formato data scelto nelle celle, e, evitando di collegare la propriet LinkedCell della combobox a
nessuna cella, usare a suo posto una riga di istruzione. Nell'esempio sotto vediamo il costrutto :
sfruttiamo l'evento Change della combobox in modo che ad ogni selezione di una data presente nel
men della stessa, si attivi l'esecuzione del codice: prima impostiamo la formattazione della data nel
formato 5-feb-02 (d-mmm-yy)(scritto col formato italiano ma usando i termini inglesi), poi dichiariamo la
variabile mydate di tipo Date, poi assegniamo la variabile alla combobox, indi gli diciamo quale cella
del foglio di lavoro dovr essere collegata (LinkedCell) al dato selezionato nella combobox. Le celle
del foglio di lavoro interessate alle date dovranno avere il formato cella impostato uguale al formato
scelto per formattare la combobox (personalizzato : g-mmm-aa)(sul foglio di lavoro i termini sono solo
in italiano) :

Private Sub ComboBox1_Change()


ComboBox1 = Format(ComboBox1, "d-mmm-yy")
Dim mydate As Date
mydate = ComboBox1
Range("G5") = mydate 'G5 la cella che va a sostituire la propriet
LinkedCell della combobox
End Sub

Per la trattazione degli orari, previsto un nuovo paragrafo che seguir questo.

http://ennius.interfree.it/ Pagina 39
MANUALE VBA X EXCEL
Calcolo con le date in VBA 2
Nel paragrafo precedente abbiamo avuto un primo "assaggio" di cosa sono le date per il VBA. Ora
vediamo su come poter lavorare con le date, faremo esempi che ci aiuteranno nel Calcolo su date.
Vediamo il primo, un divertente esempio in cui, sfruttando due inputbox, chiederemo di introdurre dei
dati e forniremo risposte ai quesiti posti (in verde sono i commenti che andranno tolti):

Private Sub CommandButton2_Click()


Dim Message, Title
Message = "Inserisci la tua data di nascita :"
'Imposta il testo del messaggio.
Title = "Giorni Vissuti" ' Imposta il titolo.
Dim natoil As Date
Dim giorni, anno As Integer
natoil = InputBox(Message, Title)
giorni = Date - natoil
viene calcolata la diff. tra la data del giorno e quella immessa
nell'inputbox (natoil) e 'viene restituito un valore che il Numero
seriale dei giorni che intercorrono tra le due date e memorizzato
'nella. variabile giorni
MsgBox "hai vissuto per " & giorni & " giorni!"
'appare il messaggio che dice quanti giorni sono trascorsi
anno = giorni / 365
'poi trasformiamo il Numero di giorni diviso 365 per ottenere a quanti
anni corrispondono
MsgBox "e oggi hai " & anno & " anni!"
End Sub

e questo il risultato (Date = 21/09/02):

Un esempio un p pi articolato e quello che presento sotto. Ho sfruttato una UserForm per mostrare
due tipi di calcolo con date :
ottenere la differenza tra due date, per poter eseguire calcoli sul risultato della differenza (in giorni,
settimane, mesi o anni) moltiplicato per un costo unitario, e ottenere un totale.
ottenere una data finale aggiungendo un periodo (giorni, settimane, mesi o anni) ad una data iniziale.

http://ennius.interfree.it/ Pagina 40
MANUALE VBA X EXCEL

Le funzioni su cui si basano i calcoli sulle date sono : DateDiff e DateAdd. Funzione DateDiff
Restituisce un valore Variant (Long) corrispondente al numero di intervalli di tempo tra due date
specificate. Sintassi :
DateDiff(interval, date1, date2[, firstdayofweek[, firstweekofyear]])

interval Obbligatoria. Espressione stringa corrispondente all'intervallo di tempo


utilizzato per calcolare la differenza tra date1 e date2. (vedi sotto interval)
date1, date2 Obbligatoria. Variant (Date). Date da utilizzare nel calcolo.
firstdayofweek Facoltativa. Costante che specifica il primo giorno della settimana. Se non
specificata, verr utilizzata Domenica.
firstweekofyear Facoltativa. Costante che specifica la prima settimana dell'anno. Se non
specificata, verr utilizzata la settimana nella quale cade il 1 gennaio.

Le possibili impostazioni dellargomento interval sono:

Impostazione Descrizione
yyyy Anno
q Trimestre
m Mese
y Giorno dellanno
d Giorno
w Giorno della settimana
ww Settimana
h Ora
n Minuti
s Secondi
Osservazioni :

http://ennius.interfree.it/ Pagina 41
MANUALE VBA X EXCEL
possibile utilizzare la funzione DateDiff per determinare quanti intervalli di tempo specificati esistono
tra due date. , ad esempio, possibile utilizzare DateDiff per calcolare il numero di giorni che
intercorrono tra due date oppure il numero di settimane tra la data odierna e la fine dell'anno.

Per ottenere il numero di giorni tra date1 e date2 possibile utilizzare sia l'impostazione del giorno
dell'anno ("y") che quella del giorno ("d"). Quando per interval viene impostato il giorno della settimana
("w"), DateDiff restituisce il numero di settimane che intercorrono tra le due date. Se date1 cade di
luned, DateDiff conter il numero di luned fino a date2, includendo nel conteggio date2 ma non
date1. Se per interval viene invece impostata la settimana ("ww"), la funzione DateDiff restituir il
numero di settimane del calendario comprese tra le due date. La funzione conter il numero di
domeniche che intercorrono tra date1 e date2, includendo nel conteggio date2 se cade di
domenica, ma non date1, anche se cade di domenica.

Se date1 successiva a date2, la funzione DateDiff restituir un numero negativo.


Quando si esegue il confronto tra il 31 dicembre e l'1 gennaio dell'anno immediatamente successivo,
DateDiff utilizzata con l'impostazione dell'anno ("yyyy") restituisce 1 anche se trascorso un solo giorno.

Funzione DateAdd Restituisce un valore Variant (Date) contenente una data alla quale stato
aggiunto un intervallo di tempo specificato.
Sintassi
DateAdd(interval, number, date)

interval Obbligatoria. Espressione stringa corrispondente all'intervallo di tempo che si desidera


aggiungere.(vedi sotto)

number Obbligatoria. Espressione numerica corrispondente al numero di intervalli da


aggiungere. Pu essere positiva, per ottenere date future, oppure negativa, per
ottenere date passate.

date Obbligatoria. Valore Variant (Date) o stringa che rappresenta una data a cui viene
aggiunto l'intervallo.

Le possibili impostazioni dellargomento interval sono:

Impostazione Descrizione
yyyy Anno
q Trimestre
m Mese
y Giorno dellanno
d Giorno
w Giorno della settimana
ww Settimana
h Ora
n Minuti
s Secondi

Osservazioni :

http://ennius.interfree.it/ Pagina 42
MANUALE VBA X EXCEL
La funzione DateAdd consente di aggiungere o sottrarre da una data un intervallo di tempo
specificato. , ad esempio, possibile utilizzare DateAdd per determinare la data risultante dall'aggiunta
di 30 giorni alla data odierna oppure l'orario risultante dall'aggiunta di 45 minuti all'ora corrente.
Per aggiungere giorni a date, possibile utilizzare l'impostazione per il giorno dell'anno ("y"), per il giorno
("d") o per il giorno della settimana ("w").
La funzione DateAdd non restituisce una data non valida. In questo esempio, alla data 31 gennaio
viene aggiunto un mese:
DateAdd("m", 1, "31/01/95")
In questo caso, DateAdd restituir 28/02/95 e non 31/02/95. Se date 31/01/96, la funzione restituir
29/02/96, in quanto il 1996 un anno bisestile.
Se la data calcolata precede l'anno 100, vale a dire se si sottrae un numero di anni maggiore di quello
presente in date, verr generato un errore.
Se number non un valore Long, prima di essere valutato verr arrotondato al numero intero pi
vicino.
Nota Il formato del valore restituito dalla funzione DateAdd dipende dalle impostazioni del Pannello di
controllo e non dal formato passato dall'argomento date.

Nella form ho cercato di inserire anche alcuni passaggi che dovrebbero servire a familiarizzarsi con altri
"oggetti" inseribili nelle form, come i "pulsanti di opzione" (OptionButton) che possono servire in molte
altre occasioni per creare condizioni diverse all'esecuzione: in questo caso sono state abbinate alla
scelta tra lavorare con date immesse dall'utente (inizio - fine) oppure usare la data di sistema (giorno
attuale) come data iniziale, inserendo solo la data finale per ottenere una differenza futuribile su cui
eseguire calcoli. La data di sistema l'ho abbinata solo a calcoli sulle differenze. Chi volesse usare
questo metodo con le aggiunte periodi, potr, leggendo come sono impostate le istruzioni in
"differenza", modificare il codice. Desidero sottolineare che lo scopo di questo lavoro quello di fornire
indicazioni di massima su come operare, sar compito di chi interessato assimilare i concetti ed
adattarli alle proprie esigenze. Ho inserito dei semplici controlli per la verifica della presenza dei dati
nelle textbox, in modo che se ci si dimenticasse di inserire un dato, si venga fermati ed avvisati. Due dei
controlli inseriti possono avere una validit anche in altri tipi di applicazioni su userform:
controllo formato data: dovr essere scritto come 02/11/01, cio gg/mm/aa con le barre ( / ) e l'anno
a due cifre (per evitare errori di digitazione): in caso di errore la data viene cancellata e si viene
avvisati di quale sia il giusto formato, ed il focus si riposiziona sulla textbox con l'errore. (questo controllo
l'ho abbinato solo al primo pulsante "differenza in giorni" e controlla l'inserimento sulle textbox2 e 3.
Ovviamente ripetibile per tutti gli altri pulsanti.
controllo inserimento cifra con decimali e presenza della virgola di separazione dei decimali. Spesso
viene usato il punto ( . ) in maniera impropria. questo controllo provvede a garantire l'inserimento di
due soli decimali e della virgola; in caso contrario, si viene avvisati e la text box viene pulita. Questo
controllo abbinato solo al pulsante "calcola importo" e controlla l'inserimento sulla textbox5.
Riporto di seguito le istruzioni usate per i due controlli menzionati (gli altri sono leggibili scaricando il file)

'controllo inserimento formato data


If Mid(TextBox2, 3, 1) <> "/" Or Mid(TextBox2, 6, 1) <> "/" Then
MsgBox "Scrivi la data come: 02/10/01"
TextBox2 = ""
TextBox2.SetFocus
Exit Sub
End If
If Mid(TextBox3, 3, 1) <> "/" Or Mid(TextBox3, 6, 1) <> "/" Then
MsgBox "Scrivi la data come: 02/10/01"
TextBox3 = ""
TextBox3.SetFocus
Exit Sub
End If
http://ennius.interfree.it/ Pagina 43
MANUALE VBA X EXCEL
'fine controllo-----------
'controllo inserimento 2 decimali con virgola

Dim X
X = Right(TextBox5, 2)
If Right(TextBox5, 3) <> "," & X Then
MsgBox "Gli importi vanno scritti con la virgola e due decimali"
TextBox5 = ""
TextBox5.SetFocus
Exit Sub
End If
'fine controllo

Sono state usate due funzioni: Mid e Right di cui invito gli interessati a consultare la guida in linea per
capire il funzionamento. Chi comunque avesse problemi a capire, trover su questo sito, in futuro, una
spiegazione. Il file disponibile e scaricabile : Calcolo su date2000.zip 21 kb
Ma non ancora finita, ci risentiremo per completare l'argomento qui impostato e finire la
panoramica.

http://ennius.interfree.it/ Pagina 44
MANUALE VBA X EXCEL
Calcolo sulle date in VBA 3
Funzioni native per le date
Continuiamo la panoramica dei calcoli con le date, esaminando alcune delle funzioni native del VBA
che permettono di gestirle.
Date abbiamo gi visto nella pagina precedente l'impiego di questa parola; opportuno riprenderla
per sottolineare che viene utilizzata in contesti diversi con significati diversi :
come tipo di dato assegnato ad una variabile, e che quindi deputato a contenere date (o/e orari).
come funzione per restituire la data di sistema, o per interrogazioni sul calendario del computer
in questo esempio interroghiamo l'orologio interno e otteniamo il giorno della settimana in una finestra
di messaggio, che porta nella barra del titolo il testo contenuto nell'istruzione
Title:
Dim X As Date
X = Date
MsgBox Prompt:=Format(X, "dddd"), Title:="Giorno della settimana per la
data del " & X

Time questa funzione restituisce un valore di tipo Date con l'orario corrente; quest'esempio mostra una
finestra di messaggio con l'orario corrente:

Dim x As Date
x = Time
MsgBox Time

L'esempio per vedere il costrutto, perch in realt per avere una messagebox con l'ora di sistema
sarebbe sufficiente una semplice istruzione, cos:

MsgBox Time

TimeValue questa funzione restituisce un valore Variant (Date) contenente un orario. Utile quando si
voglia calcolare la differenza tra due orari. Questo esempio considera due celle, ad esempio la A1 e la
B1 con due orari immessi, formato celle impostato a Ora, e restituisce la differenza in C1.

Sub miaora()
Dim cc As Date
'si impostano due variabili ( cc e pp ) come tipo Date
Dim pp As Date
pp = Range("A1").Value
'poi si assegna a pp l'orario che si trova in A1
y = TimeValue(pp)
' con y si memorizza la variabile pp come TimeValue
cc = Range("B1").Value
'poi si assegna a cc l'orario che si trova in B1
z = TimeValue(cc)
' indi si memorizza con z la variabile cc come TimeValue
Range("C1") = z - y
'e si restituisce in C1 la differenza tra i due orari

http://ennius.interfree.it/ Pagina 45
MANUALE VBA X EXCEL
End Sub

Ricordo che tutto ci che riguarda date ed orari NON pu avere valore negativo, quindi dovremo
sempre sottrarre l'orario minore da quello superiore, e non viceversa. Inoltre le ore partono dalle 0.0.0 e
terminano alle 23.59.59. Se dobbiamo fare la differenza, per esempio tra le 17.30 e le 01.30, per
calcolare un turno di lavoro che inizia alle 5.30 del pomeriggio e termina alle 01.30 di notte, non
possiamo fare 01.30 - 15.20, perch le 01.30 appartengono al giorno dopo. Infatti una differenza come
l'esempio, viene vista come differenza tra le 5.30 del pomeriggio e le 01.30 di mattina, ma dello stesso
giorno, e quindi negativa, con manifesta irritazione di Excel che segnala una serie infinita di cancelletti
(#). Andr infatti sommata la differenza tra le 23.59.59 e le 17.30, e tra le 01.30 e le 0.0.0 per ottenere il
totale delle ore del turno.

TimeSerial questa funzione restituisce un valore Variant (Date) che contiene lorario corrispondente a
unora, minuto e secondo specifici. Utile quando si voglia restituire un orario per differenza non da
un'altro orario, ma da un certo numero di ore, minuti, secondi, da sottrarre ad un determinato numero
di ore. Esempio (banale): supponiamo di voler sapere che ore saranno togliendo 5 ore e 25 minuti alle
17. Per meglio capire, vediamo prima la sintassi della funzione:
TimeSerial(ora, minuti, secondi)

La sintassi della funzione TimeSerial composta dai seguenti argomenti predefiniti:

Parte Descrizione
Obbligatoria. Variant (Integer). Numero compreso tra 0 (12.00) e 23
Ora
(23.00) inclusi oppure un'espressione numerica.
Minuti Obbligatoria. Variant (Integer). Qualsiasi espressione numerica.
Secondi Obbligatoria. Variant (Integer). Qualsiasi espressione numerica.

E' necessario quindi fornire tutti e tre gli argomenti, (ore,minuti,secondi), separati da una virgola. Poich
la funzione consente di eseguire "direttamente" la differenza tra due valori ora, meno i minuti, meno i
secondi, un istruzione va compilata in questo modo:
TimeSerial(12 - 6, -15, 0)

12 l'ora da cui vogliamo sottrarre 6 ore e 15 minuti, ovvero la funzione TimeSerial restituisce un'ora che
corrisponde a sei ore (12 - 6) e a 15 minuti (0 - 15) prima di mezzogiorno, cio le 5.45.00
Per indicare un'ora specifica, quale 11.59.59, ciascun argomento della funzione TimeSerial dovr essere
rappresentato da un numero incluso nell'intervallo di valori validi per quell'argomento. I valori validi per
le ore vanno da 0 a 23, per i minuti e per i secondi da 0 a 59. Se un qualsiasi argomento non rientra
nell'intervallo valido specifico dell'argomento, verr incrementato all'unit superiore successiva in
modo appropriato. Se si specifica, ad esempio, 75 minuti, l'argomento "minuti" verr valutato come 1
ora e 15 minuti. Se si usasse un'ora + frazione di ora come 16,30 , verr valutato solo l'argomento "ora" e
non i minuti dopo la virgola.
Se volessimo fare un esempio su un foglio di lavoro, dovremmo vedere una situazione del genere:

C D E F G
1
2
3 16 4 20 0

dove in D3 abbiamo l'ora a cui vanno sottratte:


4 ore in E3
20 minuti in F3
0 secondi in G3
in C3 vorremo il valore restituito dalla funzione TimeSerial, che fornir questo risultato:

C D E F G
1
2
http://ennius.interfree.it/ Pagina 46
MANUALE VBA X EXCEL
3 11.40.00 AM 16 4 20 0

e ora vediamo la procedura della macro:

Sub Differenzaore()
Dim gg
'si dichiara la variabile gg
'ora si assegnano a tre variabili i valori contenuti nelle celle
x = Range("D3").Value
'con x si prende l'ora da cui sottrarre (16 o quel che vorrete)
y = Range("E3").Value
'con y si prende il numero di ore da sottrarre da x (4 o quel che
vorrete)
z = Range("F3").Value
'con z si prende il numero di minuti da sottrarre da x (20 o quel che
vorrete)
gg = TimeSerial(x - y, -z, 0)
'ora si restituisce a gg il valore ottenuto con TimeSerial, usando le
variabili a 'posto dei numeri. Per i secondi, visto che non ci
interessano, usiamo lo zero (0) direttamente in formula.
Range("C3") = gg
'poi si assegna a C3 il valore rappresentato da gg
End Sub

Attenzione: il formato delle celle da D a G 3 "generale", in C3 provveder il codice a formattare in


formato personalizzato h.mm.ss. AM/PM. Se vorrete, potrete preimpostare la cella di destinazioni in un
vostro formato preferito, esempio: personalizzato, h.mm.ss e la data sopra la vedreste 11.40.00
Capisco che siano argomenti un p ostici, ma tant', e consiglio quindi di munirsi di santa pazienza e
provare senza arrabbiarsi, per le proprie esigenze. E' sempre meglio comunque aiutarsi con la guida in
linea.

http://ennius.interfree.it/ Pagina 47
MANUALE VBA X EXCEL
Calendario perpetuo
Lavoro realizzato in collaborazione con Marco Nocciolini (marco.nocciolini@tin.it)
Questa applicazione stata realizzata sfruttando la funzione =DATA() (inserita nel Range F5:F35)
Sono state nascoste due colonne, la E e la H che riportano, la prima il riferimento alle due celle
richiamate nella funzione DATA e, dal Range E5 al E35, le celle con inserito il numero progressivo dei
giorni in un mese, la seconda, sempre nel Range H5:H35, la funzione =GIORNO.SETTIMANA() che
converte il dato (contenuto nella stessa riga ma nella colonna F) in un numero da 1 a sette e che sono
i corrispondenti di domenica, lunedi, martedi ecc. fino a sabato. Questo il numero che viene letto
dalla routine che provvede a evidenziare in rosso le celle che corrisponderanno a "domenica" (routine
che trovate in calce).
La colonna G (G5:G35) riporta una semplice uguaglianza alla stessa riga ma alla colonna F, solo che,
avendo in F una data espressa in formato data, in G vogliamo che di questa data venga riportato il
relativo giorno della settimana, ed sufficiente formattare le celle G5:G35 scegliendo:
"Numero/Personalizzato e scrivere "gggg" nella finestrina di immissione formato.
Per quanto riguarda le due combobox, la prima, che "pesca" gli Anni dalla colonna S ("S5:S105") stata
presa dalla "Casella degli Strumenti" ed ha nell'evento Change, la routine che provvede prima a
riportare le celle della colonna G (i giorni della settimana) ai colori iniziali, indi, trovato il giorno
"domenica", colora di rosso la cella e di bianco il font, in modo che ad ogni "cambio" di anno vengano
aggiornati i colori sui rispettivi giorni "domenica". La seconda, che deve fornire uno dei valori numerici
che servono alla funzione =DATA(), stata presa dalla finestra dei "moduli" che "pesca" i Mesi dalla
colonna P (P5:P16), che mostra nel men i nomi dei mesi, MA che restituisce non il mese selezionato ma
il suo indice di riga e quindi un valore numerico. A questa seconda combobox (che non un "oggetto"
e non possiede eventi) stata associata una macro con le stesse istruzioni dell'altra combobox. In
questo modo, cambiando l'anno o il mese, avremo sempre lo stesso effetto di evidenziazione della
"domenica". Sotto, la foto dell'applicazione e dopo la routine ed il file scaricabile.

Sub Macro1()
With Range("G5:G35")
.Interior.ColorIndex = Null
.Font.ColorIndex = 1
End With
Dim CL As Object

For Each CL In Range("h5:h35")


http://ennius.interfree.it/ Pagina 48
MANUALE VBA X EXCEL
If CL.Value = "1" Then

CL.Offset(0, -1).Font.ColorIndex = 2
CL.Offset(0, -1).Interior.ColorIndex = 3
End If
Next
End Sub

http://ennius.interfree.it/ Pagina 49
MANUALE VBA X EXCEL
Cambiare i Fonts sul foglio di lavoro.
Un indicazione per tutti coloro che intendono sostituire il font (carattere) in Celle o Range di celle sul
foglio di lavoro, usando codice VBA.
Il font predefinito di Excel l'Arial, ma come tutti sappiamo possibile modificare questa impostazione
selezionando nella finestra dei font il tipo e la dimensione del carattere, scegliendo tra i font installati sul
nostro computer.
E' possibile per utilizzare una macro, da associare ad un pulsante oppure sfruttando l'evento
Worksheet_Change del foglio di lavoro per modificare il o i font.
Come procedere: useremo una cella dove scriveremo il nome del font che ci interessa utilizzare
usando il suo nome esatto (che possiamo reperire nella su menzionata finestra), e poi usare queste
istruzioni:
supponendo di usare la cella A1 come vettore per il nome del font, affideremo il riferimento a questa
cella ad una variabile che chiameremo "X". Dovremo inoltre identificare la cella o le celle alle quali
applicare il font scelto, quindi vediamo il primo esempio, in cui la cella o le celle di destinazione del
font lasciata ad una selezione sulla quale agir l'istruzione

Sub MioFont()
Dim X
X = Range("A1").Value
'in A1 scriveremo il nome di un font
With Selection.Font
.Name = "" & X & ""
'assegnazione alla propriet Font.Name del nome scritto in A1
.Size = 16
'questa propriet determina la grandezza del font (di default 10)
.Strikethrough = False
.Superscript = False
.Subscript = False
.OutlineFont = False
.Shadow = False
.Underline = xlUnderlineStyleNone
.ColorIndex = xlAutomatic
End With
End Sub

secondo esempio con definizione di un range di celle sul quale agire:

Sub MioFont2()
Dim X
X = Range("A1").Value
With Range("A3:C5").Font
'range sul quale applicare il font scritto in A1
.Name = "" & X & ""
.Size = 14
.Strikethrough = False

http://ennius.interfree.it/ Pagina 50
MANUALE VBA X EXCEL
.Superscript = False
.Subscript = False
.OutlineFont = False
.Shadow = False
.Underline = xlUnderlineStyleNone
.ColorIndex = xlAutomatic
End With
End Sub

terzo esempio inserito nel Worksheet_Change, in questo modo la routine viene applicata sul Range
designato ad ogni cambio di valore in una cella, ma solo sulle celle del range :
Private Sub Worksheet_Change(ByVal Target As Range)
Dim X
X = Range("A1").Value
With Range("A3:C5").Font
.Name = "" & X & ""
.Size = 14
.Strikethrough = False
.Superscript = False
.Subscript = False
.OutlineFont = False
.Shadow = False
.Underline = xlUnderlineStyleNone
.ColorIndex = xlAutomatic
End With
End Sub

E' possibile ridurre le istruzioni delle propriet che non interessano, ottenendo comunque l'impostazione
con il font scelto, aggiungendo magari solo il "grassetto" (Bold), in questo esempio:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim X
X = Range("A1").Value
With Range("A13:C15").Font
.Name = "" & X & ""
.Size = 10
.Bold = True
'imposta il grassetto
End With
End Sub
Per i curiosi, possibile controllare il significato delle propriet (eliminate) usando la guida in linea.

http://ennius.interfree.it/ Pagina 51
MANUALE VBA X EXCEL
Caricare una ListBox
Un breve esercizio basato sul metodo AddItem per caricare i dati, anzich sfruttare la propriet
ListFillRange se la ListBox si trova sul foglio di lavoro, oppure RowSource se la ListBox su una UserForm.
Stiamo parlando di una ListBox ActiveX, presa quindi da "Strumenti di controllo" (o Casella degli
strumenti) anzich da Moduli.
In questo esempio ipotizziamo di voler reperire i dati non da una sola colonna, come di solito
facciamo, ma da un certo numero di colonne, tutte conseguenti, ma di cui non sappiamo n il
numero di colonne che contengono i dati che vogliamo caricare, n quante righe di dati saranno
presenti nelle singole colonne.
Si tratta quindi di una situazione che spesso si verifica, quella di non conoscere l'esatta dimensione
della zona contenente i dati, e allora vediamo come impostare le routine:
Useremo la propriet End per reperire, data una cella iniziale, sia l'ultima colonna occupata, sia l'ultima
riga occupata di ogni colonna. Per fare questo sar necessario che i dati siano su celle contigue,
senza celle vuote nel mezzo, altrimenti End si fermerebbe all'ultima cella occupata anche se i dati
continuassero su celle sottostanti. Lo stesso dicasi per le colonne.
Una volta reperita l'ultima Colonna occupata da dati, conteremo quante sono le colonne con
Columns.Count. Il numero cos ottenuto lo useremo come indice estremo in un ciclo For Next che
scorra le colonne, una alla volta, partendo dalla prima fino all'ultima rappresentata dal numero indice.
Lo stesso faremo, con un altro ciclo For Next interno al primo ciclo, per reperire quante sono le righe di
ogni colonna. Otteniamo quindi che avviata la macro, verranno contate le colonne, poi inizieremo
dalla prima e ne conteremo le righe, poi il ciclo passer alla seconda colonna e verranno contate le
righe di questa, e cos via fino all'ultima colonna.
Ad ogni scorrimento di cella, verr preso il dato (valore) ivi presente, assegnato ad una variabile, e
questa variabile restituir il valore alla ListBox che l'aggiunger nella lista.
vediamo allora le istruzioni, e nell'esempio useremo come cella iniziale del nostro elenco la cella A1:

Sub CaricaLista()
'con zonac impostiamo l'area che si trova dalla cella A1 fino
all'ultima colonna occupata, 'andando verso destra (End(xlToRight))
Set zonac = Range(Cells(1, 1), Cells(1, 1).End(xlToRight))
'con x memorizziamo in numero di quante colonne sono in zonac
x = zonac.Columns.Count
'prima di avviare i cicli che caricheranno i dati, puliamo la ListBox
ActiveSheet.ListBox1.Clear
'ora inizializiamo il primo ciclo che scorrer le colonne, partendo
dalla numero 1, 'assegnando alla variabile z il numero indice
For z = 1 To x
'ora impostiamo con zonar, andando verso il basso (End(xlDown)) l'area
che comprende 'le righe occupate da dati, e con la variabile y
memorizziamo il numero di queste righe
Set zonar = Range(Cells(1, z), Cells(1, z).End(xlDown))
y = zonar.Rows.Count
'ora iniziamo il secondo ciclo, che scorrer tutte le righe contate,
nella colonna il cui 'numero ora rappresentato da z, assegnando alla
variabile t il numero indice di riga, 'partendo dalla 1 e fino alla
numero y
For t = 1 To y
'ora memorizziamo con w il valore che verr trovato nella cella, riga
t, colonna z
w = Cells(t, z).Value

http://ennius.interfree.it/ Pagina 52
MANUALE VBA X EXCEL
'e carichiamo con AddItem questo valore (w) nella ListBox
ActiveSheet.ListBox1.AddItem w

Next
'con questo Next passiamo al secondo indice t (riga successiva), e
finito il ciclo alla
'riga y, passiamo al Next successivo che si occuper di scorrere nella
successiva colonna,
'ritornando al primo For (z) ripetendo poi il ciclo sulle righe della
nuova colonna.
Next

End Sub
Mi sembra che le spiegazioni siano chiare, e vediamo un'immagine che illustra l'esercizio

Ho evidenziato con le frecce rosse i valori presenti nelle ultime celle di ogni riga per mostrare come
avviene la sequenza di caricamento, progressiva per ogni colonna. Si vede altres che si possono
caricare indifferentemente sia testo, sia date, sia numeri.

http://ennius.interfree.it/ Pagina 53
MANUALE VBA X EXCEL
Cerca e seleziona
con evidenziazione, nell'area trovata, dei caratteri in rosso e in grassetto.
Questa volta l'esercizio proposto rientra in una casistica spesso richiestami: come evidenziare una zona
di dati compresa da due valori presenti in una tabella, ma di cui non conosciamo la posizione, sia dei
valori nella tabella, sia della tabella stessa. Supponiamo di avere quindi una tabella come quella sotto
(in cui per mia comodit ho inserito dei numeri con valore univoco. Attenzione: i valori devono essere
univoci, altrimenti le istruzioni qui usate non funzionano; con valori doppi o ripetuti dovremo usare altre
istruzioni, ma facciamo una cosa per volta, la routine per i valori doppi la trovate alla fine di questa
pagina).

Vediamo i singoli passaggi per capirli meglio, poi alla fine ricostruiamo l'intera sequenza.
identificare la posizione della tabella sul foglio di lavoro; per fare questo ci affideremo all' UsedRange,
(di cui esistono spiegazioni in questa sezione, paragrafo "Copia/Incolla 4") e assegneremo con
l'istruzione Set, un nome alla tabella (zona) dell'UsedRange nel foglio attivo:
Set zona = ActiveSheet.UsedRange
faccio presente che la propriet UsedRange rintraccia una tabella anche se non sono presenti valori,
ma purch le celle destinate a formare la tabella siano state "bordate".
Inserimento dell'istruzione che ripristina il colore del font a nero e toglie il grassetto ai font che
eventualmente fossero stati evidenziati; per fare questo useremo il costrutto With oggetto....End With, in
modo da poter con un'unica istruzione, modificare tutte le "propriet" volute, all'interno delle celle
comprese nell'UsedRange:

With zona
.Font.ColorIndex = 0
.Font.Bold = False
End With

inseriamo l'istruzione per chiamare una InputBox (finestra di dialogo) nella quale scriveremo il primo
valore da cercare tra i dati presenti nella tabella ( chiamata "zona" ). Il valore che scriveremo dovr
essere memorizzato e quindi dimensioniamo una variabile, la X, atta a contenere il dato immesso nella
InputBox. Nell'istruzione dovremo dichiarare, tra parentesi, il messaggio che la finestra di dialogo ci
mostrer ("dato uno" o qualunque altra frase che noi vorremo) e il titolo (che apparir nella barra della
InputBox: "inserisci il primo dato" ):

X = InputBox("dato uno", "inserisci il primo dato")

http://ennius.interfree.it/ Pagina 54
MANUALE VBA X EXCEL
per evitare che il debugger, in caso di mancanza di inserimento del dato nella inputbox, o per aver
premuto il pulsante "annulla", si "arrabbi" e ci segnali un errore, inseriremo una semplice istruzione : se il
valore rappresentato dalla X sar vuoto, usciremo dalla routine:
If X = "" Then Exit Sub
inizializiamo ora il ciclo di ricerca assegnando un nome ( CL, ma l'avremmo potuta chiamare "pippo",
sarebbe lo stesso ) ad una variabile, ed il "tipo" di variabile come "Object" (oggetto ) (Dim st per :
dimensioniamo).
Dim CL As Object
l'istruzione seguente dice : per ogni CL (l'oggetto cella) presente in "zona", se il valore presente nella
cella uguale al valore memorizzato nella X, allora assegnamo alla variabile "uno" l'indirizzo (Address)
della cella trovata col valore uguale (indirizzo = riferimento). I cicli For Each....Next consento di eseguire
le istruzioni di ricerca, cella per cella, fino alla fine dell'area assegnata. Poi, visto che stiamo lavorando
con dei numeri (se si facesse cercare del testo non sarebbe necessario), E' NECESSARIO dichiarare il
"tipo" di dati restituito dalla InputBox, altrimenti il codice non riconoscerebbe come numero il dato
inserito. Per fare questo usiamo la funzione Val() che restituisce i numeri inclusi in una stringa sotto forma
di valore numerico di tipo appropriato. Dobbiamo inoltre ricordare che la funzione Val riconosce solo il
punto (.) come separatore decimale valido, se quindi lavoreremo con numeri decimali, nella InputBox
dovremo scrivere il valore da cercare usando il punto ( . ) come separatore e NON la virgola, mentre
ovviamente sul foglio di lavoro i decimali dovranno essere regolarmente inseriti con la virgola ( , ).
Oppure definire come "tipo" di dati non pi Val ma CDbl (es. CDbl(X) ) in questo modo potremo usare
la virgola ( , ) come separatore, nell'inserimento del valore nella InputBox.

For Each CL In zona


If CL.Value = Val(X) Then uno = CL.Address
Next

Dal momento che potremmo cercare un dato che potrebbe essere non presente nell'area, avremo
bisogno di essere avvisati con un messaggio, e sopratutto di impedire che la routine prosegua
generando poi un errore perch l'indirizzo assegnato alla variabile "uno" non stato trovato. Useremo
quindi la seguente istruzione: se "uno" vuoto, avvisa con il messaggio ed esci dalla routine:

If uno = "" Then


MsgBox "Valore non presente"
Exit Sub
End If

se invece il valore presente, proseguiamo con la ricerca, sempre tramite InputBox, del secondo
valore da cercare. Le istruzioni sono le stesse usate per il primo ciclo di ricerca, cambiano solo i nomi
assegnati alle variabili:

Y = InputBox("dato due", "inserisci il secondo dato")


If Y = "" Then Exit Sub
For Each CL In zona
If CL.Value = Val(Y) Then due = CL.Address
Next

If due = "" Then


MsgBox "Valore non presente"
Exit Sub
http://ennius.interfree.it/ Pagina 55
MANUALE VBA X EXCEL
End If
dato per scontato, di avere trovato tutte e due i valori cercati, e di essere quindi in possesso dei
riferimenti delle celle, selezioneremo tutta l'area rappresentata dai riferimenti, con la seguente
istruzione :

Range(uno & ":" & due).Select

ora che abbiamo selezionato l'area, assegneremo le propriet ai font presenti: il colore dei font, e il
grassetto. Per il colore useremo il codice colore voluto (io ho usato il rosso = 3) e usciremo dalla routine
(End Sub)

With Selection
.Font.ColorIndex = 3
.Font.Bold = True
End With
End Sub

E questo sar il risultato della nostra macro, ipotizzando di avere scelto come primo valore 13 e come
secondo 53 :

E questa la routine completa:

Sub selezona()

Set zona = ActiveSheet.UsedRange

With zona
.Font.ColorIndex = 0
.Font.Bold = False
End With

X = InputBox("dato uno", "inserisci il primo dato")


If X = "" Then Exit Sub

http://ennius.interfree.it/ Pagina 56
MANUALE VBA X EXCEL
Dim CL As Object
For Each CL In zona
If CL.Value = Val(X) Then uno = CL.Address
Next

If uno = "" Then


MsgBox "Valore non presente"
Exit Sub
End If
'secondo ciclo
Y = InputBox("dato due", "inserisci il secondo dato")
If Y = "" Then Exit Sub
For Each CL In zona
If CL.Value = Val(Y) Then due = CL.Address
Next

If due = "" Then


MsgBox "Valore non presente"
Exit Sub
End If

Range(uno & ":" & due).Select

With Selection
.Font.ColorIndex = 3
.Font.Bold = True
End With

End Sub

Stessa procedura con variante per selezionare un area cercando due valori uguali presenti nella
tabella (zona).
vediamo i passaggi che differiscono dalla precedente:
ovviamente inseriremo lo stesso valore sia nella prima che nella seconda InputBox.
premessa: il ciclo For Each.....Next "gira" cercando nella zona assegnata tutte le occorrenze uguali al
valore da cercare, e nel caso di pi valori uguali, li rintraccerebbe tutti ma si fermerebbe sempre
all'ultimo valore trovato.
dovremo quindi "interrompere" l'azione di ricerca del primo valore dopo che sar stato trovato e sar
stato memorizzato il suo Address (indirizzo o riferimento cella), in modo da passare alla seconda
InputBox che ci chieder il secondo valore da cercare e inizializzer il secondo ciclo di ricerca. Per fare
questo ci affidiamo all'istruzione GoTo che ci far uscire dal primo ciclo se il primo valore sar stato
trovato e ci mander direttamente al secondo ciclo. Questo secondo ciclo, legger anche il primo
valore, ma si fermer solo all'ultimo valore trovato e memorizzer SOLO questo Address.

If CL.Value = Val(X) Then

http://ennius.interfree.it/ Pagina 57
MANUALE VBA X EXCEL
CL.Select
uno = ActiveCell.Address
GoTo 10

GoTo 10 vuol dire semplicemente : "vai al numero di riga 10" e il compilatore si sposter alla riga
indicata senza eseguire le istruzioni che si trovano tra il GoTo e la riga indicata. In questo modo
saltiamo l'istruzione Next posta alla fine del primo ciclo interrompendolo in quanto il primo valore
stato trovato, e dovremo cercare il secondo o ultimo. Inseriremo quindi il numero 10 seguito dal segno
dei due punti ( : ) immediatamente prima dell'istruzione che dovr essere eseguita:
10:

Y = InputBox("dato due", "inserisci il secondo dato")


If Y = "" Then Exit Sub
For Each CL In zona
If CL.Value = Val(Y) Then due = CL.Address
Next

In questo modo otteniamo che:


se il secondo valore o ultimo non esiste in quanto il valore nella tabella univoco, verr evidenziato
solo il primo.
nel caso di errore di digitazione si cercasse un numero che non presente, si verr avvisati che il
numero non esiste.
se il secondo numero diverso dal primo ed presente in tabella, verranno evidenziati tutti i valori
compresi tra i due ( e si verifica quello che otteniamo con la prima routine sopra indicata ).
e questa la seconda routine completa:

Sub selezonadue()

Set zona = ActiveSheet.UsedRange

With zona
.Font.ColorIndex = 0
.Font.Bold = False
End With

X = InputBox("dato uno", "inserisci il primo dato")


If X = "" Then Exit Sub
Dim CL As Object
For Each CL In zona
If CL.Value = Val(X) Then
CL.Select
uno = ActiveCell.Address
GoTo 10
If uno = "" Then
MsgBox "Valore non presente"
Exit Sub
http://ennius.interfree.it/ Pagina 58
MANUALE VBA X EXCEL
End If
End If

Next

10:
Y = InputBox("dato due", "inserisci il secondo dato")
If Y = "" Then Exit Sub
For Each CL In zona
If CL.Value = Val(Y) Then due = CL.Address
Next

If due = "" Then


MsgBox "Valore non presente"
Exit Sub
End If

Range(uno & ":" & due).Select


With Selection
.Font.ColorIndex = 3
.Font.Bold = True
End With
End Sub

http://ennius.interfree.it/ Pagina 59
MANUALE VBA X EXCEL
Un esercitazione interessante : Ricerca tra due date con totale dei valori
correlati.
Una delle necessit che spesso incontriamo nella realizzazione dei nostri lavori la possibilit di
ottenere dei totali di valori inseriti in una tabella (o elenco), relativi a due parametri che vogliamo
poter definire di volta in volta, e quindi variabili. Un tipico esempio potrebbe essere quello di voler
scegliere, tra due date, quanto fatturato, o incassato, o comunque quanto il totale dei valori
registrati tra le due date, e magari per tipi di prodotti, o argomenti, o quello che vi pare. Presento
quindi un esempio basato su una tabella dove avremo una colonna, la A, dove scriveremo le date, e
tre colonne (B,C,D) dedicate a tre tipi di prodotti, dove registreremo gli incassi del giorno. Scopo della
routine sar quello i poter selezionare due date, tra quelle presenti, ed ottenere il totale dei valori dei
tre prodotti, nel periodo specificato. Va da s che la soluzione presentata si presta a tutte le varianti
che vorrete, quello che importa vedere le istruzioni impiegate. Sotto la tabella usata per l'esempio,
nella cella F4, il risultato della somma richiesta dei valori relativi alle tre colonne dei prodotti, tra le date
12/01/03 e 25/01/03:

Come si diceva si possono variare tutte le impostazioni, per esempio di chiedere la somma colonna per
colonna (baster variare i riferimenti su cui operare, e/o ripetere le istruzioni per tante colonne quante
vorremo, oppure usare delle InputBox per definire su quali riferimenti colonna lavorare (vedi ultimo
esempio)).
Ho basato questo progettino su due InputBox che ci chiedono di indicare le due date tra cui eseguire
la somma dei valori di tutte e tre le colonne comprese nel periodo. Le date vengono cercate nella
Colonna A, e ho inserito un controllo che avvisa se la/le date inserite non figurano nell'elenco, e viene
riproposta la richiesta di inserire una data presente in elenco. Per quanto riguarda i riferimenti che
servono a definire la zona da sommare, le colonne le abbiamo gi, ma non sappiamo a priori quali
righe saranno interessate, e allora ho preparato una Funzione Utente (enn) che cerca il numero di riga
relativo alle date che inseriremo nelle InputBox e questi dati vengono memorizzati in due variabili. A
questo punto baster legare le variabili "riga" alle colonne, per avere i riferimenti necessari alla funzione
=SOMMA (=SUM in inglese). Poich anche la funzione enn pu "girare a vuoto" se non viene trovata la
data immessa, stata munita di un controllo che la fa uscire dalla funzione e che fornisce zero come
risultato della funzione. Vediamo le istruzioni, prima la Funzione Utente (vedi event. paragrafo
precedente in questa stessa sezione), e poi la procedura per la somma.

Function enn(Intervallo, Valore)


If Valore = "" Then Exit Function
For Each c In Intervallo
If c.Value = Valore Then

http://ennius.interfree.it/ Pagina 60
MANUALE VBA X EXCEL
Y = c.Row 'con Y prendiamo il numero di riga corrispondente al Valore
trovato
Exit For
End If
Next c
enn = Y
'enn sar uguale al numero di riga trovato in Intervallo
End Function

e questa la procedura

Sub mia()
Dim datauno As Date
'dichiarazioni delle variabili necessarie. con datauno prendiamo il
'valore che verr fornito dalla prima inputbox, e bisogna definirla
come data perch il 'codice la renda come tale.
Dim datadue As Date
'come sopra ma per la seconda inputbox.
Dim mioval, titolo, messaggio
'variabili per le inputbox

Set Intervallo = Range("A4:A20")


'con Intervallo definiamo il range su cui intervenire per cercare le
date
10:
'rimando per riavviare l'inputbox nel caso di prima data non trovata
in Intervallo
titolo = "Inserisci una data"
messaggio = "Scrivi la PRIMA data del periodo"
mioval = InputBox(messaggio, titolo)
If mioval = "" Then Exit Sub
'se non si scrive nulla nella inputbox si esce
datauno = mioval
'datauno ora uguale alla data scritta nell'imputbox
rigauno = enn(Intervallo, datauno)
'si ottiene il numero di riga con la "funzione utente" e si 'assegna a
rigauno
If rigauno = 0 Then
'se rigauno zero (data non trovata) si d il messaggio sotto
MsgBox "la data non presente. Scegliere un'altra data"
GoTo 10
'e si ritorna a 10 per riavviare la inputbox di richiesta data
End If
'si ripete sotto per la seconda data
http://ennius.interfree.it/ Pagina 61
MANUALE VBA X EXCEL
20:
titolo = "Inserisci una data"
messaggio = "Scrivi la SECONDA data del periodo"
mioval = InputBox(messaggio, titolo)
If mioval = "" Then Exit Sub
datadue = mioval
rigadue = enn(Intervallo, datadue)
If rigadue = 0 Then
MsgBox "la data non presente. Scegliere un'altra data"
GoTo 20
End If
'ora convertiamo i numeri di riga in riferimenti della zona da sommare,
decidendo noi che 'il primo numero di riga si lega con la colonna B ed
il secondo con la colonna D. E' qui 'che possiamo decidere su quali
colonne (o quale) intervenire:
rifuno = "B" & rigauno
rifdue = "D" & rigadue
'sotto assegniamo alla cella F4 la funzione somma ( una cella come
un'altra)
Range("F4").Formula = "=Sum(" & rifuno & ":" & rifdue & ")"
'Questa sotto invece una variante su come usare la funzione somma, al
posto di quella sopra, usando il "WorksheetFunction" spiegato nel
paragrafo precedente
'Dim miorang As Range
'questa riga pu essere omessa
'Set miorang = Worksheets("Foglio1").Range(rifuno & ":" & rifdue)
'Range("F4") = WorksheetFunction.Sum(miorang)
End Sub

L'esempio seguente invece modificato con l'aggiunta delle richieste (InputBox) di quali Colonne
(prodotti) intendiamo avere i totali. In questo modo ampliamo la gestibilit della procedura,
disponendo anche di una scelta completa, su richiesta, della zona su cui vogliamo agire. Sar
sufficiente alla prima richiesta, di inserire la lettera che identifica la colonna e fare altrettanto con la
seconda richiesta. Se vorremo, ad esempio, solo il totale tra due date, ma solo della colonna B,
scriveremo B sia nella prima che nella seconda richiesta.

Sub miaricerca()
Dim datauno As Date
Dim datadue As Date
Dim mioval, titolo, messaggio

Set Intervallo = Range("A4:A20")


10:
titolo = "Inserisci una data"
messaggio = "Scrivi la PRIMA data del periodo"

http://ennius.interfree.it/ Pagina 62
MANUALE VBA X EXCEL
mioval = InputBox(messaggio, titolo)
If mioval = "" Then Exit Sub
datauno = mioval
rigauno = enn(Intervallo, datauno)
If rigauno = 0 Then
MsgBox "la data non presente. Scegliere un'altra data"
GoTo 10
End If
Range("G1").Value = rigauno

20:
titolo = "Inserisci una data"
messaggio = "Scrivi la SECONDA data del periodo"
mioval = InputBox(messaggio, titolo)
If mioval = "" Then Exit Sub
datadue = mioval
rigadue = enn(Intervallo, datadue)
If rigadue = 0 Then
MsgBox "la data non presente. Scegliere un'altra data"
GoTo 20
End If
Range("G2").Value = rigadue

'ora inseriamo due InputBox per le richieste delle o della


'colonna di cui vorremo i totali.
titolo = "Specifica la Colonna"
messaggio = "Scrivi la Colonna del prodotto di cui vuoi il totale"
mioval = InputBox(messaggio, titolo)
If mioval = "" Then Exit Sub
coluno = mioval 'coluno uguale alla prima lettera della colonna
indicata

titolo = "Specifica la seconda Colonna"


messaggio = "Scrivi la Colonna del prodotto di cui vuoi il totale"
mioval = InputBox(messaggio, titolo)
If mioval = "" Then Exit Sub
coldue = mioval 'coldue uguale alla seconda lettera della colonna
indicata
'ora convertiamo i numeri di riga
'in riferimenti della zona da sommare
rifuno = coluno & rigauno 'uniamo la prima colonna e il primo n di
riga

http://ennius.interfree.it/ Pagina 63
MANUALE VBA X EXCEL
rifdue = coldue & rigadue 'uniamo la seconda colonna e il secondo n
di riga
Range("F4").Formula = "=Sum(" & rifuno & ":" & rifdue & ")"
'quindi avvisiamo anche con un messaggio
'il totale cos ottenuto
MsgBox "Il totale richiesto " & Range("F4").Value & ""
End Sub

http://ennius.interfree.it/ Pagina 64
MANUALE VBA X EXCEL
Ricerca di tre valori

Ancora un esempio scaturito da una richiesta: controllare se esistono tre valori su una stessa riga di una
tabella, e se trovati selezionare (restituire) un'altro valore.
La richiesta: "Se io per volessi trovare in una tabella una combinazione di numeri, esempio:12-54-33 in
questa sequenza, cio in maniera tale che il 12 sia nella colonna B, il 54 nella colonna C e il 33 nella
colonna D, contemporaneamente (non uno alla volta) in maniera tale da evidenziare poi a parte in
quale giorno si verificata (o non si verificata.....non necessariamente la combinazione deve essere
presente) come posso fare?"
Vorrei provare a ragionare con la testa del pellegrino neofita, che pur trovando sul sito molti esempi di
come trovare un dato, si trova a chiedersi: "Ok, come si trova un dato l'ho capito, ma se i dati da
trovare sono due, o tre, come faccio?"
Allora vediamo: intanto devo trovare in quale modo poter dire al codice quali sono i numeri che voglio
trovare. Poi devo trovare cosa dire al codice perch mi evidenzi la cella con la data se mi trova i tre
numeri.
mi rispondo al primo quesito: posso usare tre celle del foglio di lavoro, dove scrivere i numeri, e poi
usare i riferimenti a queste celle da usare come vettori per eseguire la ricerca; oppure, forse meglio,
usare tre InputBox, ognuna delle quali memorizzer con l'assegnazione ad una variabile (vettore) il
valore che immetter nella InputBox. Mi sembra l'idea giusta.
Ricapitoliamo: come trovare un dato l'ho capito: devo identificare un range di celle nella colonna che
uso per la ricerca, applico un ciclo For Each...Next per controllare tutte le celle del range, i tre valori a
questo punto me li ritrovo con le InputBox, ma non ho ancora presente come far leggere i valori nelle
celle accanto ad ogni cella controllata dal ciclo. Aspetta un p, da qualche parte ho letto che con
Offset posso "mirare" ad altre celle. Ottimo, ora so cosa scrivere per controllare anche le altre celle, ma
come le lego insieme le istruzioni? Vediamo un p: io nel linguaggio parlato dico: vorrei che se il valore
nella cella X e il valore nella cella Y e il valore nella cella Z; uso quindi l'operatore "e" per unire insieme le
condizioni....vuoi vedere che anche il codice accetta questo sistema? (Solo che il codice ragiona in
inglese e il concatenatore "E" si scrive "And"). A questo punto mi rispondo al secondo quesito, usando
ancora Offset, per identificare la cella con la data. Mettiamoci al lavoro................
Il pellegrino ennius a questo punto presenta la soluzione. Vediamo una tabella d'esempio:

Nella colonna A le celle con le date, che vorremo evidenziate se la ricerca di tre valori nelle colonne B-
C-D saranno uguali ai valori immessi nelle inputbox. Per variare l'esempio, cercheremo due numeri ed
un testo, cos capiamo come diversificare l'assegnazione del "tipo" di dati assegnato ad ogni variabile.

Sub cerca()
'con CL dimensioniamo una variabile di tipo Object (CL identificher
gli oggetti (celle) 'presenti nel Range assegnato)
Dim CL As Object
'assegnazione alle variabili "uno" "due" e "tre" che diventano vettori
dei valori che introdurremo 'nelle rispettive InputBox
uno = InputBox("inserisci il primo numero")
due = InputBox("inserisci il secondo numero")
tre = InputBox("inserisci il terzo numero")

http://ennius.interfree.it/ Pagina 65
MANUALE VBA X EXCEL
'si inizia il ciclo For Each, che vuol dire: per ogni CL (cella nel
Range B1:B100)
For Each CL In Range("B1:B100")
'esegui questo controllo: SE il valore della cella in quel momento
identificata dal ciclo uguale 'al vettore "uno" E la cella
immediatamente a destra (Offset(0, 1)) uguale al vettore "due" E la
'cella, due celle a destra (Offset(0, 2)) uguale al vettore "tre",
Allora (Then)...Da notare che per i vettori "uno e "due", trattandosi
di numeri, necessario dichiarare il tipo di dati usando 'Val, mentre
per il terzo vettore che sar testo, dichiariamo CStr (stringa). La
riga sotto tutta 'una riga, anche se per necessit di spazio la
vedete su due righe.
If CL.Value = Val(uno) And CL.Offset(0, 1).Value = Val(due) And
CL.Offset(0, 2).Value = CStr(tre) Then
'con l'istruzione sotto, se vengono riscontrati i tre valori uguali ai
vettori, si seleziona con Offset 'la cella, stessa riga, immediatamente
a sinistra della cella (CL).
CL.Offset(0, -1).Select
End If
Next
End Sub

http://ennius.interfree.it/ Pagina 66
MANUALE VBA X EXCEL
Trovare un dato (vettore) in una tabella, con restituzione di un dato
correlato.

La ricerca di dati uno degli "sport" preferiti dagli Excelnauti. La variet delle necessit delle ricerche
tale, che impensabile esemplificarli tutti. Stasera una richiesta mi fornisce lo spunto per esaminare un
metodo di ricerca che pu essere semplice da capire e al tempo stesso adattabile, con poche
modifiche, in modo che i concetti usati siano sfruttabili da chiunque. Se vogliamo, l'esempio che
faremo, richiama a grandi linee il comportamento delle funzioni CERCA.VERT e CERCA.ORIZ unite
insieme: ognuna di queste funzioni, ricerca un dato (vettore) in un elenco di dati su pi colonne o
righe, restituendo il valore che si trover sulla stessa riga, o colonna, del vettore trovato, ma in una
colonna o riga scelta in precedenza. L'esempio:
una tabella di dati su un foglio (Foglio1), formata da pi colonne; nella colonna A della tabella una
serie di valori.
un'altra tabella su un'altro foglio (Foglio2), formata anch'essa da pi colonne e righe: da B1 a Z100, in
ognuna di queste celle si trovano dei valori, e in una sola delle celle di questa zona si pu trovare uno
qualsiasi dei valori presenti nella colonna A del foglio1. Nella colonna A ma sempre del Foglio2 (quindi
da A1 a A100) si trovano dei valori correlati.
esercizio : vogliamo che selezionando una cella contenente un valore nella colonna A del foglio1,
venga trovato lo stesso valore nella tabella sul foglio2, nella zona B1:Z100, ma non vogliamo il valore
trovato, bens il valore presente nella stessa riga ma nella colonna A.
I valori presenti nel Range(B1:Z100) sono univoci, ma non sappiamo dove sono.
La procedura semplice: selezioniamo sul foglio1 la cella con il valore da cercare, attiviamo la macro
che avremo associato ad un pulsante, indichiamo con una variabile il valore della cella da cercare
(X), iniziamo un ciclo di ricerca di X nella zona Foglio2 , Range B1:Z100, trovato il valore, selezioniamo la
cella, ci spostiamo a inizio riga, selezioniamo quindi la cella stessa riga ma della colonna A, e
restituiamo il valore della cella ora attiva, con una MessageBox. Ovviamente potremmo restituire detto
valore in qualunque cella lo volessimo, con un semplice:
Range("tuacella").Value = ActiveCell.Value
Questa la procedura:

Sub cercalapippo()
'evitiamo i saltellamenti a schermo
Application.ScreenUpdating = False
'siamo sul foglio1, abbiamo selezionatoo una cella e ne assegnamo il
valore ad una 'variabile, la X
X = Selection.Value
'ci spostiamo sul foglio2 dove esiste la zona in cui eseguire la
ricerca Range("B1:Z10")
Worksheets(2).Select
'dichiariamo una variabile di tipo Object
Dim CL As Object
'inizia il ciclo di ricerca: per ogni cella (CL) nel range previsto
For Each CL In Worksheets(2).Range("B1:Z100")
'se il valore della cella (CL) uguale al valore della X
If CL.Value = X Then
'allora selezioniamo la cella (CL)
CL.Select
'ora dalla cella selezionata, ci spostiamo a inizio riga e selezioniamo
la cella inizio riga
http://ennius.interfree.it/ Pagina 67
MANUALE VBA X EXCEL
With ActiveCell
Cells(ActiveCell.Row, 1).Select
End With
'rendiamo il valore della cella attiva nella colonna A con un messaggio
MsgBox "Il valore " & ActiveCell & ""
End If
Next
'ritorniamo sul foglio1
Worksheets(1).Select
End Sub
E' evidente che potrete avere in "restituzione" qualunque valore di qualsiasi colonna. Uno dei problemi
delle ricerche che spesso non sappiamo dove si trover il valore che cerchiamo, e risulta
problematico quindi fornire richieste di dati correlati, visto che Excel lo pu fare solo se gli si danno
delle coordinate precise. Impossibile quindi impostare a priori istruzioni che dicano "restituisci il valore
che si trova due colonne a destra o 3 colonne a sinistra", visto che non sapremo quale sar la colonna
in cui esister il valore cercato. L'istruzione Cells(ActiveCell.Row, 1).Select invece ci permette di
determinare con esattezza di quale colonna, stessa riga, vorremo il valore restituito, modificando il
numero presente nell'istruzione; se avessimo voluto in valore che si trovava nella colonna C avremmo
dovuto scrivere: Cells(ActiveCell.Row, 3).Select
Se il valore cercato (X) non presente nella zona ricerca (Range("B1:Z100")), la routine non porter
risultato e quindi nessun messaggio. Se invece saranno presenti pi valori X, verr riportato il valore
associato alla prima riga dove sar presente il primo valore X, poi il successivo, fino all'ultimo dove il
ciclo per si fermer, e solo l'ultimo sar visualizzato, o memorizzato nel caso si usi una cella per la
destinazione del valore correlato, a meno che non si usi un'istruzione che a partire dalla cella di
destinazione prevista, non cerchi una cella in una riga libera; in questo caso saranno registrati tanti
valori X correlati quanti saranno i valori X trovati.

http://ennius.interfree.it/ Pagina 68
MANUALE VBA X EXCEL
Cercare File(s) sull'Hard-Disk.
Un esercizio utile a chi voglia ricercare se esiste un file, oppure di avere l'elenco di tutti i file con una
determinata estensione presenti in una cartella. Sfrutteremo il metodo Execute applicato all'oggetto
FileSearch. Con Execute possiamo usare due costanti che ci forniranno l'elenco dei file trovati ordinati
per nome e in ordine crescente (da A a Z). ( Execute inizia la ricerca per il file o i file specificati.
Restituisce un oggetto Long; zero (0) se non viene trovato alcun file o un numero positivo se vengono
trovati uno o pi file). Le istruzioni si basano sul settaggio di una variabile assegnata ad
Application.FileSearch, che saranno sempre le stesse, a cui seguiranno istruzioni su dove cercare il file e
il nome o l'estensione da trovare; queste ultime le renderemo variabili per poter eseguire tipi diversi di
ricerca.. Ma partiamo col primo esempio, la ricerca di un file in una cartella. Di questo esempio, con i
parametri di ricerca fissi e impostati nelle istruzioni, non vedo una pratica utilit, serve solo a avvicinarsi
ai concetti di queste ricerche; in verde i commenti:

Sub cercaunfile()
Set fs = Application.FileSearch 'assegnazione alla variabile "fs" del
metodo di ricerca
With fs 'con la variabile "fs"
.LookIn = "C:\Documenti" 'cerca nella cartella documenti
.Filename = "Pippo.doc" ' il file col nome di Pippo.doc
If .Execute() > 0 Then 'se eseguendo la ricerca trovi il file
(execute sar 1, quindi 'maggiore di zero), avvisi col il seguente
messaggio:
MsgBox "Il File presente."
Else 'altrimenti avvisi con questo messaggio:
MsgBox "File non trovato."
End If 'fine condizione
End With 'fine con "fs"
Set fs = Nothing 'cancelliamo dalla memoria "fs"
End Sub

Nel secondo esempio invece esaminiamo le procedure per la ricerca di file impostando non pi i
parametri nel codice, ma usando tre celle del foglio di lavoro da usare come contenitori (vettori) che
assegneremo a tre variabili, e saranno le tre variabili a prendere il posto del
nome della cartella entro cui cercare
nome del file (o dei files) da cercare
estensione dei file da cercare
In questo modo potremo cercare in qualunque cartella, un file specifico o, impostando un asterisco (
carattere jolly * al posto del nome file, cos verranno cercati TUTTI i file), variare il tipo di estensione dei
file, per ottenere di volta in volta tutti i tipi di documento Word (doc), o di file di Excel (xls), o di
immagini (bmp, jpg, ecc.) ecc. ecc. Nell'esempio proposto uso le celle A1, B1 e C1 (ma potranno
essere quelle che vorrete) per scrivere rispettivamente: il nome cartella, il nome del file, l'estensione da
cercare. Esempio delle tre celle con, rispettvamente: nome della cartella - asterisco - estensione :

A B C
1 Documenti * txt

Altro accorgimento: inserendo nelle istruzioni la propriet SearchSubFolders impostata a True , sar
possibile eseguire la ricerca in tutte le cartelle del nostro Hard-Disk, SENZA bisogno di indicare il nome di
una cartella, in questo modo verranno trovati TUTTI i file con l'estensione richiesta presenti in tutte le
cartelle, Esempio in cui la cella A1 viene lasciata vuota:

http://ennius.interfree.it/ Pagina 69
MANUALE VBA X EXCEL
A B C
1 * txt

Una cosa da considerare che non sapremo il numero di quanti files saranno presenti in una
determinata cartella, e visto che una volta lanciata la routine, il metodo Execute restituisce un SOLO
messaggio col totale dei files trovati e a seguire, MA SENZA INTERRUZIONE, un messaggio col nome ed il
percorso dei ogni file trovato, se vogliamo interrompere il ciclo anzitempo, doveroso prevedere una
domanda condizionale se vorremo uscire (dal ciclo) oppure no. Vediamo le istruzioni, in verde i
commenti:

Sub cercafiledue()
'sotto assegnazione a tre variabili del contenuto delle tre celle
usate:
cartella = Range("A1").Value
nome = Range("B1").Value
este = Range("C1").Value

Set fs = Application.FileSearch
With fs
'il metodo NewSearch viene utilizzato per ripristinare i criteri di
ricerca predefiniti prima 'di iniziare una nuova ricerca.
.NewSearch
'sotto cercheremo sul C:\ il nome della cartella digitato in A1
.LookIn = "C:\" & cartella & ""
'sotto: istruzione per cercare in tutte le cartelle e sottocartelle se
verr lasciata vuota la variabile "cartella" (cio la cella A1)
.SearchSubFolders = True
'sotto usiamo i valori scritti in B1 e C1 per cercare nome file o tutti
i file (*) con 'l'estensione voluta
.Filename = "" & nome & "." & este & ""
'sotto: utilizzo delle costanti di execute per ottenere la ricerca in
ordine alfabetico
If .Execute(SortBy:=msoSortByFileName, _
SortOrder:=msoSortOrderAscending) > 0 Then
'primo messaggio che avvisa quanti files sono stati trovati (con
.FoundFiles.Count)
MsgBox "Ci sono " & .FoundFiles.Count & file(s) trovati."
'inizio del ciclo For Next per restituire per ogni file trovato, il
nome e il suo percorso; 'assegnazione alla variabile I di detto nome,
che cambier ad ogni ciclo fino alla fine dei 'files trovati, e
restituiti uno dopo l'altro con un messaggio
For I = 1 To .FoundFiles.Count
MsgBox .FoundFiles(I)
'sotto: inserimento in questo punto, cio dopo che sar riportato il
nome di un file con la 'msgbox sopra, che inseriamo la domanda se
vorremo uscire
dimmi = MsgBox("Vuoi uscire dalla ricerca ?", vbYesNo)

http://ennius.interfree.it/ Pagina 70
MANUALE VBA X EXCEL
'se la risposta sar SI allora:
If dimmi = vbYes Then
'cancelliamo fs dalla memoria
Set fs = Nothing
'usciamo dal ciclo e dalla routine
Exit For
End If
Next I
'sotto: altrimenti (else) se nessun nome o estensione richiesta verr
trovato, si avvisa con il 'messaggio:
Else
MsgBox "File(s) non trovato."
End If
End With
Set fs = Nothing
End Sub
Alcuni accorgimenti: la routine sopra l'abbiamo impostata con, tra i criteri di ricerca, la possibilit di
scegliere noi l'estensione da cercare. Bene, esiste una variante usando la propriet FileType con la
costante msoFileTypeOfficeFiles , di ottenere tutti i file caratterizzati dalle seguenti estensioni: *.doc, *.xls,
*.ppt, *.pps, *.obd, *.mdb, *.mpd, *.dot, *.xlt, *.pot, *.obt, *.htm o *.html. - In questo caso non useremo
nelle istruzioni la propriet FileName, sostituendo la riga dell'istruzione

.Filename = "" & nome & "." & este & ""

con questa:

.FileType = msoFileTypeOfficeFiles

http://ennius.interfree.it/ Pagina 71
MANUALE VBA X EXCEL
Controllo comunicazioni MSCOMM32.OCX per comunicare col Modem e/o
chiamare numeri telefonici.

Premetto che non ho n provato, n intendo farlo, ad usare le istruzioni che seguono per eseguire
chiamate a numeri telefonici, ma spinto da alcune richieste ricevute, provo a segnalare ai "volenterosi"
queste istruzioni : se ne avranno voglia, si cimenteranno nel seguirle.
Fornisco comunque alcune considerazioni di massima:
per telefonare dal computer necessario un Modem ed una porta di connessione al modem: la
COM1 o la COM2. Inoltre il Modem deve essere munito dei ModemAudioDevice, driver che in genere
vengono installati dal Sistema Operativo al momento del riconoscimento del Modem stesso, insieme ai
driver del modem.
Perch Excel possa utilizzare il "controllo" per comunicare, dovr essere inserito nella UserForm.
Trattandosi di un "controllo" OCX, dovremo, nell'editor di visual basic, scegliere dal men "Strumenti" e
poi "Riferimenti" - In questa finestra dovremo premere sul pulsante "Sfoglia", si aprir la finestra "Aggiungi
riferimento": qui dovremo selezionare in "Tipo di file", il tipo ocx (Controlli ActiveX *.ocx). A questo punto
nella zona centrale cercheremo e selezioneremo MSCOMM32.OCX, che il controllo che serve.
Daremo OK, OK, e troveremo il nostro controllo "caricato" nella "casella degli strumenti" della UserForm.

A questo punto selezioneremo il "controllo" nella casella degli strumenti e spostandoci sulla UserForm,
trasciniamo fino ad ottenere l'icona del controllo inserito (in esecuzione il controllo non visibile).
Questa l'immagine che vedremo
:

e questa l'immagine della finestra delle "propriet" del controllo:

http://ennius.interfree.it/ Pagina 72
MANUALE VBA X EXCEL

Passiamo alle spiegazioni trovate su un libro:

Controllo comunicazioni MSCOMM32.OCX


Il controllo comunicazioni consente di aggiungere nell'applicazione funzioni semplici per comunicazioni
attraverso porte seriali nonch funzioni avanzate per la creazione di uno strumento di comunicazione
completo basato su eventi.

Il controllo comunicazioni MSCOMM32.OCX


Il controllo comunicazioni fornisce un'interfaccia a un gruppo di comandi di comunicazione standard e
consente di stabilire una connessione a una porta seriale, di connettersi a un'altra periferica di
comunicazione, ad esempio un modem, di inviare comandi, di scambiare dati nonch di eseguire il
monitoraggio e rispondere ai vari eventi ed errori generati durante una connessione seriale.

Esempi di utilizzo
Composizione di numeri telefonici
Monitoraggio di una porta seriale per il controllo di dati in entrata
Creazione di programmi per terminale completi
Nozioni fondamentali sulle comunicazioni seriali

In tutti i computer sono disponibili una o pi porte seriali COM1, COM2 e cos via. In un PC standard il
mouse in genere collegato alla porta COM1, un modem alla porta COM2, uno scanner alla porta
COM3 e cos via. Le porte seriali rappresentano il canale di trasmissione dei dati inviati attraverso
queste periferiche seriali esterne.

La funzione fondamentale della porta seriale consiste nell'agire da interprete tra la CPU e la periferica
seriale. Durante la trasmissione di dati dalla CPU alla porta seriale, i valori Byte vengono convertiti in bit
seriali, che vengono quindi riconvertiti in valori Byte durante la ricezione dei dati.
Per completare la trasmissione dei dati, tuttavia necessario un ulteriore livello di interpretazione. Nel
sistema operativo di Windows viene utilizzato il driver di comunicazione Comm.drv per inviare e
ricevere dati utilizzando le funzioni standard dell'API di Windows. Il produttore della periferica seriale
fornisce un driver specifico per la connessione dell'hardware a Windows. Quando si utilizza il controllo
comunicazioni, vengono eseguite funzioni dell'API che vengono quindi interpretate dal driver
Comm.drv e passate al driver della periferica.

Un programmatore deve occuparsi esclusivamente dell'interazione di Windows. Un programmatore di


Visual Basic deve invece occuparsi dell'interfaccia fornita dal controllo comunicazioni alle funzioni
dell'API del driver di comunicazione di Windows, ovvero deve impostare ed eseguire il monitoraggio
delle propriet e degli eventi del controllo comunicazioni.
Connessione seriale
Per utilizzare il controllo comunicazioni innanzitutto necessario stabilire la connessione alla porta
seriale. Nella tabella seguente sono elencate le propriet che consentono di stabilire la connessione
seriale.

http://ennius.interfree.it/ Pagina 73
MANUALE VBA X EXCEL
Propriet Descrizione

CommPort Imposta e restituisce il numero della porta di comunicazione.

Settings Imposta e restituisce in forma di stringa i valori di velocit in baud, parit, bit
di dati e bit di stop.

PortOpen Imposta e restituisce lo stato di una porta di comunicazioni, oltre ad aprire e


a chiudere la porta.

Apertura di porte seriali


Per aprire una porta seriale, necessario impostare le propriet CommPort, PortOpen e Settings. Ad
esempio:

' Apre la porta seriale


MSComm1.CommPort = 2
MSComm1.Settings = "9600,N,8,1"
MSComm1.PortOpen = True

La propriet CommPort consente di impostare la porta seriale da aprire. Se un modem collegato alla
porta COM2, l'esempio precedente imposta il valore su 2 (COM2) ed esegue la connessione al
modem. possibile impostare il valore della propriet CommPort su un numero compreso tra 1 e 16 (il
valore predefinito 1). Se tuttavia si imposta questo valore su una porta COM non disponibile per il
sistema in cui l'applicazione viene eseguita, verr generato un errore.
La propriet Settings consente di specificare la velocit in baud, la parit e il numero di bit di dati e bit
di stop. Per impostazione predefinita, la velocit in baud impostata su 9600. L'impostazione della
parit relativa alla convalida dei dati. In genere non viene utilizzata ed pertanto impostata su "N".
L'impostazione dei bit di dati specifica il numero di bit che rappresenta un blocco di dati. Il bit di stop
indica quando un blocco di dati stato ricevuto.
Dopo aver specificato la porta che si desidera aprire e la modalit di gestione della comunicazione di
dati, necessario stabilire la connessione impostando la propriet PortOpen. Si tratta di un valore
booleano, ovvero True o False. Se tuttavia la porta non attiva, la propriet CommPort impostata in
modo non corretto oppure la periferica non supporta le impostazioni specificate, verr generato un
errore oppure la periferica esterna non funzioner correttamente. Quando la propriet PortOpen viene
impostata su False la porta viene chiusa.
Utilizzo di un modem
Nella maggior parte dei casi il controllo comunicazioni viene utilizzato per programmare l'applicazione
in modo che possa essere eseguita insieme a un modem. Il controllo consente di utilizzare il gruppo di
comandi Hayes compatibili standard per comporre un numero telefonico o per connettersi e interagire
con un altro modem.
Dopo aver stabilito la connessione con la porta seriale tramite le propriet CommPort, Settings e
PortOpen, necessario attivare il modem impostando la propriet Output con cui possibile eseguire i
comandi per il controllo dell'interazione tra due modem. Ad esempio:

' Attiva il modem e compone un numero telefonico.


MSComm1.Output = "ATDT 555-5555" & vbCr

Nell'esempio precedente il comando "AT" avvia la connessione, "D" compone il numero e "T" specifica
la composizione a toni, anzich quella a impulsi. Quando si invia output a un terminale, necessario
specificare un carattere di ritorno a capo (vbCr). Questa operazione non invece necessaria per
l'output di matrici di byte.
Per controllare se il comando viene elaborato in modo corretto, sufficiente verificare che venga
restituito il codice "OK".
http://ennius.interfree.it/ Pagina 74
MANUALE VBA X EXCEL
Ulteriori informazioni Per un elenco completo dei comandi Hayes compatibili, vedere la
documentazione del modem.
Impostazione delle propriet Receive e Transmit Buffer in fase di progettazione
Quando una porta viene aperta vengono creati buffer di trasmissione e di ricezione. Per la gestione di
tali buffer, sono disponibili alcune propriet del controllo comunicazioni che possibile impostare in
fase di progettazione nella finestra Pagine propriet del controllo.
Impostazione delle propriet dei buffer in fase di progettazione

Allocazione delle memoria dei buffer


Le propriet InBufferSize e OutBufferSize consentono di specificare la quantit di memoria allocata ai
buffer di ricezione e trasmissione. Per impostazione predefinita le due propriet vengono impostate sui
valori indicati nell'illustrazione. Maggiore il valore, minore la quantit di memoria disponibile per
l'applicazione. Se le dimensioni del buffer sono troppo piccole, potrebbe verificarsi un overflow del
buffer, a meno che non si utilizzi la sincronizzazione.
Nota Data la quantit di memoria attualmente disponibile nella maggior parte dei PC, l'allocazione di
memoria ai buffer non un'operazione di fondamentale importanza, in quanto disponibile un
maggior numero di risorse. In altri termini, l'impostazione di valori del buffer maggiori non ha alcun
effetto negativo sulle prestazioni delle applicazioni.
Propriet RThreshold e SThreshold
Le propriet RThreshold e SThreshold consentono di impostare o restituire il numero di caratteri che
dovranno essere ricevuti nel buffer di ricezione e di trasmissione prima che venga generato l'evento
OnComm. L'evento OnComm consente di eseguire il monitoraggio e rispondere alle modifiche dello
stato della comunicazione. Con l'impostazione di entrambe le propriet su zero (0) possibile impedire
che l'evento OnComm venga generato, mentre con l'impostazione su un valore diverso da 0, ad
esempio 1, l'evento OnComm viene generato ogni volta che un carattere viene ricevuto in uno dei
buffer.
Ulteriori informazioni Per informazioni su queste propriet, vedere "Evento OnComm e propriet
CommEvent" pi avanti in questa sezione.
Propriet InputLen e EOFEnable
Se si imposta la propriet InputLen su 0 il controllo comunicazioni esegue la lettura dell'intero contenuto
del buffer di ricezione quando si utilizza la propriet Input. Durante la lettura di dati in un computer in
cui l'output formattato come blocchi di dati di lunghezza fissa, possibile impostare il valore di
questa propriet in modo appropriato.
La propriet EOFEnable consente di segnalare l'individuazione di un carattere di fine del file, o EOF,
durante l'ingresso dei dati. Se la propriet impostata su True, l'ingresso dei dati viene interrotto e viene
generato l'evento OnComm per indicare che si verificata questa condizione.
Ulteriori informazioni Vedere "Gestione dei buffer di ricezione e di trasmissione" e "Evento OnComm e
propriet CommEvent" pi avanti in questa sezione.
Gestione dei buffer di ricezione e di trasmissione
I buffer di ricezione e di trasmissione vengono creati in corrispondenza dell'apertura di una porta e
utilizzati per la memorizzazione dei dati in arrivo e per la trasmissione dei dati in uscita. Il controllo
comunicazioni consente di gestire questi buffer tramite alcune propriet per l'inserimento e il recupero
di dati, per la restituzione delle dimensioni di ciascun buffer e per la gestione sia di testo che di dati
binari. Quando si utilizza il controllo comunicazioni, estremamente importante gestire questi buffer in
modo corretto.
Buffer di ricezione
La propriet Input consente di memorizzare e recuperare dati dal buffer di ricezione. Se, ad esempio, si
desidera recuperare dati dal buffer di ricezione per visualizzarli in una casella di testo, possibile
utilizzare il codice seguente:

TxtDisplay.Text = MSComm1.Input

Per recuperare l'intero contenuto del buffer di ricezione, innanzitutto necessario impostare la
propriet InputLen su 0 in fase di progettazione o di esecuzione.
inoltre possibile ricevere dati in arrivo come testo o come dati binari impostando la propriet
InputMode sulle costanti Visual Basic comInputModeText o comInputModeBinary. I dati verranno in tal
http://ennius.interfree.it/ Pagina 75
MANUALE VBA X EXCEL
modo recuperati in forma di stringa o di dati binari in una matrice Byte. necessario impostare la
propriet su comInputModeText per i dati che utilizzano il set di caratteri ANSI e la costante
comInputModeBinary per tutti gli altri dati, ad esempio i dati che includono caratteri di controllo
incorporati, valori Null e cos via.

Ciascun byte di dati ricevuto viene inserito nel buffer di ricezione e il valore della propriet
InBufferCount viene incrementata di una unit. Tale valore pu quindi essere utilizzato per recuperare il
numero di byte del buffer di ricezione. inoltre possibile impostare la propriet su 0 per svuotare il buffer
di ricezione.

Buffer di trasmissione
La propriet Output consente di inviare comandi e dati al buffer di trasmissione.
In modo analogo

alla propriet Input, possibile trasmettere i dati in forma di testo o di dati binari. Con la propriet
Output tuttavia necessario trasmettere testo o dati binari specificando una matrice String o Byte.
La propriet Output consente di inviare comandi, stringhe di testo o dati di matrice Byte. Ad esempio:

' Invia un comando AT


MSComm1.Output = "ATDT 555-5555"

' Invia una stringa di testo


MsComm1.Output = " Questa una stringa di testo"

' Invia dati di matrice Byte


MSComm1.Output = Out

Le righe di trasmissione devono terminare con un carattere di ritorno a capo (vbCr). Nell'esempio
precedente Out una variabile definita come matrice Byte, ovvero Dim Out() As Byte. Se fosse un
valore Variant di tipo String, sarebbe definito come Dim Out() As String.
possibile controllare il numero di byte del buffer di trasmissione tramite la propriet OutBufferCount e
svuotare il buffer impostando questa propriet su 0.

Sincronizzazione
Una parte integrante della procedura di gestione dei buffer di ricezione e di trasmissione consiste
nell'assicurare che la trasmissione dei dati venga eseguita correttamente in entrambe le direzioni, ad
esempio che la velocit di ricezione dei dati non superi i limiti del buffer.

Con il termine sincronizzazione viene fatto riferimento al protocollo di comunicazione interno in base a
cui i dati vengono trasferiti dalla porta hardware al buffer di ricezione. Quando la porta seriale riceve
un carattere sotto forma di dati, la periferica di comunicazione deve trasferirlo nel buffer di ricezione in
modo che possa essere letto dal programma.

Un protocollo di sincronizzazione assicura che non si verifichi alcuna perdita di dati dovuta a un overrun
del buffer. Questa situazione si verifica quando i dati raggiungono la porta ad una velocit troppo
elevata che ne impedisce il trasferimento nel buffer di ricezione.

Per specificare il protocollo di sincronizzazione da utilizzare nell'applicazione, necessario impostare la


propriet Handshaking. Per impostazione predefinita, questo valore viene impostato su comNone,
ovvero nessun protocollo. Le possibili impostazioni sono le seguenti:

http://ennius.interfree.it/ Pagina 76
MANUALE VBA X EXCEL
Impostazione Valore Descrizione

comNone 0 Nessuna sincronizzazione (impostazione


predefinita).

comXOnXOff 1 Sincronizzazione XOn/XOff.

comRTS 2 Sincronizzazione RTS/CTS (Request To Send/Clear


To Send).

comRTSXOnXOff 3 Sia Request To Send che XON/XOFF.

La scelta del protocollo si basa sulla periferica a cui ci si connette. Con l'impostazione comRTSXOnXOff
supportato sia il protocollo Request To Send che il protocollo XON/XOFF.
In molti casi, la sincronizzazione viene gestita dal protocollo stesso. Di conseguenza, l'impostazione della
propriet su un valore diverso da comNone pu generare conflitti.
Nota Se si imposta la propriet su comRTS o comRTSXOnXOff, necessario impostare la propriet
RTSEnabled su True. In caso contrario, sar possibile connettersi e inviare dati, ma non ricevere dati..

Evento OnComm e propriet CommEvent


A seconda dell'area di validit e della funzionalit dell'applicazione, potrebbe essere necessario
controllare e rispondere a un certo numero di eventi o errori generati durante la connessione a un'altra
periferica oppure durante la ricezione o la trasmissione dei dati.
L'evento OnComm e la propriet CommEvent consentono di intercettare e verificare il valore degli
eventi e degli errori di comunicazione.

In corrispondenza di un evento o di un errore di comunicazione, viene generato l'evento OnComm e il


valore della propriet CommEvent viene modificato. Se necessario, pertanto possibile verificare il
valore della propriet CommEvent ogni volta che l'evento OnComm viene generato. Dato che la
qualit della comunicazione imprevedibile, soprattutto nel caso di comunicazioni telefoniche,
l'intercettazione di questi eventi ed errori consente di fornirvi una risposta adeguata.
Nella tabella seguente sono elencati gli eventi di comunicazione che generano l'evento OnComm. I
valori vengono quindi scritti nella propriet CommEvent.

Costante Valore Descrizione

comEvSend 1 Il numero di caratteri del buffer di trasmissione inferiore al


valore di SThreshold.

comEvReceive 2 Numero di caratteri RThreshold ricevuti. Questo evento


viene generato continuamente fino a quando i dati non
vengono rimossi dal buffer di ricezione tramite
l'impostazione della propriet Input.

comEvCTS 3 Modifica della linea CTS (Clear To Send).

comEvDSR 4 Modifica della linea DSR (Data Set Ready). Questo evento
viene generato solo con la modifica di DSR da 1 a 0.

comEvCD 5 Modifica della linea CD (Carrier Detect).

comEvRing 6 Individuato squillo. Alcuni trasmettitori-ricevitori asincroni


universali o UART (Universal Asynchronous Receiver-
Transmitter) potrebbero non supportare questo evento.

comEvEOF 7 Ricezione di un carattere di fine del file, o EOF (carattere


ASCII 26).

http://ennius.interfree.it/ Pagina 77
MANUALE VBA X EXCEL
L'evento OnComm viene inoltre generato quando vengono individuati gli errori indicati di seguito, con
la conseguente scrittura di un valore nella propriet CommEvent.

Impostazione Valore Descrizione

comEventBreak 1001 Ricezione di un segnale di interruzione.

comEventFrame 1004 Errore di frame. L'hardware ha individuato un errore di


frame.

comEventOverrun 1006 Overrun della porta. L'hardware non ha letto un


carattere prima dell'arrivo del successivo e il carattere
andato perduto.

comEventRxOver 1008 Overflow del buffer di ricezione. Spazio esaurito nel


buffer di ricezione.

comEventRxParity 1009 Errore di parit. stato rilevato un errore di parit.

comEventTxFull 1010 Buffer di trasmissione pieno. Spazio esaurito nel buffer di


trasmissione durante il tentativo di inserimento di un
carattere.

comEventDCB 1011 Errore imprevisto durante il recupero di DCB (Device


Control Block) per la porta.

http://ennius.interfree.it/ Pagina 78
MANUALE VBA X EXCEL
Chiamare usando il telefono da Excel (con modem).
ovvero: utilizzare il programma Dialer.exe
Forse non molti sanno che i Sistemi Operativi a partire dalla versione Windows 95, possiedono un'utility
che consente di telefonare usando il computer per la composizione dei numeri di telefono, e di
effettuare la chiamata utilizzando un modem voice. Questo piccolo programma si chiama : Dialer.exe
A secondo il S.O. installato, cambia la versione di questo eseguibile, che comunque si pu richiamare
dal men Start/Esegui (sul Desktop), e nella finestrina digitare: dialer

Le opzioni del programma dialer.exe differiscono a secondo la versione, comunque hanno una finestra
per l'inserimento del numero telefonico da chiamare, una rubrica in cui memorizzare i numeri di pi
frequente consultazione, o la possibilit di comporre il numero attraverso un tastierino numerico, oltre
alle opzioni per selezionare la periferica adatta alla connessione.

Ma vediamo come "richiamare" questo dialer da Excel. Useremo quindi il sistema gi spiegato su
questa sezione, paragrafo "Apertura applicativi". Creeremo quindi la nostra macro che richiameremo
con un pulsante posto sul foglio di lavoro. Poich cambia il percorso dove si trova il file, in dipendenza
del sistema operativo installato, vi presento le relative istruzioni:

su Windows XP - dialer.exe si trova in C:\Programmi\Windows NT\Dialer.exe e quindi questa l'istruzione:


Sub fonosxp()
Dim x
x = Shell("C:\Programmi\Windows NT\dialer.exe", 1)
End Sub

Su Windows98SE - dialer.exe si trova nella cartella di sistema C:\Windows\Dialer.exe e quindi questa


l'istruzione:
Sub fonosw98()
Dim x
x = Shell("C:\Windows\dialer.exe", 1)
End Sub

Non ho presenti gli altri sistemi operativi (W95 - W98 - ME) ma ritengo che il percorso di dialer.exe sia lo
stesso di W98SE.
Queste istruzioni comunque attivano il programma Dialer, e sar sufficiente a questo punto, lavorare
direttamente sul programma cos aperto.
Note sui collegamenti:
Perch sia possibile usare il Dialer.exe per effettuare chiamate telefoniche, necessario disporre di un
modem con gli innesti PHONE e LINE, come nello schema che vediamo sotto:

Nell'innesto LINE inseriremo il cavetto che ci collegher alla linea telefonica, mentre in PHONE
collegheremo il cavetto del telefono (quello che normalmente v direttamente alla linea telefonica).
In questo modo la doppia presa funziona come bypass: se il modem non sar in funzione, potremo
usare il telefono normalmente, sia per chiamare che per ricevere. Quando dal Dialer useremo dal
http://ennius.interfree.it/ Pagina 79
MANUALE VBA X EXCEL
men Telefono/Componi, apparir una finestra come quella sotto, dove dovremo selezionare
"Chiamata telefonica" da "Modalit chiamata", indi premere il pulsante "Effettua chiamata". Apparir
sul video, in alto a sinistra, la finestra di "Chiamata in corso" ed una finestrina con un pulsante "Alza il
Ricevitore". Quando appare la scritta "Connessione effettuata", immediatamente potremo premere
"Alza il Ricevitore" e contemporaneamente alzare la cornetta del telefono e iniziare a parlare. La
chiamata dal computer via telefono sar in corso..

http://ennius.interfree.it/ Pagina 80
MANUALE VBA X EXCEL
Chiamare usando il telefono da Excel (con modem),
ma composizione automatica di un numero di telefono presente in un elenco sul foglio di lavoro.
Presento delle istruzioni che ho trovato e rese freeware (riporto il testo originale in inglese), adattate e
modificate da me per l'utilizzo in una cartella di Excel.

Il testo originale:
'AutoDial - Telephone dialer demo program
'Copyright (c) 1996-97 SoftCircuits
'Redistributed by Permission.
'This Visual Basic 5.0 example program demonstrates how an application
'can dial a telephone number under Windows 95 using Assisted Telephony
'which is a subset of TAPI. This code is simple because it relies on a
'call manager applet to perform the actual dialing.
'This program may be distributed on the condition that it is
'distributed in full and unchanged, and that no fee is charged for
'such distribution with the exception of reasonable shipping and media
'charged. In addition, the code in this program may be incorporated
'into your own programs and the resulting programs may be distributed
'without payment of royalties.
'This example program was provided by:
' SoftCircuits Programming
' http://www.softcircuits.com
' P.O.Box 16262
' Irvine, CA 92623
' Downloaded from http://surf.to/VbArea

Il progetto su citato si basa sull'uso delle librerie TAPI32.DLL, che sono le stesse utilizzate dal Dialer.exe
citato nel paragrafo precedente.
Ma vediamo come gestire le istruzioni. Visto che avremo necessit di disporre di un elenco telefonico
dal quale attingere i numeri da chiamare, bisogner creare una "Rubrica" con nominativo e relativo
numero telefonico, posta su un foglio di lavoro. Poi useremo una UserForm con una casella combinata
che "peschi" i dati, su due colonne, presenti nella "rubrica". Con la selezione di un nominativo,
otterremo che in una textbox compaia il numero correlato, e con un pulsante attiveremo la routine
che chiamer il dialer usando come numero da comporre il numero presente nella textbox. Un
semplice controllo che la textbox non sia vuota, impedir l'esecuzione della routine.
Istruzioni da inserire nella sezione Generale - Dichiarazioni della UserForm

Option Explicit

Private Declare Function tapiRequestMakeCall& Lib "TAPI32.DLL" (ByVal


DestAddress$, ByVal AppName$, ByVal CalledParty$, ByVal Comment$)
'Questa tutta una riga
Private Const TAPIERR_NOREQUESTRECIPIENT = -2&
Private Const TAPIERR_REQUESTQUEUEFULL = -3&
Private Const TAPIERR_INVALDESTADDRESS = -4&

http://ennius.interfree.it/ Pagina 81
MANUALE VBA X EXCEL
Istruzioni da inserire nell'apertura della UserForm per assegnare alla ComboBox1 il range di celle che
former il RowSource (elenco nomi e numeri che nell'esempio pongo in A1:B10)

Private Sub UserForm_Activate()


ComboBox1.RowSource = "A1:B10"
End Sub

Impostazione delle "propriet" della ComboBox perch ci mostri due colonne: colonna A con i nomi e
colonna B con i numeri. Le propriet interessate sono:
ColumnCount - che andr impostata a 2 (imposta a due le colonne visualizzate nella combobox)
BoundColumn - che andr impostata a 2 (Identifica la fonte dati di un controllo ComboBox a colonne
multiple. Il valore indicato (in questo caso 2) assegna al controllo il valore della colonna specificata. Le
colonne vengono numerate a partire da 1).

e questo l'aspetto dell'elenco sul foglio e della ComboBox a due colonne in cui si notano i nomi e
relativi numeri:

Poich avremo bisogno che selezionando un nominativo nella ComboBox, nella TextBox1 compaia il
numero associato e presente nella seconda colonna della stessa combo, useremo l'evento Change
della ComboBox indicando per quale colonna ci interessa (BoundColumn) ma sfruttando
l'argomento Value anzich Text (con Text verrebbe restituito il nome e non il numero di colonna. Con
Value si identifica il numero di colonna assegnato a BoundColumn, indipendentemente dal fatto che
nella colonna siano presenti numeri o testo )

Private Sub ComboBox1_Change()


ComboBox1.BoundColumn = 2
TextBox1 = ComboBox1.Value
TextBox1.SetFocus
End Sub

e questo il risultato:

http://ennius.interfree.it/ Pagina 82
MANUALE VBA X EXCEL

E queste sono le istruzioni collegate al pulsante "Componi..." , chiamato cmdDial:

Private Sub cmdDial_Click()


'controllo se la textbox1 vuota, allora avviso ed esco dalla routine
If TextBox1 = "" Then
MsgBox "Seleziona il Nominativo da chiamare o scrivi un numero di
telefono"
Exit Sub
End If
'inizio delle istruzioni originali da me riportate
Dim buff As String
Dim nResult As Long

'Invoke tapiRequestMakeCall. If tapiRequestMakeCall returns 0, the


'request has been accepted. It is up to the call manager application
'to do any further work. The second-to-last argument should be
'changed to be the name of the person you are dialing.
'riga sotto: modifica con TextBox1(casella dove si trova il numero da
chiamare) assegnata a nResult
nResult = tapiRequestMakeCall&(Trim$(TextBox1), CStr(Caption), "Test
Dial", "")
'Display message if error
If nResult <> 0 Then
buff = "Error dialing number : "
Select Case nResult
Case TAPIERR_NOREQUESTRECIPIENT
buff = buff & "No Windows Telephony dialing application is running and
none could be started."
Case TAPIERR_REQUESTQUEUEFULL
buff = buff & "The queue of pending Windows Telephony dialing requests
is full."
Case TAPIERR_INVALDESTADDRESS
buff = buff & "The phone number is not valid."

http://ennius.interfree.it/ Pagina 83
MANUALE VBA X EXCEL
Case Else
buff = buff & "Unknown error."
End Select
MsgBox buff
End If
End Sub

http://ennius.interfree.it/ Pagina 84
MANUALE VBA X EXCEL
Codici a barre in Excel.
Premesso che non uso e non so usare le procedure per utilizzare la conversione di stringhe numeriche o
alfanumeriche in codice a barre, ho trovato un sito che interesser tutti coloro che ne sono in cerca.
Questo sito propone loro soluzioni che si basano sull'uso di Funzioni specifiche per la conversione, e che
sono, da quanto letto, liberamente fruibili purch non si alteri o modifichi il codice compilato. E' infatti
possibile scaricare dal sito un file zip d'esempio. Solo che per poter veramente funzionare, necessario
ACQUISTARE i fonts necessari da installare sul sistema operativo in modo che le Funzioni trovino i fonts
necessari per eseguire la conversione. Poich la cosa di per s molto interessante, segnalo questo
sito, tutto in inglese, anche se ben strutturato e con chiare indicazioni sulle modalit operative; questo
l'indirizzo:
http://www.bizfonts.com/vba/

Questa un'immagine della homepage del sito:

ed un'immagine di come lavora la funzione con il font adatto installato (AdvC128b) :

http://ennius.interfree.it/ Pagina 85
MANUALE VBA X EXCEL
Colore dei caratteri (font)
Questa routine simile alla precedente, consente di ottenere un colore carattere diverso per ogni
variabile impostata, in modo da evidenziare, appunto con colore diverso, lettere, numeri, parole o
frasi. Come la precedente potr essere impostata con valori preimpostati nel codice, o assegnati a
variabili inserite in opportune celle. La variante principale rispetto alla precedente, che dovr essere
inserita nell'evento SelectionChange del foglio di lavoro. Supponiamo quindi di avere delle lettere che
vogliamo evidenziare con colori diversi, questa la routine: (in verde i commenti)

Private Sub Worksheet_SelectionChange(ByVal Target As Range)


Dim CL As Object
For Each CL In Range("A1:F100") 'per ogni cella in A1:F100
If CL.Value = "A" Then 'se il valore della cella uguale ad A
CL.Font.ColorIndex = 3 'mi metti il colore del carattere uguale a
rosso
ElseIf CL.Value = "B" Then 'se invece il valore uguale a B ecc.ecc
CL.Font.ColorIndex = 4
ElseIf CL.Value = "C" Then
CL.Font.ColorIndex = 8
ElseIf CL.Value = "D" Then
CL.Font.ColorIndex = 9
ElseIf CL.Value = "E" Then
CL.Font.ColorIndex = 5
ElseIf CL.Value = "F" Then
CL.Font.ColorIndex = 7
End If
Next
End Sub

Appena dopo aver scritto la lettera e confermato con "invio", si attiva la routine e se la lettera
corrisponder ad una di quelle riportate nelle istruzioni, si colorer con il colore scelto. In questa
sezione, al paragrafo "Colori e Colorindex" potrete trovare la tabella indice/colori.

http://ennius.interfree.it/ Pagina 86
MANUALE VBA X EXCEL
ComboBox, ListBox, Label e Image :
Ovvero: come utilizzare una ComboBox o una ListBox per visualizzare delle immagini (foto) in un
controllo "Image" o in una Label (etichetta).
Abbiamo visto nel paragrafo precedente, come "caricare" con dati una ComboBox o una ListBox:
sfruttando la propriet "RowSource", alla quale va associato il riferimento alle celle che contengono i
dati da visualizzare.
In questo esercizio ci occupiamo di come associare la selezione di un dato presente nel "menu" dei
due controlli, con la comparsa di un immagine associata al dato stesso. Per poter visualizzare delle
immagini necessario di disporre di due "controlli" (o "oggetti") presenti nella "casella degli strumenti"
tipica di una UserForm: il controllo "Image", che grazie alle sue "propriet" consente una migliore
gestione di come visualizzare una determinata foto o immagine, oppure di una normale "Label" che
offre decisamente poche possibilit. Vediamo le caratteristiche di questi due controlli:
Controllo Image - propriet:

A destra, la finestra delle propriet di un controllo


Image: tre sono le propriet pi importanti:
Picture: a lato andrebbe scritto il percorso
completo che porta all'immagine da visualizzare,
ma che invece gestiremo via codice.
PictureAlignment: di default impostato su 2, cio
con l'immagine piazzata nel centro del controllo.
PictureSizeMode: cio il modo con cui la foto
verr visualizzata, e quindi:
fmPictureSizeModeClip indica che si desidera
visualizzare l'immagine con le dimensioni e
l'ingrandimento originali. Se il controllo Image ha
dimensioni inferiori rispetto all'immagine, verr
visualizzata soltanto la parte dell'immagine che
rientra nel controllo.
L'impostazione fmPictureSizeModeStretch
ingrandisce l'immagine verticalmente e
orizzontalmente, fino a farle raggiungere i margini
del contenitore o del controllo.
fmPictureSizeModeZoom ingrandisce l'immagine
fino a quando questa non raggiunge i margini
orizzontali oppure i margini verticali del del
controllo. Se l'immagine raggiunge prima i margini
orizzontali, lo spazio rimanente tra l'immagine e i
margini verticali rester vuoto. Se l'immagine
raggiunge prima i margini verticali, lo spazio
rimanente tra l'immagine e i margini orizzontali
rester vuoto.

PictureTiling: di default impostata a False. Se le dimensioni di un'immagine sono inferiori a quelle del
controllo che la contengono, possibile affiancare pi copie dell'immagine nel controllo.

La modalit di affiancamento dipende dall'impostazione corrente delle propriet PictureAlignment


e PictureSizeMode.

Se ad esempio PictureAlignment impostata su fmPictureAlignmentTopLeft, la disposizione inizia


nell'angolo superiore sinistro e l'immagine viene ripetuta verso destra e verso il basso nel form o nella
pagina. Se PictureSizeMode impostata su fmPictureSizeModeClip, quando l'ultima immagine
affiancata non rientra completamente nei margini del controllo, tale immagine verr ritagliata

Controllo Label. Le propriet di una Label interessate a ricevere un immagine sono in pratica due:
La propriet Picture (gi vista sopra)
http://ennius.interfree.it/ Pagina 87
MANUALE VBA X EXCEL
La propriet PicturePosition, che di default impostata a : fmPicturePositionAboveCenter e
che centra l'immagine all'interno della Label. 12 sono le impostazioni settabili, e invito i pellegrini a
scoprirle da soli.
Ma veniamo all'esempio di questo esercizio. In una zona del foglio di lavoro, creeremo un elenco che
former il RowSource della ComboBox o della ListBox. Le ho usate tutte e due solo per mostrare le
istruzioni usate che comunque differiscono di poco, e perch la destinazione delle immagini collegate
all'elenco richiamato dalla ListBox sar la Label1. Il controllo Image supporta i seguenti formati di file:
*.bmp - *.cur - *.gif - *.ico - *.jpg - *.wmf

Condizione necessaria sar comunque di definire una cartella che conterr le immagini, e sar
opportuno chiamare le immagini con un nome che sar lo stesso che scriveremo nel nostro elenco sul
foglio di lavoro. Io ho chiamato le immagini : foto1.ipg, foto2.jpg, ecc.ecc. mentre nell'elenco ho usato
solo il nome: foto1, foto2, ecc. senza estensione: in questo modo nelle istruzioni imposto una sola volta il
formato dell'estensione: .jpg. Vediamo le istruzioni:

Nell'UserForm_Activate faccio caricare le liste dei controllo ComboBox e ListBox :

Private Sub UserForm_Activate()


ComboBox1.RowSource = "A1:A10"
ListBox1.RowSource = "A1:A10"
End Sub

Il comando per il caricamento dell'immagine nel controllo Image, si avvale della funzione LoadPicture
seguita dall'indicazione del percorso dove risiede l'immagine. Poich dovremo poter caricare pi
immagini a scelta, uso una variabile ( X ) per definire di volta in volta il nome che verr selezionato nella
ComboBox, sfruttando quindi l'evento ComboBox_Click per inserire le istruzioni, queste:

Private Sub ComboBox1_Click()


Dim X
X = ComboBox1.Text
Image1.Picture = LoadPicture("C:\Temp\" & X & ".jpg")
End Sub
Per la ListBox stesso discorso, con poche varianti, in particolare la destinazione che una Label:
Private Sub ListBox1_Click()
Dim X
X = ListBox1.Text
Label1.Picture = LoadPicture("C:\Temp\" & X & ".jpg")
End Sub

E questa un immagine dei risultati: frecce verdi per ListBox1 e Label1, frecce rosse per ComboBox1 e
Image1. Nella colonna A vediamo l'elenco che forma il RowSource:

http://ennius.interfree.it/ Pagina 88
MANUALE VBA X EXCEL

http://ennius.interfree.it/ Pagina 89
MANUALE VBA X EXCEL
ComboBox : ordinare la lista dei dati.

Una delle domande che spesso mi viene rivolta : come eliminare gli spazi vuoti dall'elenco di una
ComboBox (delle ActiveX); spazi vuoti rappresentati dalle celle senza dati presenti nel range assegnato
alla propriet ListFillRange ,se la combo inserita sul foglio di lavoro, o dalla propriet RowSource se la
combo inserita in una UserForm. Il discorso vale comunque anche per le ListBox.
Vedremo anche come far caricare una sola volta i dati se questi sono doppi. Ma diamo un occhiata
ad un esempio di un elenco preparato ad hoc:

Come si nota, i dati nella colonna B (da B5 in gi) non sono in righe contigue, e la ComboBox che
"pesca" la lista (con la propriet ListFillRange) in questo range, presenta analogamente un elenco con
spazi vuoti. La cosa di per se non rappresenta un errore, ma pu dare fastidio dover scorrere un men
pi lungo, alla ricerca del valore voluto. Inoltre i dati nel men, rispecchiando fedelmente l'origine dati,
non sono in ordine alfabetico, cosa che ci farebbe piacere specie con elenchi lunghi dove
risulterebbe pi veloce spostarsi ad una determinata lettera iniziale. Qualcuno potrebbe obiettare che
basterebbe creare un ordinamento sulla tabella di origine, per vederli in ordine anche nella
combobox, ma esistono molti casi in cui questo non possibile, specie con elenchi impostati su chiavi
che non sono le stesse dei dati richiamati dalla combobox, o ancora casi in cui l'inserimento di dati
nella tabella avviene in progressione, senza poter determinare un ordine di inserimento basato sui dati
richiamati nella combobox. Insomma, qualunque sia il motivo, andiamo avanti.
Un modo abbastanza veloce e semplice per la nostra esigenza pu essere questo:
Copiare in una altra colonna del foglio, in una colonna fuori vista (io user la colonna H nell'esempio), i
dati contenuti nella colonna B.
Applicare un ordinamento ascendente su questa colonna (la H) per ordinare alfabeticamente i nomi.
Con questo passo le celle vuote vengono automaticamente accodate all'elenco che si ordiner.
Assegnare questa colonna (H) come ListFillRange della ComboBox, sfruttando End per reperire l'ultima
cella occupata. In questo modo il nostro elenco sar depurato dagli spazi vuoti, e con i nomi in ordine
alfabetico.
Queste sono le immagini della ComboBox "epurata" e ordinata e della nuova lista che si crea nella
colonna H

http://ennius.interfree.it/ Pagina 90
MANUALE VBA X EXCEL

Ed ora vediamo come procedere, e poi le istruzioni, che ho posizionato nell'evento Click della
ComboBox1. In verde le spiegazioni.
iniziamo ad assegnare, in "modalit progettazione" (che si attiva appena inserita la ComboBox sul
foglio), nella finestra delle sue propriet, oltre alla LinkedCell, anche un range di celle alla propriet
ListFillange. Operazione NECESSARIA per inizializzare un elenco nella stessa combo, altrimenti sarebbe
vuota e non si genererebbe n l'evento Click, n l'evento Change necessari ad attivare le istruzioni,
oppure potremmo sfruttare l'evento Workbook_Open per "caricare" la lista della combo box, con
un'istruzione tipo:

Private Sub Workbook_Open()


Worksheets("Foglio1").ComboBox1.ListFillRange = "B5:B100"
'e gi che ci siamo, impostiamo anche la LinkedCell
Worksheets("Foglio1").ComboBox1.LinkedCell = "B2" 'o la cella che
vorrete
End Sub

Non ha importanza il range che viene caricato in quanto al primo click nella lista della combobox
otterremo l'attivazione della macro e dell'ordinamento.

Private Sub ComboBox1_Click()


'sotto. "puliamo" la ListFillRange della Combobox
ComboBox1.ListFillRange = ""
'sotto : puliamo la colonna H predisponendola alla copia del nuovo
elenco
ActiveSheet.Range("H:H").ClearContents
'sotto : impostiamo con "zona" il range che dovr essere copiato;
poich non possibile 'usare End per determinare la fine elenco,
dovremo assegnare un numero di celle che 'preveda successivi
inserimenti di dati
Set zona = Range("B5:B100")
zona.Select 'si seleziona il range con i dati e le celle vuote (zona)
zona.Copy Range("H5") 'e la si copia nella colonna H a partire da H5
'sotto : poich avremo una copia che contiene celle vuote anche in H,
non potremo usare 'End per gli stessi motivi, assegneremo noi un range
che copra quello di origine dati, e lo 'selezioniamo
Range("H5:H100").Select
http://ennius.interfree.it/ Pagina 91
MANUALE VBA X EXCEL
'sotto: ora si esegue l'ordinamento sulla selezione (H)
Selection.Sort Key1:=Range("H5"), Order1:=xlAscending, Header:=xlGuess,
_
OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom
'sotto: ora che le celle vuote sono tutte finite a fine elenco,
possiamo usare End per 'reperire l'ultima cella con i dati, ed
assegniamo a due variabili, gli indirizzi della cella 'iniziale ( x ) e
finale ( y )
x = Cells(5, 8).Address
y = Cells(5, 8).End(xlDown).Address
'sotto : ora con i riferimenti esatti alle celle, carichiamo la
ListFillRange della combobox
ComboBox1.ListFillRange = "" & x & ":" & y & ""
Range("B2").Select ' poi selezioniamo una cella per deselezionare
l'area in H
End Sub
Se invece vorremo una lista che non preveda le voci doppie, dovremo inserire nella precedente
routine, altre istruzioni per l'eliminazione dei doppioni. (routine peraltro gi presente in questa sezione,
articolo "Eliminare dati doppioni". Vediamo sotto come integrare le due serie di istruzioni. Non ripeto le
spiegazioni:
Private Sub ComboBox1_Change()
ComboBox1.ListFillRange = ""
ActiveSheet.Range("H:H").ClearContents
Set zona = Range("B5:B100")
zona.Select
zona.Copy Range("H5")
Range("H5:H100").Select
Selection.Sort Key1:=Range("H5"), Order1:=xlAscending, Header:=xlGuess,
_
OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom
'sotto, inizia il controllo dei doppioni, nel caso venga trovato un
dato doppio, viene 'cancellata la CELLA
Set currentCell = Worksheets("Foglio1").Range("H5")
Do While Not IsEmpty(currentCell)
Set nextCell = currentCell.Offset(1, 0)
If nextCell.Value = currentCell.Value Then
currentCell.Cells.Delete
End If
Set currentCell = nextCell
Loop 'poi si continua come sopra
x = Cells(5, 8).Address
y = Cells(5, 8).End(xlDown).Address
ComboBox1.ListFillRange = "" & x & ":" & y & ""
Range("B2").Select
End Sub
http://ennius.interfree.it/ Pagina 92
MANUALE VBA X EXCEL
ComboBox e ListBox.
Ovvero: come caricare una ListBox selezionando una voce nella Combobox
Le ComboBox e ListBox che useremo fanno parte delle ActiveX, e le troviamo nella "Casella degli
Strumenti" o "Strumenti di controllo" (a seconda delle versioni di Excel) dal men "Visualizza/Barre degli
strumenti". Questi due "oggetti" sono diversi dalle ComboBox e ListBox presi da "Moduli".
Gli "oggetti" facenti parte delle ActiveX sono inseribili sia in un foglio di lavoro, sia in una UserForm,
anch'esso un "oggetto" inseribile ma dall'Editor di Visual Basic (VBE). Tutti gli "Oggetti" possiedono delle
"propriet", ed una di queste propriet presenti sia nelle ComboBox sia nelle ListBox quella che ci
consente di determinare la provenienza dei dati che saranno poi visualizzati nelle stesse. A secondo il
posizionamento di questi due "controlli" (su foglio o su UserForm) , cambia il nome della "propriet",
anche se il "funzionamento" il solito:
con oggetto sul foglio di lavoro la propriet : ListFillRange
con oggetto su una UserForm la propriet : RowSource
Entrambe queste propriet sono programmabili, sia scrivendo direttamente nella finestra delle loro
"propriet" il percorso della zona che contiene i dati da visualizzare, sia attraverso istruzioni inserite in un
evento.
Dopo queste premesse, veniamo al problema preso come esempio. Supponiamo di avere una tabella
sul foglio1 (o elenco, o database che dir si voglia), dove sono inseriti degli articoli, con codice articolo
(campo necessariamente univoco), descrizione, prezzo, ecc. Ogni articolo per formato da
sottocategorie, ognuna con caratteristiche diverse, e non tutti gli articoli possiedono lo stesso numero
di sottocategorie. Non quindi pensabile di realizzare un'unica tabella che comprenda tutte queste
disponibilit. Ci affideremo quindi ad un secondo foglio (Foglio2) dove costruire la nostra tabella delle
sottocategorie. Questa tabella dovr necessariamente possedere il campo "Codice articolo", un
campo "categoria" (che potr essere a sua volta formata da un codice), ed altri dati correlati che ne
identifichino le diversit. Il problema nasce quando vorremo, per un determinato articolo, visualizzare
tutti i dati pertinenti l'articolo, presenti nelle sottocategorie. Ovviamente questo esercizio si presta ad
un'infinit di varianti, sia come tipo di dati sia come scelta dei campi correlati che vorremo vedere, se
ci pensiamo bene, corrisponde un p a "filtrare" i dati, anche se con tecniche diverse dall'uso del "Filtro"
e con risultati diversi.
Stabilito qual' il problema, vediamo come affrontarlo : useremo una UserForm, che chiameremo da
un pulsante posto sul Foglio1, e nella U.F. inseriremo una Combobox ed una Listbox. Useremo l'apertura
della
UserForm (UserForm1_Activate) per "caricare" l'elenco nella ComboBox1 assegnando via codice, la
zona che contiene i "Codici Articolo" della nostra tabella, cie la colonna A, dalla riga 1 fino a dove
vorremo, usando questa istruzione:

Private Sub UserForm_Activate()


'carico la lista degli articoli nella colonna A del foglio1
ComboBox1.RowSource = ("A1:A10")
End Sub

e questo sar l'effetto sulla Combobox (a sinistra l'elenco sul foglio 1)

http://ennius.interfree.it/ Pagina 93
MANUALE VBA X EXCEL

A questo punto dovremo sviluppare delle istruzioni che ci consentano di ottenere , selezionando uno
degli articoli presenti nella lista, che nella ListBox vengano caricate tutte le occorrenze relative al
codice scelto. Il sistema che presento semplice: faccio cercare nella tabella sul Foglio2, tutti i codici
articolo uguali a quello selezionato. Individuato un articolo, faccio estrarre i dati che mi interessano
(nella stessa riga ma nelle due colonne a destra) e li copio in una zona appositamente assegnata, sullo
stesso Foglio2 (colonne G e H), con ricerca della prima riga libera, in modo da comporre un elenco.
Questa zona con l'elenco cos composto, la zona che assegno alla propriet RowSource della
ListBox. Un'altra propriet della ListBox da sfruttare, la "ColumnCount" normalmente impostata a 1 e
che determina in numero delle colonne visibili nella Listbox. Noi imposteremo questa propriet a 2,
perch due sono i campi che abbiamo deciso di estrarre. Un'altro accorgimento da usare, sar quello
di pulire la zona che forma il RowSource della Listbox, in modo che ad ogni selezione nella ComboBox
si azzeri il contenuto della ListBox e si rinfreschi con nuovi dati (Refresh).
Per queste istruzioni sfrutteremo l'evento Click della Combobox:

Private Sub ComboBox1_Click()


'questo sotto evita il saltellamento a schermo
Application.ScreenUpdating = False
'faccio pulire la zona che uso come estrazione dati
Worksheets(2).Range("G1:H10").ClearContents

Dim CL As Object 'dichiaro la variabile CL come Object


Worksheets(2).Select 'seleziono il foglio2
'per ogni cella nel range A1:A20 foglio2
For Each CL In Worksheets(2).Range("A1:A20")
'se il valore nella cella (CL) uguale al valore selezionato nella
combobox
If CL = ComboBox1.Text Then
'allora seleziono le due celle a destra di quella trovata
Range(CL.Offset(0, 1), CL.Offset(0, 2)).Select
'copio tutte e due i valori
Selection.Copy
'cerco la prima riga libera a partire dalla riga 1 e nella colonna 7
(la G )
Dim iRow As Integer
iRow = 1

http://ennius.interfree.it/ Pagina 94
MANUALE VBA X EXCEL
While Cells(iRow, 1).Columns(7).Value <> ""
iRow = iRow + 1
Wend
'trovata la riga con la cella vuota, incollo i dati copiati con
Selection.Copy (sopra)
Selection.Copy Cells(iRow, 1).Columns(7)

End If
Next
'finito il ciclo di ricerca, carico la listbox con i dati ora contenuti
nelle colonne G e H
ListBox1.RowSource = "Foglio2!G1:H10"
'poi ritorno sul foglio1
Worksheets(1).Select
End Sub

e questo sar il risultato (a sinistra la zona del Foglio2 con la seconda tabella)

Appare evidente che i range usati nell'esempio sono modificabili a piacere e sar possibile usare
anche la funzione End per non determinare a priori la lunghezza di un elenco.

http://ennius.interfree.it/ Pagina 95
MANUALE VBA X EXCEL
ComboBox (ActiveX) collegata ad un Range su Foglio di un'altra Cartella.
A volte si ha la necessit di richiamare un elenco di dati che risiedono su un foglio diverso da quello sul
quale stiamo lavorando, e vogliamo usare una ComboBox (da "Casella degli Strumenti" o "Strumenti di
controllo") per avere un riepilogo di cui desideriamo operare una scelta (Men lista). La propriet di
una ComboBox, posizionata sul foglio di lavoro, interessata a reperire il range di celle (sempre in
verticale) da mostrarci nel men a tendina della stessa C.box, la propriet ListFillRange(cambia
se usiamo ua C.box su una UserForm, in questo caso RowSource). La sintassi da usare nella Finestra
delle Propriet della ComboBox, (in "Modalit Progettazione", visibile nell'Editor di Visual Basic), per
ListFillRange, la seguente (esempio):

ListFillRange A1:A100

Ovviamente il range riferito al foglio di lavoro nel quale stata inserita la ComboBox, ed sufficiente
indicare solo i Riferimenti alle celle.
Quando invece si usa la Combobox inserita su un Foglio, ma vogliamo "caricare" un range di celle che
sono per su un altro foglio della stessa cartella di lavoro, bisogna anteporre al range, l'indicazione di
quale foglio conterr detto range, seguito da un punto esclamativo ( ! ). Esempio:

ListFillRange Foglio2!A1:A100

E' possibile per cercare e caricare un elenco di dati che risiedono su un'altro Foglio di un'altra Cartella
di lavoro. Condizione necessaria sar che ANCHE l'altra Cartella di lavoro sia aperta.
Attenzione alla sequenza con la quale apriremo le due cartelle: dovremo per PRIMO aprire la cartella
che contiene i dati richiamati dalla ComboBox presente sull'altra cartella, e POI aprire quest'ultima. Ma
vediamo la sintassi da usare in questo caso per istruire il ListFillRange della combobox:

ListFillRange '[Pippo.xls]Foglio1'!B10:B50

Come si nota, il riferimento viene scritto riportando, tra Parentesi Quadre, il nome del file che porta i
dati, poi l'indicazione del Foglio dove risiede il range dei dati, il punto esclamativo, indi i riferimenti al
range di celle. Inoltre la stringa NomeFile/Nome foglio, va inserita tra apici semplici ( ' ).

Nell'eventualit che si apra invece per primo il foglio dove risiede la combobox, apparir all'apertura,
una finestra che ci chiede se vogliamo aggiornare i dati : a questo punto, sar indifferente premere
"aggiorna" o "non aggiornare" , visto che Pippo.xls ancora chiuso e i dati chiamati dalla combobox
non sono disponibili.
E per possibile aprire anche Pippo.xls, selezionare il foglio che contiene la combobox, che non si
aggiorner perch gi aperto, ma predisporre un CommandButton ad quale affidare la seguente
routine :

Private Sub CommandButton1_Click()


ComboBox1.ListFillRange = " ' [Trova.xls]Foglio1'!A1:A5"
End Sub

Baster un click sul CommandButton e verr ripristinato il collegamento, a fogli aperti, e la combobox
riporter ora l'elenco voluto.

Anche per le Caselle Combinate (simili a ComboBox, ma prese dalla finestrina "Moduli"), dove si usa,
anzich il ListFillRange di cui sono sprovviste, l' "Intervallo di input" (da: Formato Controllo) come
indicazione dell'area dati da "caricare", andr scritto il percorso che identifica l'area di provenienza
dati in questa maniera:
http://ennius.interfree.it/ Pagina 96
MANUALE VBA X EXCEL
'[Trova.xls]Foglio1'!A1:A5
Per le ComboBox ActiveX poste su UserForm, ricordo che la propriet che identifica l'origine dati non
la ListFillRange ma RowSource. Il discorso non cambia, e potremo usare la stessa sintassi:

ComboBox1.RowSource = " ' [Trova.xls]Foglio1'!A1:A5"

http://ennius.interfree.it/ Pagina 97
MANUALE VBA X EXCEL
Un CommandButton personalizzabile. (Controllo ActiveX)

Per tutti coloro che usando CommandButton su UserForm, vogliano renderli pi carini, facendo
cambiare colore ed effetto (ma anche cambiare ev. immagini sul pulsante stesso) a secondo
dell'azione che compiamo sul commandbutton stesso (al passaggio del mouse o sul click), presento un
controllo ActiveX reperito sul Web, e rilasciato freeware, cio di libero utilizzo, che risulta di facile
settaggio per ottenere i risultati voluti.

Ma vediamo come inserirlo e le sue propriet.


Si tratta di un ocx e si chiama : MyHover.ocx: una volta scaricato e decompresso, va posto nella
cartella System di Windows (o System32, a secondo delle versioni di Windows). Una volta aperto Excel,
dal suo editor di visual basic, inseriremo una UserForm, e dalla sua casella degli strumenti, cliccandoci
destro di mouse, sceglieremo : "Controlli aggiuntivi":

si aprir la finestra per la selezione dei controlli disponibili e su questa metteremo un segno di spunta al
controllo "MyHoverButton Button" (nell'immagine vediamo anche il percorso dove risiede il controllo.
(seconda freccia in basso))

Se il controllo non appare nella finestra "Controlli aggiuntivi", bisogner seguire un altro percorso: dal
men "Strumenti" del VBE, scegliere la voce "Riferimenti", si aprir la finestra dei "Riferimenti disponibili",
sceglieremo il pulsante "Sfoglia" che aprir la finestra "Aggiungi riferimento", che ci mostrer i file
presenti nella cartella System (o System32); in questa finestra, nel men inferiore, quello relativo al "Tipo
di file", dovremo selezionare la voce "Controlli ActiveX (*.ocx)"; a questo punto nella finestra dei file
compariranno tutti i file .ocx, cercheremo e selezioneremo MyHover.ocx e premeremo il pulsante "Apri".
Questa operazione porter il controllo scelto nella finestra "Riferimenti Disponibili", baster mettere un
segno di spunta al controllo voluto che sar quindi disponibile per essere "caricato" nella "casella degli
http://ennius.interfree.it/ Pagina 98
MANUALE VBA X EXCEL
strumenti" della UserForm. (icona rossa indicata da una freccia nella prima immagine). Cliccheremo
questa icona e, "trascinando" nella UserForm, otterremmo il nostro commandbutton:

Il commandbutton cos inserito avr tutte le propriet tipiche di un command button, con in pi la
possibilit di sceglie, oltre al colore e alla Caption di base:
un colore ed una Caption diversa quando si passer sul pulsante con il mouse, oppure:
un'immagine da inserire sfruttando la propriet "Picture" relativa
un colore ed una Caption diversa quando si premer il pulsante, oppure:
un'immagine da inserire sfruttando la propriet "Picture" relativa

Le propriet interessate sono quelle evidenziate


con le frecce, e di facile comprensione, comunque
vediamole insieme:
BackColor - il colore di base
Caption - la parola o frase che identifica l'azione
DownBackColor - il colore che sostituir il colore di
base all'atto della pressione sul pulsante.
DownCaption - la parola o la frase che apparir
all'atto della pressione sul pulsante.
DownPicture - un immagine che apparir all'atto
della pressione sul pulsante.
HoverBackColor - il colore che sostituir il colore di
base al passaggio del mouse.
HoverCaption - la parola o la frase che apparir al
passaggio del mouse
HoverPicture - un immagine che apparir al
passaggio del mouse
Picture - l'immagine scelta come base

Come vedete, un simpatico modo di abbellire i nostri lavori; questi tre esempi:

http://ennius.interfree.it/ Pagina 99
MANUALE VBA X EXCEL

http://ennius.interfree.it/ Pagina 100


MANUALE VBA X EXCEL
Usare un CommandButton (ActiveX) per una doppia istruzione.
Ovvero: come far eseguire allo stesso CommandButton due istruzioni alternate sfruttando l'evento
Click.
Tutte le operazioni eseguite tramite una routine vba non sono intercettabili dall'opzione "Annulla" del
men "Modifica/Annulla". Una volta che il codice vba stato eseguito, le istruzioni eseguite sono
permanenti e si potranno annullare solo se prevediamo un routine che esegua al contrario le stesse
istruzioni. A questo punto avremmo bisogno di un'altro commandbutton con le istruzioni per il ripristino,
ma si pu fare tutto con un solo commandbutton, sfruttando la sua propriet Caption. Sar sufficiente
creare un'istruzione condizionale ( If... Then ) che legga il valore della Caption e su questo valore
esegua l'istruzione appropriata. Il segreto di tutto : facciamo cambiare il valore della Caption al primo
Click sul commandbutton e lo ripristiniamo al secondo Click: in questa alternanza impostiamo le
condizioni che il codice legge, ed eseguir l'istruzione relativa. Facciamo un esempio, supponiamo di
voler cambiare il colore delle celle in un certo range, e poi di volerlo ripristinare ( un esempio banale,
ma serve allo scopo di vedere i passaggi) se necessario.
Per prima cosa, una volta inserito il CommandButton prendendolo da "Casella degli strumenti" o da
"Strumenti di controllo" ( a secondo le versioni di Excel), e quindi un "controllo" ActiveX, ci rechiamo
nell'editor di visual basic, in modalit "progettazione", e nella finestra delle propriet del
CommanButton, alla propriet Caption, assegniamo un nome, ad esempio "Pigia". Questa sar la
parola che vedremo scritta sul pulsante, e questa parola sar il valore di default assegnato al
commandbutton, ovvero all'apertura della cartella quello il nome con cui il pulsante si presenta. Ora
vediamo come compilare le istruzioni, da inserire nell'evento Click dello stesso CommandButton:

Private Sub CommandButton1_Click()


'si controlla il valore della Caption : se uguale a Pigia, si esegue
If CommandButton1.Caption = "Pigia" Then
'l'istruzione che colora di giallo il range di celle e
Range("C1:D10").Interior.Colorindex = 6
'ora rinomina la Caption in Annulla; in questo modo al prossimo click,
con la caption 'impostata ad "Annulla", verr eseguita
CommandButton1.Caption = "Annulla"
'con Else, questa istruzione, che
Else
'ripristina il colore togliendolo
Range("C1:D10").Interior.Colorindex = xlNone
'e rinomina la Caption Pigia
CommandButton1.Caption = "Pigia"
End If
End Sub
E' evidente che potr essere eseguita qualunque istruzione, compresa la sostituzione di valori e il
relativo ricalcolo.

http://ennius.interfree.it/ Pagina 101


MANUALE VBA X EXCEL
Conto alla rovescia (Countdown)
Un simpatico esercizio per crearsi un "Conto alla rovescia". Le istruzioni si basano sull'utilizzo della
funzione Timer, che ci consente di "temporizzare" delle istruzioni. Vogliamo infatti usare una cella (ma
anche una MsgBox) dove veder scorrere i secondi all'indietro fino ad un'ora X. Queste le istruzioni,
ottenute modificando un esempio preso dalla guida in linea.

Sub ContoRovescia()
'assegniamo ad una cella un valore espresso in secondi che rappresenta
il tempo massimo 'iniziale
Range("B1").Value = 60
10: 'indice riga a cui si ritorna per continuare il ciclo
Dim PauseTime, Start 'dimensionamento delle due variabili

PauseTime = 1 ' Imposta la durata espressa in secondi


Start = Timer ' Imposta l'ora di inizio.
Do While Timer < Start + PauseTime
DoEvents ' Passa il controllo ad altri processi.
Loop
'quindi ad ogni secondo trascorso temporizzato dal timer si sottrae 1
al valore presente 'nella cella B1 (sotto)
Range("B1").Value = Range("B1").Value - 1
'inseriamo l'istruzione: se B1 uguale a zero
If Range("B1").Value = 0 Then
'avvisiamo con un messaggio
MsgBox "L'ora X scoccata"
Exit Sub 'si esce dalla routine
End If
'altrimenti (se non siamo a zero in B1), si ritorna alla riga 10
GoTo 10

End Sub

Attenzione: con valori di PauseTime bassi (un secondo come nell'esempio), se si lavora sul foglio di
lavoro si interrompe in conto alla rovescia.

http://ennius.interfree.it/ Pagina 102


MANUALE VBA X EXCEL
Controllo immissione dati
Questa routine consente di verificare se i dati che vengono inseriti in una cella corrispondono a
parametri fissi stabiliti in precedenza. Facciamo un esempio: nella zona che comprende tutte le celle
da A1 a F100 vogliamo inserire solo lettere che corrispondano ad A, B, C, D, E, e che ci venga
segnalato immediatamente se scriviamo qualunque cosa che sia diversa: questa la routine da
inserire nell'evento Change del Foglio su cui lavoriamo: (in verde sono i commenti)

Private Sub Worksheet_Change(ByVal Target As Range)


Dim CL As Object

For Each CL In Range("A1:F100") 'per ogni cella nella zona A1:F100


If CL.Value = "" Then GoTo 10 'se la cella vuota passa a 10: Next
(la successiva)

If CL.Value = "A" Or CL.Value = "B" Or CL.Value = "C" _


Or CL.Value = "D" Or CL.Value = "E" Then
GoTo 10 'se la cella contiene una di queste queste lettere, vai
alla successiva
Else 'altrimenti
CL.Select 'seleziona la cella col valore diverso
MsgBox ("Errore.Valore non Ammesso!!") 'avvisami con questo messaggio
End If
10:
Next

End Sub

Appare evidente che potremo, modificando i parametri assegnati a CL.Value =, eseguire controlli sia
su lettere, sia su numeri, sia su frasi. Con questa soluzione avremo un controllo "predefinito" in quanto il
valore da controllare nelle celle inserito direttamente nel codice.
Se invece volessimo che il controllo fosse eseguito non su valori fissi perch "preimpostati", ma assegnati
da variabili, potremmo utilizzare delle celle (al di fuori del range su cui si esegue il controllo) nelle quali
potremmo inserire dei valori che possiamo variare a nostro piacimento. Per esempio potremo
assegnare le celle G1:G4 alla routine, e in queste celle scrivere ci che vogliamo sia usato come valore
di confronto. Un unico appunto: se in G1 scriviamo "pippo" (ed avremo inserito in alcune celle del
range A1:F100 la stessa parola), sostituendolo in G1 con "peppo", la routine trover "pippo" e lo
segnaler come errore. Comunque questa la routine da usare con valori variabili:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim CL As Object

For Each CL In Range("A1:F100") 'per ogni cella nella zona A1:F100


If CL.Value = "" Then GoTo 10 'se la cella vuota passa a 10: Next (la successiva)

If CL.Value = Range("G1").Value Or CL.Value = Range("G2").Value _


Or CL.Value = Range("G3").Value Or CL.Value = Range("G4").Value Then
GoTo 10 'se la cella contiene un valore uguale a questi Range, vai alla successiva
Else 'altrimenti
CL.Select 'seleziona la cella col valore diverso
MsgBox ("Errore.Valore non Ammesso!!") 'avvisami con questo messaggio
http://ennius.interfree.it/ Pagina 103
MANUALE VBA X EXCEL
End If
10:
Next

End Sub
In questo modo, ci che verr scritto nelle celle G1 ecc, sar usato come valore di confronto.

http://ennius.interfree.it/ Pagina 104


MANUALE VBA X EXCEL
Gestire Convalida usando il VBA
Visto l'interesse che desta l'utilizzo dello strumento Convalida, che non richiede assolutamente nessuna
istruzione in codice vba (di cui trovate tre diversi utilizzi sul sito, sezione "Formule"), era naturale che a
qualcuno venisse la curiosit di chiedermi "ma si pu gestire Convalida via vba?". E quindi in questa
pagina parleremo delle istruzioni che si possono usare per ottenere quello che in vba si chiama
"Validation". Prender come esempio quanto riportato in "Usare CONVALIDA (3)", per mostrare come si
possa ottenere lo stesso risultato con l'impiego del Vba. Senza stare a ripetere cosa vorremo ottenere
(basta leggere la pagina in "formule"), passo alla routine:
Sub MacroConvalida()

With Range("D2:D7").Validation
.Delete
.Add Type:=xlValidateWholeNumber, AlertStyle:=xlValidAlertStop, _
Operator:=xlBetween, Formula1:="1", Formula2:="6"
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = "inserire valore "
.ErrorTitle = "avviso"
.InputMessage = "valori ammessi compresi tra 1 e 6"
.ErrorMessage = "hai inserito un valore errato"
.ShowInput = True
.ShowError = True
End With
End Sub
Attenzione! La routine sopra, funziona solo con numeri interi, NON decimali, in base all'impostazione:
.Add Type:=xlValidateWholeNumber, se si volesse invece un controllo che intervenga per numeri
decimali, come nel caso di valuta Euro, andr sostituito WholeNumber con Decimal, cos:
.Add Type:=xlValidateDecimal
E' inoltre possibile assegnare dei valori variabili, usando il sistema di usare due celle del foglio di lavoro,
come "contenitori" dei valori che servono di confronto, e poi via codice, assegnando il valore di queste
celle a due variabili ( X e Y ), richiamare queste al posto di valori predefiniti nelle istruzioni Formula1:= e
Formula2:= ; sar necessario modificare anche la stringa assegnata ad "InputMessage" perch possa
presentare un messaggio aggiornato con i valori delle variabili, come nell'esempio sotto fatto per valori
decimali:
Sub MacroModificata()
Dim X, Y
X = Range("J1").Value 'J1 cella che conterr il valore minimo
Y = Range("K1").Value 'K1 cella che conterr il valore massimo
With Range("D2,E7,C3").Validation 'definizione delle celle per la convalida
.Delete
.Add Type:=xlValidateDecimal, AlertStyle:=xlValidAlertStop, _
Operator:=xlBetween, Formula1:=X, Formula2:=Y
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = "inserire valore "
.ErrorTitle = "avviso"
.InputMessage = "valori ammessi compresi tra " & X & " e " & Y & ""
.ErrorMessage = "hai inserito un valore errato"
.ShowInput = True
.ShowError = True
End With

End Sub

E questa la routine per togliere dalle stesse celle, il controllo convalida:


Sub TogliConvalida()

With Range("D2:D7").Validation
http://ennius.interfree.it/ Pagina 105
MANUALE VBA X EXCEL
.Delete
End With
MsgBox "E' stata tolta la convalida alle celle richieste"

End Sub
Alcune precisazioni. Si pu assegnare, come range di applicazione della Convalida, non solo un range
di celle contigue, come nell'esempio ( Range("D2:D7" ), ma anche celle "sparse", dove appunto ci
interessi eseguire un controllo, baster indicare nei riferimenti del Range, i riferimenti alle celle, separate
da una virgola, cos : Range("D1, C2, D3, F10, A1)" .
Poich le combinazioni del controllo convalida sono diverse, suggerisco di usare il "Registratore di
macro", Se avviate il registratore e poi scegliete i vari passaggi di Convalida, alla fine, premendo lo
stop del registratore, nell'editor di visual basic, nel Modulo che troverete, potrete leggere tutto il codice
corrispondente alle azioni da voi fatte e quindi vedere, imparare e modificare, se credete, le istruzioni
che il registratore ha compilato per voi. Registrate gente, registrate.

http://ennius.interfree.it/ Pagina 106


MANUALE VBA X EXCEL
Tipo di dati. Formati di Conversione del tipo di dati.
Conosciamo ed abbiamo gi visto in questa sezione, la funzione vba Format, che ha il compito di
predisporre il formato di un dato in modo che noi possiamo vederlo restituito con il formato che
abbiamo deciso.
Mi sono accorto che esiste una certa confusione di interpretazione sul comportamento di ci che in
realt otteniamo con la funzione Format in vba, e vorrei cercare di chiarire alcuni aspetti.
Quando siamo sul foglio di lavoro e scegliamo "Formato Celle", noi in realt scegliamo il "TIPO DI DATI"
che una cella dovr contenere, e nella finestra "Numero", una volta selezionato il Tipo di dato, nella
parte destra appare il tipo di Formato con il quale vogliamo che il dato ci venga mostrato nella cella.

E' quindi Excel che provvede, attraverso le nostre decisioni, ad impostare sia il TIPO di dato, sia il
FORMATO nella cella.
Quando ci troviamo a lavorare di codice, dovremo invece essere noi a compilare le necessarie
istruzioni sia per definire il formato, sia per il tipo di dati. Per quanto riguarda il formato, useremo la
funzione Format (vba) che ha esclusivamente il compito di predisporre il modo in cui un dato ci
appare, per esempio in una TextBox, o come il codice lo passa d una cella del foglio di lavoro. E'
soprattutto questa differenza tra Formato (Format) e Tipo di dati che genera confusione. In parole
povere questa istruzione:
TextBox1 = Format(TextBox1, "#,###.00")
determina SOLO il modo in cui il valore verr mostrato nella textbox o in una cella, ma NON dice
assolutamente ad Excel di che TIPO di dati viene passato dal vba. Per comunicare quindi ad Excel il
TIPO di dati, necessario dichiarare di che TIPO di dati si tratta. Questa operazione si chiama
"CONVERSIONE DEL TIPO DI DATI". Dovremo usare una sintassi specifica, per definire se un numero
intero o un numero con decimali, se testo, o una data, o un orario, ecc, in modo che il vba passi ad
Excel il dato facendogli capire di che cosa si tratta. Per fare questo possiamo procedere in diversi
modi:
Assegnare il Tipo di dati ad una variabile:
Dim MioValore As Double
MioValore = TextBox1.Value
Cells(1, 7).Value = MioValore

oppure, molto pi semplicemente, senza usare il dimensionamento, cos:


MioValore = TextBox1.Value
Cells(1, 7).Value = CDbl(MioValore)

o, pi veloce ancora:
Cells(1, 7).Value = CDbl(TextBox1)

Tutti questi esempi restituiscono tutti un valore Double, cio un numero con decimali, e anche senza il
Format nella Textbox, il dato che viene passato al foglio viene riconosciuto come Double e
corrisponderebbe all'azione che avremmo fatto sul foglio di lavoro scegliendo da "Formato Celle",
"Numero con decimali". Ovviamente l'impiego della funzione Format in abbinamento all'indicazione
del Tipo di dato, ci avrebbe consentito di decidere anche con quanti decimali il valore sarebbe stato
poi visualizzato nella cella. Esempio:
TextBox1 = Format(TextBox1, "#,###.00")
http://ennius.interfree.it/ Pagina 107
MANUALE VBA X EXCEL
Cells(1, 7).Value = CDbl(TextBox1)
oppure, in un unica istruzione:
Cells(1, 7).Value = CDbl(Format(TextBox1, "#,###.00"))
ed il valore restituito in G7 sar Double a due decimali anche se noi avremo 1354,8792

Quando si adopera "Tipi di dati" numerici, bisogna sempre ricordarsi che la textbox non pu restare
vuota, pena un errore di debug, (il vuoto per il vba NON corrisponde a zero) ma bisogna impostare un
istruzione tipo questa
If TextBox1 = "" Then TextBox1 = 0
e ovviamente va posizionata prima del comando di trasferimento al foglio.
If TextBox1 = "" Then TextBox1 = 0
Cells(1, 7).Value = CDbl(TextBox1)

Per quanto riguarda il Tipo di dati, la guida a questo proposito comunque ben fornita, solo che
bisogna conoscere come cercare. Nella guida dell'editor del visual basic, andare sull'indice, digitare :
Funzione, e nella finestra sotto pi grande (la 3) dove c' scritto: selezionare un argomento, scorrere
fino a trovere. "Funzioni di conversione del tipo", selezionare l'argomento, e sulla destra ve li trovate tutti.
E comunque i pi usati sono:
CDate - per indicare che si sta trasferendo una data, ed utile usare prima una variabile per definire il
formato data, esempio
MyStr = Format(TextBox1, "h:m:s")
Cells(1, 7).Value = CDate(MyStr)
CDbl - per tutti i numeri positivi o negativi con decimali (idem c.s. per definire il formato numerico)
CLng - per interi numerici
CInt - tipo di dati integer
CStr - tipo di dati stringa (formato testo)
Val - pi generico per numeri o testo (o solo numeri se presenti in una stringa)
Cells(1, 7).Value = Val(TextBox1)

http://ennius.interfree.it/ Pagina 108


MANUALE VBA X EXCEL
La procedura Indiceriga.
Utilizzo: Copia/Incolla con ricerca della prima riga libera per incollare.
Questa procedura non esiste come funzione predefinita in Excel e non documentata, quindi non
cercatela nella Guida in Linea. Si basa sul dimensionamento di una variabile: "Indiceriga". Esistono altre
procedure che consentono di "incollare" dati su fogli di lavoro, cercando la prima riga libera per
"scaricare" i dati precedentemente copiati, ma si basano su una ricerca (della prima riga libera), che
parte dall' ultima riga, e sale verso la prima: questo vuol dire che se noi avessimo destinato per
l'incollaggio, per esempio, la zona che va dalla prima alla 50esima riga, e nella riga 60 avessimo scritto
altri dati, l'incollaggio avverrebbe non nella zona che noi vorremmo (righe 1-50), ma al di sotto della
riga 60. La procedura che propongo, permette di "mirare" con esattezza la zona di destinazione, e qui,
cercare la prima riga libera per incollare i dati copiati, indipendentemente dalla presenza di dati in
altre righe del foglio di destinazione. I riferimenti alle celle di questo esempio dovranno ovviamente
essere adattati alle vostre esigenze, come pure il nome del/dei fogli (pincopallino). In verde sono i
commenti:
Sub CopiaIncolla()
'dichiaro la variabile Indiceriga
Dim Indiceriga As Integer
ActiveSheet.Range("A1:D1").Select 'seleziono le quattro celle da copiare(o
'quelle che vorrete) sul foglio attivo
Selection.Copy 'copio il contenuto

Sheets("pincopallino").Select 'poi vado al foglio su cui devo


incollare(incoller a 'partire dalla D2:G2)
For Indiceriga = 2 To 200 'dimensiono la lunghezza in righe in cui incollare
(dalla '2 alla 200)

'con il foglio di destinazione selezionato


With Worksheets("pincopallino").Cells(Indiceriga, 4) 'qui dico di iniziare con la
cella che parte nella '2 riga(di Indiceriga), ma nella colonna 4 (la D)
If .Value = "" Then GoTo 10 ' se trovo una cella vuota nella colonna D, passo
al '10:
End With

Next Indiceriga 'se ho trovato la cella 2 occupata (non vuota) passo alla
'successiva

Exit Sub

10: 'ho trovato una cella vuota e devo ripetere le selezioni per incollare
Sheets("pincopallino").Select
Cells(Indiceriga, 4).Select 'seleziono la prima riga vuota trovata Colonna D
Selection.PasteSpecial Paste:=xlValues, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=False 'incollo solo i valori, non eventuali formule

Application.CutCopyMode = False 'elimina il tratteggio delle celle copiate

'ed esco

End Sub

Per chi ha un minimo di conoscenza in Vba non risulter difficile adattare le istruzioni alle proprie
esigenze. La procedura lavora anche sul copia/incolla di pi righe: se si fosse selezionato A1:D5, cio
tutti i dati compresi dalla cella A1 alla D5 (cinque righe), il Paste (incollaggio) sarebbe avvenuto
occupando 5 righe vuote, in sequenza.

http://ennius.interfree.it/ Pagina 109


MANUALE VBA X EXCEL
Un'altra procedura per copiare/incollare.
Utilizzo: Copia/Incolla con ricerca della prima riga libera per incollare.
Questa procedura meno complessa della precedente, ed documentata in parte su Excel.
Riguarda la popriet End Select . Riporto la spiegazione che ne d la guida in linea: Propriet End
Restituisce un oggetto Range che rappresenta la cella alla fine dell'area contenente l'intervallo di
origine. Equivale a premere FINE+ FRECCIA SU, FINE+ FRECCIA GI, FINE+ FRECCIA SINISTRA o FINE+
FRECCIA DESTRA. Propriet di tipo Range di sola lettura.
espressione.End(Direction)
espressione: Argomento necessario. Un'espressione che restituisce un oggetto nell'elenco Si applica a
Direction : Argomento necessario di tipo XlDirection. Specifica la direzione dello spostamento.
XlDirection pu essere una delle seguenti costanti XlDirection.
xlDown 'direzione gi
xlToRight 'direzione a destra
xlToLeft 'direzione a sinistra
xlUp 'direzione su
Esempio
Questo esempio seleziona la prima cella (la B1) della colonna B nell'area contenente la cella B4.
Range("B4").End(xlUp).Select
se le celle fossero vuote, altrimenti se per esempio la cella B3 fosse occupata con un valore, l'istruzione
avrebbe fatto fermare la selezione a questa cella. Quindi si pu dire che End Select viene usata per
rintracciare la prima cella occupata, data una cella di partenza e con la direzione desiderata. Nel
caso che nessuna cella sia occupata, verr selezionata l'ultima cella del foglio. (verso dx. sx, su o gi).

Ed ecco invece l'istruzione usata per incollare dei dati, sfruttando la succitata propriet End, ma per
trovare la prima riga libera dove "scaricare" i dati. Supponiamo quindi di avere un foglio, che
chiameremo "Archivio", nel quale vorremo "incollare" dei dati provenienti da un altro foglio.
Decideremo che i dati verranno inseriti a partire dalla colonna A. In genere sceglieremo la prima cella
del foglio, la A1, per iniziare a formare il nostro archivio. Solo che dovremo usare un accorgimento, per
evitare che se nell'istruzione usiamo la cella A1 come inizio di selezione, non ci ritroviamo ad avere
l'ultima cella del foglio come cella individuata dell'istruzione Selection.End(xlDown).Select (infatti il
comando porterebbe, non trovando celle occupate, alla fine del foglio). L'accorgimento consiste nel
tenere le prime due celle A1 e A2 occupate, con un qualsiasi valore, tipo un intestazione colonna, e
indicare nel codice a questo punto la cella A1 come cella da selezionare per iniziare il ciclo. Poich
l'istruzione ora si fermerebbe alla cella A2, e noi invece cerchiamo una riga vuota, aggiungiamo
l'istruzione "Offset" che sposta la selezione sulla cella sottostante, la A3 (vuota), e qui avviene
l'incollaggio. Ripetendo il ciclo, troveremo sempre l'ultima cella e la successiva libera. Questo il
codice:
Sub CopiaIncolla2()
Worksheets("Arhivio").Select
Range("A1").Select 'bisogna fargli trovare 2 celle occupate la A1 e la A2,
'altrimenti l'istruzione seguente porterebbe alla fine del
'foglio generando un errore per via dell'istruzione Offset
'successiva.
Selection.End(xlDown).Select
ActiveCell.Offset(1, 0).Select 'mi sposto alla successiva che libera

'incollo i dati.
With ActiveCell
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End With

'esco
End Sub

http://ennius.interfree.it/ Pagina 110


MANUALE VBA X EXCEL
Ancora una procedura per Copiare/Incollare
Utilizzo : Copia/Incolla dati in celle NON contigue con destinazione in celle contigue.
ovvero: copia dei nuovi dati inseriti nella prima riga libera di un elenco, non tutte le celle, ed
incollaggio su una tabella elenco posta su un altro foglio.
La procedura si basa sulla necessit di NON copiare tutte le celle di un elenco, ma solo alcune, e di
ricostruire un nuovo elenco in altra zona, con i dati inseriti in celle contigue per successivi conteggi. Il
codice cerca l'ultima riga dell'elenco nel quale sono stati inseriti i nuovi dati, seleziona le celle che
devono essere copiate, si sposta sul foglio di destinazione, nel quale sono state definite le celle iniziali,
qui cerca la prima riga libera, e "scarica" (incolla) i dati copiati. La procedura esegue il "copia/Incolla"
una cella per volta, selezionando alternativamente il foglio con la cella da copiare e quindi il foglio
con la cella dove incollare, ma grazie all'istruzione : Application.ScreenUpdating = False , non si notano
saltellamenti. Questa la routine:
Sub copiazza()
'I caratteri in verde, dopo l'apice, sono commenti
'e se vuoi li puoi togliere.

Application.ScreenUpdating = False
Worksheets("Foglio1").Select
Range("A4").Select

Selection.End(xlDown).Select
Selection.Copy 'copio il nome (1 colonna partendo dalla B)

Worksheets("Foglio2").Select ' seleziono il foglio2


Range("B5").Select
Selection.End(xlDown).Select
ActiveCell.Offset(1, 0).Select 'trovo la prima cella libera
'nella colonna B, la seleziono e incollo
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
'------------------------------
Worksheets("Foglio1").Select 'poi torno sul foglio1
Range("A4").Select
Selection.End(xlDown).Select
ActiveCell.Offset(0, 1).Select 'copio la data (2 cella 2 colonna dell'elenco)
Selection.Copy

Worksheets("Foglio2").Select 'torno sul foglio2


Range("B5").Select
Selection.End(xlDown).Select 'vado alla cella ultima occupata
ActiveCell.Offset(0, 1).Select 'seleziono la colonna accanto
'e incollo
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
'-------------------------------
Worksheets("Foglio1").Select
Range("A4").Select
Selection.End(xlDown).Select
ActiveCell.Offset(0, 3).Select 'copio il primo valore (4 cella 4colonna)
Selection.Copy

Worksheets("Foglio2").Select
Range("B5").Select
Selection.End(xlDown).Select
ActiveCell.Offset(0, 2).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
'--------------------------------
http://ennius.interfree.it/ Pagina 111
MANUALE VBA X EXCEL
Worksheets("Foglio1").Select
Range("A4").Select
Selection.End(xlDown).Select
ActiveCell.Offset(0, 5).Select 'copio il secondo valore (6cella 6colonna)
Selection.Copy

Worksheets("Foglio2").Select
Range("B5").Select
Selection.End(xlDown).Select
ActiveCell.Offset(0, 3).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
'--------------------------------
Worksheets("Foglio1").Select
Range("A4").Select
Selection.End(xlDown).Select
ActiveCell.Offset(0, 8).Select 'copio il terzo valore (9 cella 9a colonna)
Selection.Copy

Worksheets("Foglio2").Select
Range("B5").Select
Selection.End(xlDown).Select
ActiveCell.Offset(0, 4).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
'-------------------------------
Worksheets("Foglio1").Select

Application.CutCopyMode = False 'questo evita i trattini intorno alla/alle


'celle copiate

End Sub

I riferimenti alle celle di inizio elenco e di inizio destinazione si capiscono meglio se scaricherete il file
allegato. la procedura, anche se appare lunga, semplice, e si ripete tante volte quante sono le celle
da copiare. Sotto due immagini, il foglio1 con l'elenco in cui si inseriscono i dati, ed il foglio2 con le
destinazioni.

File consultabile e scaricabilie : cartelennius.zip 16 kb

http://ennius.interfree.it/ Pagina 112


MANUALE VBA X EXCEL
Ancora una procedura per Copiare/Incollare (07/01/03)
Utilizzo : Copia/Incolla dati in celle NON contigue con destinazione in celle contigue.
A differenza del metodo descritto in "Copia/Incolla 3" (vedi), in questa pagina useremo istruzioni
differenti (avanzate) per ottenere lo stesso risultato, cio la copia di dati in colonne non contigue, con
incollaggio dei dati copiati in zone contigue. Presento due diversi modelli, che hanno in comune
l'utilizzo di nuove istruzioni :
UsedRange (propriet)
SpecialCells (Metodo)
xlLastCell (Costante)
Union (Metodo)
Gli esempi che seguiremo saranno:
Con un elenco (tabella) di dati, la copia dei dati inseriti nell'ultima riga, in Celle non contigue, e
relativo incollaggio dei dati cos copiati, in una zona dello stesso foglio o di un altro foglio, ma in Celle
contigue, con inserimento nella zona destinazione con ricerca della prima riga libera (progressione).
Sempre partendo da un elenco (tabella di dati) posti su pi colonne, la copia di Colonne non contigue
con incollaggio dei dati cos copiati, in una zona dello stesso foglio o di un altro foglio, ma in Colonne
contigue. (quindi non solo i dati presenti nell'ultima riga, ma tutti i dati presenti in una o pi colonne con
incollaggio nella zona di destinazione, con sostituzione in questa zona dei dati gi presenti con i nuovi
dati (aggiornamento totale).
Vediamo intanto le spiegazioni circa le nuove istruzioni:
La propriet UsedRange. In effetti la Guida un p avara di chiarimenti, e comunque, per Excel, lo
UsedRange la zona che, sul foglio di lavoro, va dalla cella A1 all'ultima cella del foglio, rappresentata
dall'incrocio dell'ultima riga con l'ultima colonna, in pratica tutto il foglio. E' possibile "pilotare" la zona
da assegnare all' UsedRange, semplicemente indicando il riferimento ad una cella che serva da inizio
zona: se usiamo quindi UsedRange con SpecialCells e la costante xlLastCell, tutto ci che si trover
sotto e a destra di questa cella, rappresenter l'UsedRange, purch contenga dati, anche in celle non
contigue. In realt l'UsedRange, su un foglio vuoto, da solo non potrebbe agire (o meglio,
identificherebbe SOLO la cella iniziale scelta) se non definiamo alcuni parametri: fino a quale cella si
dovr intendere la zona coperta da UsedRange, e/o quale tipo di celle comprendere. Useremo quindi
il metodo SpecialCells il quale fa riferimento a tutte le celle che risponderanno al "tipo" specificato. Per
definire il "tipo" useremo delle "Costanti" specifiche. Eventualmente queste costanti si possono
sommare, col risultato di comprendere pi "tipi". Vediamo sotto uno specchietto di queste costanti .
Tipo Significato
xlCellTypeNotes Celle contenenti note
xlCellTypeCostants Celle contenenti costanti
xlCellTypeFormulas Celle contenenti formule
xlCellTypeBlanks Celle vuote
xlCellTypeLastCell Ultima cella del foglio di lavoro
xlCellTypeVisible Tutte le celle visibili
Vediamo un esempio e relative istruzioni. E' possibile assegnare un nome a questa cella, e usare il nome
come riferimento nelle istruzioni. Nell'esempio sotto, per meglio capire, useremo la cella F13 come
riferimento inizio zona, ed evidenzieremo l'UsedRange, che si fermer alla cella L22 perch questa
l'ultima cella che contiene dei dati.

http://ennius.interfree.it/ Pagina 113


MANUALE VBA X EXCEL

Questa l'istruzione che abbiamo usato:


Sub Miazona()
Set LastCell = ActiveSheet.UsedRange.SpecialCells(xlLastCell)
Range(Range("F13"), LastCell).Select
End Sub
E' evidente che se invece che selezionare una zona, avessimo voluto pulirne le celle, avremmo
adoperato un'istruzione appropriata, tipo Range(Range("F13"), LastCell).ClearContents, oppure
avremmo potuto decidere il tipo di font, il grassetto, il colore celle, ecc. ecc. con un comando unico.
Due precisazioni: usare una costante specifica su un foglio che non contiene il "tipo" di celle previsto
dalla costante scelta, genera un errore. Quindi assicurarsi di usare la o le costanti giuste in funzione del
tipo di celle che vorremo comprendere. L'altra che se usiamo UsedRange assegnando una cella di
inizio zona, e non esistono dati nelle celle sottostanti e a destra di questa cella, ma esistono dati sopra,
(sia a destra che a sinistra) rispetto alla cella inizio zona, l'UsedRange cercher la prima cella sopra e la
prima cella sopra a destra occupate, e comprender le celle in queste zone, non sotto. Esercitatevi su
un foglio per meglio capire, anche variando le costanti, con xlBlanks o xlVisible.
L'ultima istruzione prevista a inizio foglio, il metodo Union - Union consente di unire pi intervalli
discontinui, utile quando si voglia, per esempio, copiare range di celle non contigui. Questo metodo ha
come "argomenti", i riferimenti alle celle che esso unisce. Esempio:
Dim c1, c2, c3, Intervallo As Range
Set c1 = Range("A1")
Set c2 = Range("D1")
Set c3 = Range("G1")
Set Intervallo = Union(c1, c2, c3)
Intervallo.Copy
Ed ora passiamo agli esempi del Copia/Incolla. Per il primo modello, useremo la tabella gi usata per il
"Copia/incolla3". Per questo esempio, ipotizzeremo di avere una tabella con dei dati che inseriremo
riga per riga, e di cui vorremo copiare solo i dati di alcune colonne (in questo caso evidenziate in
giallo), MA di voler copiare solo i dati inseriti nell'ultima riga. (il perch lo lascio decidere a voi,
potrebbe essere che non tutte le righe debbano essere copiate, o un altro motivo, l'importante
vedere quali istruzioni compileremo per questa operazione.) Quindi i dati da copiare si trovano sulla
stessa riga, MA in colonne discontinue. I dati poi li vorremo incollare in una zona dello stesso foglio o
anche di un altro foglio, e che l'elenco che si former con l'incollaggio formi una nuova tabella per
con colonne contigue. Questa sotto l'immagine della ipotetica tabella:

http://ennius.interfree.it/ Pagina 114


MANUALE VBA X EXCEL

e vediamo allora le istruzioni, e relative spiegazioni:


Sub incollauno()
'evita saltellamenti (scrolling) a schermo
Application.ScreenUpdating = False

'dichiarazioni delle variabili come Range


Dim c1, c2, c3, c4, c5, Intervallo As Range
With Foglio1
Set c1 = Range("A1").End(xlDown) 'assegnazione alla variabile c1 dell'ultima cella
occupata (End(xlDown)) nella colonna A a partire da A1
Set c2 = Range("B1").End(xlDown) 'c.s. per la colonna B
Set c3 = Range("D1").End(xlDown) 'c.s. per la colonna D
Set c4 = Range("F1").End(xlDown) 'c.s. per la colonna F
Set c5 = Range("I1").End(xlDown) 'c.s. per la colonna I
End With
'a questo punto sono state identificate e assegnate tutte le celle dell'ultima riga
Set Intervallo = Union(c1, c2, c3, c4, c5) 'assegnazione ad Intervallo dell'UNIONE delle
'celle precedentemente assegnate alle variabili.

Intervallo.Copy 'copia di Intervallo, cio delle celle discontinue prec. assegnate


Range("L1").Select 'selezione della cella dove incollare i dati copiati (sullo stesso
foglio)
Selection.End(xlDown).Select 'selezione dell'ultima cella occupata a partire da L1
ActiveCell.Offset(1, 0).Select 'selezione della cella sotto l'ultima occupata (che
vuota)
ActiveSheet.Paste ActiveCell 'incollaggio (Paste) di Intervallo nella cella ora attiva.
'Trattandosi di cinque celle, sufficiente selezionare una prima cella, ed Excel
"scaricher" in sequenza (cio contigui) sulla stessa riga, i cinque dati memorizzati.
'sotto: elimina il tratteggio intorno alle celle copiate
Application.CutCopyMode = False
End Sub
Ricordo ai lettori che la procedura per incollare, utilizzando End pi Offset(1, 0), dovr trovare le prime
due celle di inizio elenco (L1 e L2) occupate o con una intestazione di campo, o qualsiasi altro valore
(basta anche un punto).
Vediamo ora il secondo esempio di Copia/Incolla. Sempre usando la tabella dell'esempio precedente,
questa volta copieremo non pi i dati delle celle dell'ultima riga, ma le intere colonne, discontinue (le
gialle) qualunque sia la lunghezza raggiunta, e incolleremo i dati sul Foglio2. In questo caso, anzich
cercare nella destinazione, la prima riga libera per scaricare i dati, trattandosi ad ogni copia/incolla di
trasferire TUTTE le righe delle colonne interessate, provvederemo alla cancellazione dei dati presenti in
tutta la zona di destinazione (utilizzeremo UsedRange) visto che ricostruiremo un nuovo elenco
aggiornato. Sul foglio2, per identificare la cella che ci servir come inizio elenco per incollare i dati, la
B6, gli assegneremo un nome, che definiremo come pi ci piace (in questo esempio il nome sar
"pippo"). Sotto la tabella che forma l'elenco di destinazione:

http://ennius.interfree.it/ Pagina 115


MANUALE VBA X EXCEL

E queste le istruzioni, da ATTIVARE con un pulsante, dal Foglio2, e spiegazioni:


Sub incolladue()
'evita saltellamenti (scrolling) a schermo
Application.ScreenUpdating = False

'dichiarazioni delle variabili come Range


Dim c1, c2, c3, c4, c5 Intervallo As Range
'comincia l'assegnazione non pi di una singola cella della colonna A ad una
variabile, ma di tutte le righe che porteranno dati a partire dalla prima cella (A1) e
fino all'ultima cella occupata (End), e queste sono le istruzioni da impostare, per ogni
variabile (colonna):
With Foglio1.Range("A1")
Set c1 = Range(.Cells(1), .End(xlDown))
End With
With Foglio1.Range("B1")
Set c2 = Range(.Cells(1), .End(xlDown))
End With
With Foglio1.Range("D1")
Set c3 = Range(.Cells(1), .End(xlDown))
End With
With Foglio1.Range("F1")
Set c4 = Range(.Cells(1), .End(xlDown))
End With
With Foglio1.Range("I1")
Set c5 = Range(.Cells(1), .End(xlDown))
End With
'a questo punto sono state identificate e assegnate tutte le colonne da inizio
colonna fino 'all'ultima riga occupata
Set Intervallo = Union(c1, c2, c3, c4, c5) 'assegnazione ad Intervallo dell'UNIONE delle
'zone precedentemente assegnate alle variabili.

'poi viene pulito il foglio2, a partire dalla cella B6 e con UsedRange, vengono
intercettate tutte le celle che porteranno valori. L'utilit di UsedRange in questo caso
evidente: per pulire un elenco non disponendo di riferimenti precisi, con
UsedRange saremo sicuri che tutto ci che sar tra la cella B6 e la fine del foglio, se
occupato da dati, sar pulito.
Set UltimaCella = ActiveSheet.UsedRange.SpecialCells(xlLastCell)
Range(Range("pippo"), UltimaCella).Clear

'ora la pagina (Foglio2) pronta per copiare/incollare i dati, con il metodo Copy

http://ennius.interfree.it/ Pagina 116


MANUALE VBA X EXCEL
applicato all'oggetto Range
' oggetto.Copy [destinazione]

Intervallo.Copy ("pippo")

'volendo poi ordinare i dati per nome, useremo la seguente istruzione:

With Range("pippo")
.Sort Key1:=.Offset(0, 0), Order1:=xlAscending, header:=xlYes
End With

End Sub

http://ennius.interfree.it/ Pagina 117


MANUALE VBA X EXCEL
Altri esempi di Copia/Incolla (veloci)
Vediamo ancora qualche esempio di copia e incolla, questa volta basati su selezioni libere, o quasi. Si
possono usare quando, posto un elenco su un foglio di lavoro, si voglia selezionare una zona variabile
per estensione, con destinazione su altre zone dello stesso foglio o di altri fogli.
Primo esempio. Definiamo con "Zona" tutta l'area compresa tra una determinata cella, che va
identificata nell'istruzione, ed una cella "libera" che verr selezionata di volta in volta, rendendola
quindi Cella Attiva (ActiveCell). Tutte le celle che si troveranno comprese tra la cella fissa e la cella in
quel momento attiva, saranno comprese in "Zona". Questa l'istruzione, con A1 come cella fissa ( Cells(1,
1) ):
Set Zona = Range(ActiveCell, Cells(1, 1))
Ovviamente sar possibile scegliersi il nome con il quale impostare sia l'area, sia la cella iniziale fissa.
Una precisazione, lavorando con ActiveCell e quindi riferita alla cella attiva SUL FOGLIO DI LAVORO, il
pulsante per l'attivazione della macro dovr risiedere sullo stesso foglio, anche se la destinazione sar
su un foglio "distante".
Secondo esempio. Anzich lavorare con una cella che identifichi l'inizio dell'area, qui useremo una
selezione completamente libera, usando appunto Selection. Potremo in questo modo selezionare
liberamente qualsiasi area del nostro foglio, perch tutta l'area selezionata sar assegnata a "Zona".
Set Zona = Selection
Ricordo che una selezione pu essere fatta anche in celle discontinue o in aree discontinue, usando il
tasto CTRL (Control), da tenere premuto mentre eseguiamo le selezioni, PURCHE' le selezioni interessino
o delle celle SULLA STESSA RIGA anche in colonne non contigue, o aree che siano della stessa
dimensione anche se su colonne discontinue, ma poste sulle stesse righe.

Una volta "reperiti" i dati che vogliamo copiare, useremo il comando Copy per incollare i dati nelle
celle di destinazione. Assegneremo un nome alla cella di inizio zona destinazione: questo ci consentir,
stando sul foglio attivo, non solo di incollare i dati sullo stesso foglio, ma di "mirare" a destinazioni poste
su altri fogli. Chiameremo quindi "pippo" per esempio la cella L2 sullo stesso foglio, o su un altro, poco
importa, e le nostre macro diventeranno:
per il primo esempio:
Sub Prova()
Set Zona = Range(ActiveCell, Cells(1, 1))
Zona.Copy ("pippo")
End Sub
per il secondo esempio:
Sub Prova()
Set Zona = Selection
Zona.Copy ("pippo")
End Sub

http://ennius.interfree.it/ Pagina 118


MANUALE VBA X EXCEL
Copia / Incolla di pi campi con ricerca su un campo specifico. (04/08/03)
Ancora un esercizio per copiare/incollare. In questo caso, simuliamo un elenco dati formato da pi
campi (colonne), e vorremo copiare tutti i dati di una stessa riga, dove uno dei campi corrisponda ad
un certo criterio. Useremo un esempio classico: un indirizzario formato da 4 campi: Nominativo, indirizzo,
citt, telefono; l'esercizio : copiare tutti i dati dove esiste un numero di telefono. Questo esempio
adattabile ad ogni situazione, potr essere applicato a tabelle dove un valore corrisponde ad un
determinato numero, oppure ad una determinata parola, o ancora ad una determinata data,
insomma, i casi si sprecano. Intanto vediamo la tabella scelta come esempio ( i dati sono di fantasia ):
A B C D
1 Nominativo Indirizzo Citt Telefono
2 Abb Santino Via Crisi 13 Vengi 0997-774411
3 Accatto Giuseppe Via Tappicchi 23 Citros
4 Barabba Secondo Via Golgota 1 Maraneia 0985-667788
5 Bicchiere Limpido Via Tavole 5 Lavas 0966-996633
6 Catullo Rocco Via Roma 25 Calabell
Ed ora vediamo come operare. Due precisazioni: il formato celle del campo "Telefono" dovr essere
impostato a "Testo" per poter ospitare numeri con lo zero iniziale. In questo stesso campo, se non esiste il
numero NON dovr esserci comunque nessun valore (come zero, un trattino, ecc.) visto che useremo
come chiave di selezione tutte le celle nel campo Telefono che saranno vuote ( "" ).
Useremo un ciclo For Each...Next che controlli tutte le celle, nel campo "Telefono", e per fornire i
riferimenti del Range su cui operare (cio da quante righe composto l'elenco), useremo prendere gli
estremi nella colonna A (Nominativo) con End, visto che questo campo sicuramente contiene dati, a
differenza del campo telefono che pu avere celle vuote. Poi con Offset controlliamo se esiste un
numero di telefono, in caso positivo, selezioneremo l'intera riga copiandola, ed incollandola in un altro
foglio, su cui useremo un ciclo Wend..While per trovare la prima cella libera dove incollare. Vediamo le
istruzioni e le spiegazioni (in verde)
Sub Aricopia()
Application.ScreenUpdating = False 'serve per evitare i saltellamenti a schermo
Dim CEL As Object 'dichiariamo CEL come "Oggetto"
Set zona = Range(Range("A2"), Range("A2").End(xlDown)) 'con "zona" reperiamo
tutto 'il range di celle dalla cella A2 (in A1 c' "Nominativo") fino all'ultima cella
occupata nella 'colonna A
For Each CEL In zona 'per ogni CEL( Oggetto cella) nel Range "zona"
If CEL.Offset(0, 3) <> "" Then 'se la cella 3 righe a desta (3) stessa riga (0) rispetto alla
CEL in quel momento "spazzolata", diversa da vuoto (quindi la cella che contiene il
'numero di telefono, lo contiene), allora

Range(CEL, CEL.Offset(0, 3)).Select 'si selezionano tutte le celle della stessa riga che
'vanno dalla CEL attiva fino alla cella Telefono
Selection.Copy 'si copia in memoria la selezione

Worksheets("Foglio2").Select 'quindi ci spostiamo sul foglio destinazione

Dim iRow As Integer 'iniziamo il ciclo per la ricerca della prima cella vuota, a partire
dalla
iRow = 2 'riga due
While Cells(iRow, 1).Value <> "" 'fino a che la cella riga iRow, colonna 1 occupata
iRow = iRow + 1 'si scala di riga incrementando di 1 il numero di riga
Wend 'quando si trova una cella libera
Cells(iRow, 1).Select 'la selezioniamo ed incolliamo ci che stato copiato
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False

End If
Worksheets("Foglio1").Select 'ritorniamo sul foglio di partenza

Next 'e si continua il ciclo sulla cella successiva fino alla fine di "zona"

http://ennius.interfree.it/ Pagina 119


MANUALE VBA X EXCEL
Application.CutCopyMode = False 'elimina il tratteggio intorno alle celle copiate
End Sub
Spero di essere stato chiaro.

http://ennius.interfree.it/ Pagina 120


MANUALE VBA X EXCEL
Copia / Incolla di pi campi con ricerca su un campo specifico. (04/08/03)
Ancora un esercizio per copiare/incollare. In questo caso, simuliamo un elenco dati formato da pi
campi (colonne), e vorremo copiare tutti i dati di una stessa riga, dove uno dei campi corrisponda ad
un certo criterio. Useremo un esempio classico: un indirizzario formato da 4 campi: Nominativo, indirizzo,
citt, telefono; l'esercizio : copiare tutti i dati dove esiste un numero di telefono. Questo esempio
adattabile ad ogni situazione, potr essere applicato a tabelle dove un valore corrisponde ad un
determinato numero, oppure ad una determinata parola, o ancora ad una determinata data,
insomma, i casi si sprecano. Intanto vediamo la tabella scelta come esempio ( i dati sono di fantasia ):
A B C D
1 Nominativo Indirizzo Citt Telefono
2 Abb Santino Via Crisi 13 Vengi 0997-774411
3 Accatto Giuseppe Via Tappicchi 23 Citros
4 Barabba Secondo Via Golgota 1 Maraneia 0985-667788
5 Bicchiere Limpido Via Tavole 5 Lavas 0966-996633
6 Catullo Rocco Via Roma 25 Calabell
Ed ora vediamo come operare. Due precisazioni: il formato celle del campo "Telefono" dovr essere
impostato a "Testo" per poter ospitare numeri con lo zero iniziale. In questo stesso campo, se non esiste il
numero NON dovr esserci comunque nessun valore (come zero, un trattino, ecc.) visto che useremo
come chiave di selezione tutte le celle nel campo Telefono che saranno vuote ( "" ).
Useremo un ciclo For Each...Next che controlli tutte le celle, nel campo "Telefono", e per fornire i
riferimenti del Range su cui operare (cio da quante righe composto l'elenco), useremo prendere gli
estremi nella colonna A (Nominativo) con End, visto che questo campo sicuramente contiene dati, a
differenza del campo telefono che pu avere celle vuote. Poi con Offset controlliamo se esiste un
numero di telefono, in caso positivo, selezioneremo l'intera riga copiandola, ed incollandola in un altro
foglio, su cui useremo un ciclo Wend..While per trovare la prima cella libera dove incollare. Vediamo le
istruzioni e le spiegazioni (in verde)
Sub Aricopia()
Application.ScreenUpdating = False 'serve per evitare i saltellamenti a schermo
Dim CEL As Object 'dichiariamo CEL come "Oggetto"
Set zona = Range(Range("A2"), Range("A2").End(xlDown)) 'con "zona" reperiamo
tutto 'il range di celle dalla cella A2 (in A1 c' "Nominativo") fino all'ultima cella
occupata nella 'colonna A
For Each CEL In zona 'per ogni CEL( Oggetto cella) nel Range "zona"
If CEL.Offset(0, 3) <> "" Then 'se la cella 3 righe a desta (3) stessa riga (0) rispetto alla
CEL in quel momento "spazzolata", diversa da vuoto (quindi la cella che contiene il
'numero di telefono, lo contiene), allora

Range(CEL, CEL.Offset(0, 3)).Select 'si selezionano tutte le celle della stessa riga che
'vanno dalla CEL attiva fino alla cella Telefono
Selection.Copy 'si copia in memoria la selezione

Worksheets("Foglio2").Select 'quindi ci spostiamo sul foglio destinazione

Dim iRow As Integer 'iniziamo il ciclo per la ricerca della prima cella vuota, a partire
dalla
iRow = 2 'riga due
While Cells(iRow, 1).Value <> "" 'fino a che la cella riga iRow, colonna 1 occupata
iRow = iRow + 1 'si scala di riga incrementando di 1 il numero di riga
Wend 'quando si trova una cella libera
Cells(iRow, 1).Select 'la selezioniamo ed incolliamo ci che stato copiato
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False

End If
Worksheets("Foglio1").Select 'ritorniamo sul foglio di partenza

Next 'e si continua il ciclo sulla cella successiva fino alla fine di "zona"

http://ennius.interfree.it/ Pagina 121


MANUALE VBA X EXCEL
Application.CutCopyMode = False 'elimina il tratteggio intorno alle celle copiate
End Sub
Spero di essere stato chiaro.

http://ennius.interfree.it/ Pagina 122


MANUALE VBA X EXCEL
Copia / Incolla di pi campi con ricerca su un campo specifico. (04/08/03)
Ancora un esercizio per copiare/incollare. In questo caso, simuliamo un elenco dati formato da pi
campi (colonne), e vorremo copiare tutti i dati di una stessa riga, dove uno dei campi corrisponda ad
un certo criterio. Useremo un esempio classico: un indirizzario formato da 4 campi: Nominativo, indirizzo,
citt, telefono; l'esercizio : copiare tutti i dati dove esiste un numero di telefono. Questo esempio
adattabile ad ogni situazione, potr essere applicato a tabelle dove un valore corrisponde ad un
determinato numero, oppure ad una determinata parola, o ancora ad una determinata data,
insomma, i casi si sprecano. Intanto vediamo la tabella scelta come esempio ( i dati sono di fantasia ):
A B C D
1 Nominativo Indirizzo Citt Telefono
2 Abb Santino Via Crisi 13 Vengi 0997-774411
3 Accatto Giuseppe Via Tappicchi 23 Citros
4 Barabba Secondo Via Golgota 1 Maraneia 0985-667788
5 Bicchiere Limpido Via Tavole 5 Lavas 0966-996633
6 Catullo Rocco Via Roma 25 Calabell
Ed ora vediamo come operare. Due precisazioni: il formato celle del campo "Telefono" dovr essere
impostato a "Testo" per poter ospitare numeri con lo zero iniziale. In questo stesso campo, se non esiste il
numero NON dovr esserci comunque nessun valore (come zero, un trattino, ecc.) visto che useremo
come chiave di selezione tutte le celle nel campo Telefono che saranno vuote ( "" ).
Useremo un ciclo For Each...Next che controlli tutte le celle, nel campo "Telefono", e per fornire i
riferimenti del Range su cui operare (cio da quante righe composto l'elenco), useremo prendere gli
estremi nella colonna A (Nominativo) con End, visto che questo campo sicuramente contiene dati, a
differenza del campo telefono che pu avere celle vuote. Poi con Offset controlliamo se esiste un
numero di telefono, in caso positivo, selezioneremo l'intera riga copiandola, ed incollandola in un altro
foglio, su cui useremo un ciclo Wend..While per trovare la prima cella libera dove incollare. Vediamo le
istruzioni e le spiegazioni (in verde)
Sub Aricopia()
Application.ScreenUpdating = False 'serve per evitare i saltellamenti a schermo
Dim CEL As Object 'dichiariamo CEL come "Oggetto"
Set zona = Range(Range("A2"), Range("A2").End(xlDown)) 'con "zona" reperiamo
tutto 'il range di celle dalla cella A2 (in A1 c' "Nominativo") fino all'ultima cella
occupata nella 'colonna A
For Each CEL In zona 'per ogni CEL( Oggetto cella) nel Range "zona"
If CEL.Offset(0, 3) <> "" Then 'se la cella 3 righe a desta (3) stessa riga (0) rispetto alla
CEL in quel momento "spazzolata", diversa da vuoto (quindi la cella che contiene il
'numero di telefono, lo contiene), allora

Range(CEL, CEL.Offset(0, 3)).Select 'si selezionano tutte le celle della stessa riga che
'vanno dalla CEL attiva fino alla cella Telefono
Selection.Copy 'si copia in memoria la selezione

Worksheets("Foglio2").Select 'quindi ci spostiamo sul foglio destinazione

Dim iRow As Integer 'iniziamo il ciclo per la ricerca della prima cella vuota, a partire
dalla
iRow = 2 'riga due
While Cells(iRow, 1).Value <> "" 'fino a che la cella riga iRow, colonna 1 occupata
iRow = iRow + 1 'si scala di riga incrementando di 1 il numero di riga
Wend 'quando si trova una cella libera
Cells(iRow, 1).Select 'la selezioniamo ed incolliamo ci che stato copiato
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False

End If
Worksheets("Foglio1").Select 'ritorniamo sul foglio di partenza

Next 'e si continua il ciclo sulla cella successiva fino alla fine di "zona"

http://ennius.interfree.it/ Pagina 123


MANUALE VBA X EXCEL
Application.CutCopyMode = False 'elimina il tratteggio intorno alle celle copiate
End Sub
Spero di essere stato chiaro.

http://ennius.interfree.it/ Pagina 124


MANUALE VBA X EXCEL
Controllo dei costi delle chiamate telefoniche.
In pratica: trattasi di ricerca di un dato in una colonna dati, con restituzione in altra zona, del dato
trovato e dati a questo correlati. La ricerca avviene con inserimento parziale del valore da cercare.
Nella zona destinazione cerchiamo la prima cella libera nella colonna per accodare i dati trovati;
un'altro esercizio sul copia/incolla.
In seguito ad una richiesta ho realizzato una semplice esercitazione che propongo ad altri "pellegrini".
Premetto che si tratta ancora di rintracciare un dato in un elenco di dati e una volta trovato, di
copiare i dati correlati in modo da formare un riepilogo che consenta di registrare i relativi costi.
Il problema: come identificare dal riepilogo che la Telecom invia con la bolletta, i numeri di telefono
che sono stati chiamati dal telefono di casa, visto che nel succitato riepilogo i numeri, in ottemperanza
alla legge sulla Privacy, vengono riportati con il numero incompleto seguito da cancelletti (###) per
esempio: 33879854###.
Ovviamente questo programma proposto, non un mago, e quindi non potr mai risalire a rintracciare
i numeri mancanti indicati con ###, ma pu rintracciare, dato solo il numero senza cancelletti
(33879854) quale sia il numero completo presente in un elenco o database che dir si voglia, dove
avremo preventivamente inserito tutti i numeri che formano la nostra agenda telefonica. Avremo cura
di associare al numero reale anche un Nominativo in modo che, una volta trovato il numero, sia
possibile copiare in una tabella all'uopo destinata, i dati relativi al numero (il nome), inserendo a mano
il numero degli scatti e relativo costo, per ottenere sia il totale di quanto costata quella telefonata,
sia un totale generale.
Le procedure vba seguite, sono state gi presentate in questa sezione in diversi articoli, quindi per le
spiegazioni provate a consultare i vari copia/incolla e i Database in particolare il "database con
spiegazioni", dal quale ho ripetuto il ciclo di ricerca, che trova un dato anche se si fornisce solo una
parte di esso.
In pratica succede questo: attraverso una InputBox, viene richiesto di inserire il numero da trovare,
SENZA cancelletti, vedi foto sotto (le colonne in giallo sono quelle del database, in verde e arancio a
zona dove verranno incollati i dati)

Una volta inserito il numero senza cancelletti e premuto Ok, se la ricerca trova un numero in cui figura
la sequenza di numeri inserita, avvisa con una domanda se vogliamo registrare i dati relativi al numero
esatto e al nome associato. Abbiamo inserito il numero 34897 e infatti viene trovato il 348974562, vedi
foto sotto:

Confermando con Si, avremo la copia dei dati Numero/Nome nella zona di destinazione, con ricerca
della prima riga libera, ed evidenzazione della cella dove dovremo inserire il numero degli scatti e il
costo scatto, vedi foto sotto

http://ennius.interfree.it/ Pagina 125


MANUALE VBA X EXCEL

Precisazioni: le colonne A, B, D, E sono formattate a "Testo" per consentire l'uso di numeri con lo zero
iniziale. Nella colonna H in H3 una semplice moltiplicazione F3*G3 per avere il totale spesa (a seguire
nelle celle sottostanti). Sar possibile poi possibile applicare un filtro ai nomi dei chiamati per avere un
parziale dei costi relativi al nome scelto, o ancora "Estrarre" da questo secondo elenco tutti i dati
corrispondenti ad un certo nome e formarsi altre tabelle, ecc. ecc. Questa la procedura associata al
pulsante "Cerca Numero":
Sub cercaNumero()
With Worksheets(1).Range("A2:A150")

Dim X, messaggio, titolo


titolo = "Ricerca Numero Telefonico"
messaggio = "Inserisci il Numero che vuoi cercare"
X = InputBox(messaggio, titolo)
If X = "" Then Exit Sub 'se non scrivo niente nella finestra esco dalla routine
Set C = .Find(X, LookIn:=xlValues) ', LookAt:=xlWhole
If Not C Is Nothing Then
firstAddress = C.Address
Do
C.Cells.Select

Y = C.Value 'prendo il numero di telefono


Z = C.Offset(0, 1).Value 'prendo il nome a lato
'compongo il messaggio di avviso e conferma si/no
irisposta = MsgBox("Trovato " & Y & " a nome " & Z & ". Vuoi registrare ?", vbYesNo)
If irisposta = vbYes Then 'se rispondo si allora
GoTo 10 'esco dal ciclo e registro
End If
Set C = .FindNext(C)
Loop While Not C Is Nothing And C.Address <> firstAddress

Else
MsgBox "Numero non Trovato"
End If
10: 'ho trovato il numero e identifico con "zona" le due celle che voglio copiare
Set zona = Range(ActiveCell, ActiveCell.Offset(0, 1))
zona.Copy
Range("D1").End(xlDown).Select 'cerco l'ultima cella occupata partendo da D1
ActiveCell.Offset(1, 0).Select 'seleziono la riga libera sotto l'ultima occupata
ActiveSheet.Paste Destination:=ActiveCell 'Incollo i dati copiati con zona.Copy
ActiveCell.Offset(0, 2).Select 'seleziono la cella corrispondente al N scatti e scriver
il 'numero degli scatti letti sulla bolletta.
End With

Application.CutCopyMode = False
End Sub

File Scaricabile e consultabile : CostiTelefono2000.zip 14 Kb

http://ennius.interfree.it/ Pagina 126


MANUALE VBA X EXCEL
Facciamo un orologio sul Foglio di lavoro. (25/05/03)
A volte abbiamo la necessit di conoscere che ore sono allorch lavoriamo sui fogli di Excel. Possiamo
usare la funzione di Excel =ADESSO() inserita in una cella, che ci restituisce la data e l'ora di sistema.
L'orario non scorre per come in un orologio, ma rimane fisso al momento in cui abbiamo aperto il
foglio, e si aggiorna soltanto se inseriamo o modifichiamo dei valori sul foglio di lavoro, e
l'aggiornamento comunque non avviene nella scala dei minuti se effettuiamo una variazione in una
cella all'interno del minuto dell'orario attualmente presente nella cella con la funzione. Non proprio
ci che possiamo considerare un : "orologio".
Sfruttando la funzione vba "Timer", per possibile usare una routine "autoinnescante" che, trascorso un
determinato periodo di tempo, che decideremo noi, riattivi la funzione =ADESSO() (in inglese: NOW),
generando l'aggiornamento dell'orario.
Attenzione: la macro qui presentata pu provocare effetti indesiderati disabilitando alcune barre dei
men. Prima di deciderne un eventuale utilizzo, provatela su file non importanti.
Creiamo quindi una macro che inseriremo in un modulo e potremo attivare "l'orologio" associando la
macro ad un pulsante, ma meglio ancora potremo sfruttare un evento che per tutti noi quasi
impossibile non generare: il cambio di selezione di una cella sul foglio di lavoro; in questo modo
attiveremo la macro ad ogni operazione che eseguiamo sul foglio di lavoro. Non necessario riscrivere
nel Worksheet_SelectionChange del foglio di lavoro scelto tutte le istruzioni, ma sar sufficiente
richiamare il nome della macro, cos:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Oriolo 'nome della macro
End Sub
Un avvertimento: poich una volta avviata la macro, questa continua a girare restando sempre attiva,
se avremo bisogno di compilare altre istruzioni vba, sar necessario "stoppare" la macro stessa,
selezionando la routine e cliccando il pulsantino quadrato blu che troviamo nel men dell'editor di
visual basic, che corrisponde al comando "Ripristina", oppure dal men Esegui/Ripristina.
Sar comunque possibile eseguire modifiche sul foglio di lavoro anche con la macro avviata, come
pure lanciare altre macro precedentemente compilate; questo perch nelle istruzioni sotto riportate,
usiamo la funzione vba "DoEvents" che sospende l'esecuzione in modo che il sistema operativo possa
elaborare altri eventi. Vediamo le istruzioni: nell'esempio uso la cella A1, formato cella = Ora, come
cella Orologio: (tenere presente che se avviamo la macro tramite pulsante, (mettiamo dal Foglio1), la
stessa, restando attiva, sar efficace in tutte le celle A1 di tutti i fogli della cartella, baster spostarsi su
un'altro foglio, per veder comparire in A1 l'orologio; lasciare quindi disponibile (non usare per altre
istruzioni o dati) la cella che deciderete di usare come orologio); la macro attivata da pulsante si
fermer soltanto se in una cella clicchiamo per inserire una formula, mentre sul foglio di cui sfruttiamo
l'evento SelectionChange, selezionando appunto una qualsiasi cella, la riattiviamo:
Sub Oriolo()
Dim PauseTime, Start, Finish, TotalTime 'dichiarazione variabili impiegate
Range("A1").Value = Now 'assegnazione alla cella A1 della funzione Adesso()
Range("A1") = Format(Range("A1"), "h.m.ss") 'impostiamo il formato nella cella A1
10:
PauseTime = 3 ' Imposta la durata della pausa, espressa in secondi
Start = Timer ' Imposta l'ora di inizio e attiva il Timer.

Do While Timer < Start + PauseTime 'fintantoch il valore del Timer inferiore al valore
'dato dalla somma del valore iniziale del Timer (preso con la variabile Start) pi il
valore 'rappresentato dalla variabile PauseTime
DoEvents ' Passa il controllo ad altri processi.

Loop ' continua a far girare il Timer fino a che il suo valore uguale a Start +
PauseTime, 'allora passa alla seguente riga:
Finish = Timer ' Imposta l'ora di fine della pausa.
TotalTime = Finish - Start ' Calcola il tempo totale.
'sotto: ora riportatiamo in A1 il valore di Adesso() ed otteniamo quindi
l'aggiornamento.
Range("A1").Value = Now
Range("A1") = Format(Range("A1"), "h.m.ss") 'impostiamo il formato nella cella A1.
'sotto: poich a questo punto la routine finirebbe con End Sub, e allora addio
http://ennius.interfree.it/ Pagina 127
MANUALE VBA X EXCEL
orologio, 'con l'istruzione GoTo 10 mandiamo il codice all'indice riga 10 riattivando le
istruzioni 'relative al timer:
GoTo 10

End Sub

Suggerimento: non consiglio di scendere sotto i tre secondi come PauseTime, pena il rischio di non
lasciare spazio al sistema di reagire ad altri eventi, meglio sarebbe impostarlo ogni 5 secondi, l'effetto
"orologio" resta comunque valido. (routine provata solo sul Excel XP)

http://ennius.interfree.it/ Pagina 128


MANUALE VBA X EXCEL
Creare un elenco dei nomi dei files contenuti in una cartella.
Spesso avrei trovato utile poter avere un elenco di tutti i file contenuti in una cartella, ma Windows non
consente una stampa di questo tipo. Questa necessit pu scaturire dal voler conservare un elenco
dei files presenti in una nostra cartella, sia per verificare eventuali discordanze future, oppure per
tenere un elenco di file appartenenti ad una specifica categoria, per esempio alle immagini, e quindi
con estensione .Jpg oppure .Bmp, ecc.ecc. Per questo motivo presento una routine che ha il compito
di creare un elenco in formato testo (txt) che riporter il nome dei files di una eventuale estensione,
oppure tutti, contenuti all'interno di una cartella o sottocartella del nostro hard-disk. Premetto che mi
solo limitato a preimpostare il percorso dell'unit su cui cercare e scrivere, nell'unit C:\ - Volendo
potrete modificare le istruzioni in modo che anzich digitare solo il nome della cartella, possiate
digitare un percorso completo, ampliando la possibilit di scrivere o reperire cartelle con relativi files, su
qualunque unit del vostro computer. La routine si basa su quattro variabili ottenute con quattro
InputBox. Le variabili memorizzano rispettivamente:
Il nome della cartella in cui salvare il file di testo che former l'elenco
Il nome con il quale salvare il file di testo
Il nome della cartella di cui vogliamo l'elenco dei files ivi contenuti
I nome del file di cui vogliamo registrare il nome, oppure una combinazione di caratteri jolli per avere
l'elenco di tutti i file con una certa estensione ( *.xls - opp. *.jpg ecc.ecc.), oppure la combinazione (*.*
)per avere l'elenco di tutti i files e sottocartelle presenti.
Ho inserito un'istruzione che controlla se esiste la cartella di destinazione, in caso non esista, crea la
cartella. Queste le istruzioni :
Sub Creaelenco()
On Error Resume Next
'chiedo in quale cartella voglio salvare il file di testo
Dim mival, mess, tito
mess = "" & vbCr & vbCr & _
"Scrivi in quale cartella" & vbCr & _
"salvare il file su C:\ " & vbCr & _
"NON scegliere sottocartelle SE" _
& " inesistenti !"
tito = "Inserisci Nome Cartella"
mival = InputBox(mess, tito) ' primo vettore che prende il nome della cartella dato
tramite 'la inputbox
x = "C:\" + mival + "\" 'completo mival anteponendo l'unit C:\ e facendolo seguire
dalla 'barra \ separatrice
If x = "C:\" + "" + "\" Then Exit Sub 'se non metto il nome nella inputbox e quindi mival
'vuoto (""), esco dalla routine
'ora chiedo con quale nome salvare il file di testo attraverso una seconda inputbox
Dim mytesto, messa, titolo
messa = "Inserisci il nome per il file"
titolo = "" & vbCr & vbCr & _
"Ora scrivi il nome con cui salvare il file"
mytesto = InputBox(titolo, messa) + ".txt" 'con mytesto prendo il nome per salvare il
file
If mytesto = "" + ".txt" Then Exit Sub 'se mytesto vuoto, esco dalla routine
'inizia il dimensionamente per l'oggetto FileSystemObject
Dim fso, f
Set fso = CreateObject("Scripting.FileSystemObject")
'sotto: eseguo il controllo per vedere se in nome contenuto in mival gi una
cartella 'esistente
If fso.FolderExists(x) Then GoTo 10 'se la cartella esiste, passo a 10, e salto la creazione
Dim irisposta As Integer 'pongo la domanda se si vuol creare una nuova cartella nel
caso 'non esista la cartella richiesta
irisposta = MsgBox("La cartella non esiste, vuoi crearla?", vbYesNo)
If irisposta = vbYes Then ' se la risposta sar SI
Set f = fso.CreateFolder(x) 'allora creo la cartella (x il nome cartella completo di
path)
Else 'altrimenti, se rispondo NO
http://ennius.interfree.it/ Pagina 129
MANUALE VBA X EXCEL
Exit Sub 'esco dalla routine
End If
10:
'sotto: inizia l'istruzione per l'apertura di un file di testo
Open x + mytesto For Output As #1 'Crea un nuovo file di testo
'inizia la richiesta della cartella dove leggere i files per ottenere l'elenco loro nomi
Dim MyPath, MioFile
titolo = "Inserisci Cartella di provenienza"
messa = "" & vbCr & vbCr & _
"Ora scrivi di quale cartella vuoi creare" _
& " l'elenco dei files"
MyPath = "C:\" + InputBox(titolo, messa) 'MyPath sar formato dal nome digitato
nella inputbox, la terza, con gi anteposta l'unit C:\
If MyPath = "C:\" + "" Then Exit Sub 'se MyPath sar vuoto ("") esco dalla routine

'ora richiedo l'estensione dei files di cui voglio l'elenco


messa = "Inserisci Nome file di provenienza"
titolo = "" & vbCr & vbCr & _
"Ora scrivi il nome del file o l'estensione." & vbCr & _
" Se vuoi tutti i file della cartella" _
& " puoi scrivere i caratteri jolli *.*"
MioFile = MyPath + "\" + InputBox(titolo, messa) 'con la quarta inputbox prendo
'l'estensione del file o tutti i file o un solo file
If MioFile = MyPath + "\" + "" Then Exit Sub 'se non fornisco l'estensione, esco dalla
'routine
MyName = Dir(MioFile, vbDirectory) 'inizia il ciclo che cerca tutti i file con l'estensione
indicata all'interno della cartella voluta
Do While MyName <> "" 'fino a che la cartella alla fine (vuota)
'Inserisce nel file txt il nomifiles della cartella specificata
Print #1, MyName; ""
MyName = Dir
Loop
MyError = CVErr(32767)
Close #1 'Chiude il file di testo
MsgBox "L'elenco File " & mytesto & " stato completato"
Set fso = Nothing
Resume
End Sub
Come ho detto, possibile modificare le istruzioni facendo in modo da poter cercare non solo sull'unit
C:\, ma in qualunque unit del nostro computer, i file di cui vorremo un elenco, sar sufficiente
eliminare le preimpostazioni che determinano l'assegnazione dell'unit, avendo per l'accortezza di
scrivere noi il percorso completo della cartella di provenienza dati. Facendo un esempio solo sulla
provenienza, si pu modificare la riga:
MyPath = "C:\" + InputBox(titolo, messa)
con
MyPath = InputBox(titolo, messa)
e nella finestra (inputbox) che ci porr la domanda, scriveremo il percorso della cartella di cui fare
l'elenco files, completo. per esempio
D:\Immagini
Spero di essere stato chiaro ma soprattutto di esservi stato d'aiuto. Buon lavoro.

http://ennius.interfree.it/ Pagina 130


MANUALE VBA X EXCEL
Trasferire dati di TextBox di UserForm a celle del foglio di lavoro
Ancora un esempio che mostra come trasferire dei dati introdotti in TextBox presenti su una UserForm, in
modo da formare una tabella dati sul foglio di lavoro.
E' una condizione operativa che viene usata spesso nei nostri lavori e quindi vediamo come sia
possibile usare delle istruzioni che si possono applicare, una volta per tutte, in queste occasioni.
Le condizioni : da una UserForm che useremo come maschera di introduzione dati che inseriremo in
apposite TextBox, dovremo trasferire questi dati sul foglio di lavoro, partendo da una determinata riga
(che sceglieremo noi via codice), e scalando di una riga ad ogni introduzione. I dati saranno inseriti in
altrettante celle, sulla stessa riga, per quanto saranno le TextBox. Non ci occuperemo del "Formato
dati" n del "Tipo di dati" che trasferiremo (peraltro gi descritti su altri paragrafi di questa sezione), ma
di reperire l'"indice riga" per identificare su quale riga copiare i dati, e come identificare le colonne.
Questo esempio lo imposto su quattro TexBox, ma potr essere usato su quante TextBox vorremo.
Ultima condizione: vogliamo creare un numero riga progressivo, che ci indichi il numero dei record
(righe) presenti nella tabella
Private Sub CommandButton1_Click()
'queste istruzioni sotto cercano la prima riga in cui la prima cella (cio la cella della
'colonna A sia vuota, a partire dalla riga 2 (iRow = 2). La colonna identificata dal
'numero 1 nell'istruzione While Cells(iRow, 1). Se avessimo voluto creare la tabella a
'partire dalla colonna C, avremmo dovuto scrivere 3, cio While Cells(iRow, 3)
Dim iRow As Integer
iRow = 2 'si comincia dalla riga 2
While Cells(iRow, 1).Value <> "" 'se la cella contiene dati, si passa alla successiva
iRow = iRow + 1
Wend
'trovata la riga con la cella vuota, inserisco i dati contenuti nelle textbox, trovando
per
'ogni textbox la colonna (iRow 1,2,3,4,5). Poi per incrementare il numero progressivo,
gli 'faccio leggere il numero presente nella riga sopra (con Offset), stessa colonna,
ed 'aggiungo 1. In totale quindi useremo 5 celle sul foglio di lavoro, la prima ci servir
per il 'numeratore, e le altre quattro per ospitare i dati delle quattro TextBox.
Cells(iRow, 1) = Cells(iRow, 1).Offset(-1, 0) + 1
Cells(iRow, 2) = TextBox1
Cells(iRow, 3) = TextBox2
Cells(iRow, 4) = TextBox3
Cells(iRow, 5) = TextBox4
'poi dopo che ho copiato i dati sul foglio devo pulire le textbox per inserire nuovi dati
TextBox1 = ""
TextBox2 = ""
TextBox3 = ""
TextBox4 = ""

End Sub
Con questa routine credo di avere chiarito una procedura standard da seguire quando vorremo
inserire dati da una maschera di introduzione dati a celle sul foglio di lavoro. E' possibile ovviamente,
lavorando su un foglio, inserire dati su un altro foglio; sar sufficiente indicare nelle istruzioni su quale
foglio "scaricare" i dati, selezionando prima il foglio, e ritornando poi al foglio di partenza . Usando
Application.ScreenUpdating=False, eviteremo i saltellamenti a video. Questa la modifica:

Private Sub CommandButton1_Click()


Application.ScreenUpdating = False
Sheets(2).Select 'si seleziona un'altro foglio
Dim iRow As Integer
iRow = 2
While Cells(iRow, 1).Value <> ""
iRow = iRow + 1
Wend

Cells(iRow, 1) = Cells(iRow, 1).Offset(-1, 0) + 1


http://ennius.interfree.it/ Pagina 131
MANUALE VBA X EXCEL
Cells(iRow, 2) = TextBox1
Cells(iRow, 3) = TextBox2
Cells(iRow, 4) = TextBox3
Cells(iRow, 5) = TextBox4

TextBox1 = ""
TextBox2 = ""
TextBox3 = ""
TextBox4 = ""
Sheets(1).Select 'si ritorna al foglio di partenza
End Sub

Se invece vogliamo vedere come compilare delle istruzioni che sfruttino un ciclo For...Next sugli insiemi,
potremo sostituire le righe che identificano le TextBox e le Celle, in questa maniera (scrivo solo le
istruzioni da modificare):
'...omissis
Wend 'da questa riga si sostituiscono le precedenti istruzioni con:
'la prima cella non la inseriamo nel ciclo perch dispone un'istruzione singola, non
comune 'alle altre celle (contatore)
Cells(iRow, 1) = Cells(iRow, 1).Offset(-1, 0) + 1
'iniziamo il ciclo dalla seconda cella ( n = 2 To..) a cui assegniamo per la Textbox1,
quindi l'indice 'della textbox sar uguale al valore di n - 1 (n meno uno)
For n = 2 To 5
Cells(iRow, n) = UserForm1.Controls("TextBox" & n - 1).Text
'con lo stesso concetto dell'indice per le textbox, e di seguito nello stesso ciclo,
facciamo 'pulire le textbox
UserForm1.Controls("TextBox" & n - 1) = ""
Next

Sheets(1).Select 'si ritorna al foglio di partenza


End Sub
Buon lavoro.

http://ennius.interfree.it/ Pagina 132


MANUALE VBA X EXCEL
Realizzazione di un Database "SelfMade"
In molti mi hanno scritto chiedendomi delucidazioni circa il codice utilizzato nel programma "Gestione
database" presente in questa sezione. Non potendoli accontentare, ho realizzato questo programma
di cui posso fornire routine e codice, con relative spiegazioni. Premetto che le procedure impiegate,
sono utilizzabili in tutti quei casi dove sia necessario gestire elenchi di dati, anche lunghi, come
indirizzari, gestione articoli magazzino, elenchi fatture, ecc. ecc. Il programma viene esemplificato
comunque per un "indirizzario", ma chiunque potr adattarlo alle proprie esigenze. Chi interessato,
pregato di leggersi TUTTE le istruzioni.
Il programma si basa su dati inseriti su un foglio di lavoro, su cui dovr essere costruito lo "scheletro",
cio lo schema che conterr i dati stessi. Come ogni database che si rispetti, questi dati saranno
organizzati in righe e colonne. Le colonne conterranno i "campi" del database con relative "intestazioni
di colonna", cio i nomi dei "campi" (N, Nominativo, Indirizzo, Citt, ecc.ecc.), e le righe saranno i
"record", cio la zona dove fisicamente saranno inseriti i dati, ognuno nel proprio "campo" (colonna) di
pertinenza. Molti di voi sanno gi cosa si intende per "Database", quindi proseguiamo col vedere come
ho impostato il lavoro. Il programma si apre sul Foglio1 dove stata predisposta la tabella che conterr
i dati. Nell'esempio mi sono limitato ad inserire 6 campi, il N progressivo dei record, Nominativo,
Indirizzo, Citt, Telefono, Cellulare, E-mail. I dati potranno essere inseriti sul foglio, direttamente, a mano,
ma lo scopo era quello di usare una maschera di introduzione, modifica, ricerca dei dati presenti
nell'elenco sul foglio1. Per questo, sul foglio, presente un pulsante per l'apertura della maschera, una
Userform dove sono stati inseriti gli "oggetti" necessari al progetto:
2 OptionButton, per la selezione del metodo di ricerca.
7 TextBox che servono per la gestione della ricerca, e dell'immissione, controllo, modifica dei dati.
7 CommandButton per l'attivazione delle routine necessarie al progetto.

La tabella inizia dalla riga 2 dove sono inseriti i nomi dei campi; questo perch nelle routine utilizzo il
metodo End Select, che partendo dall'alto per trovare la prima riga libera, deve trovare due celle
occupate, altrimenti si precipiterebbe a fine pagina se le riga successiva alla prima fosse vuota
(quando l'elenco da iniziare, la prima cella sotto l'intestazione di campo vuota), per cui nella riga 1,
faccio inserire il segno meno ( - ) e questo serve a far trovare le prime due celle occupate (la riga1 col
meno, la riga2 col nome del campo). Il formato celle di tutta la tabella stato impostato a "Testo", in
questo modo i numeri di telefono che partono con lo zero, verranno registrati correttamente (Excel si
rifiuta di accettare numeri che inizino con zero, a meno che non gli si dica che anzich un numero, si
sta scrivendo del testo). Inoltre l'elenco l'ho impostato per contenere 150 record di dati. Chiunque
potr "allungare" a piacere il range operativo, modificando i riferimenti nelle istruzioni. La colonna A,
quella che contiene il N progressivo del record, viene inizializzata a mano, sfruttando la capacit di
Excel di completare le "serie": si scrive in A3 il numero 1, in A4 il numero 2, si selezionano entrambe le
caselle, ci si sposta nell'angolo in basso a destra della casella A4, e quando compare il puntatore del
http://ennius.interfree.it/ Pagina 133
MANUALE VBA X EXCEL
mouse fatto come una piccola croce nera, si clicca sinistro e si trascina verso il basso: Excel capisce
che si vuole completare una serie, ed in ogni cella seguente le prime due, inserisce i numeri
incrementandoli di uno.
Vediamo ora le procedure inserite nella Userform, partendo dal pulsante "Inserisci Nuovo". Quando
apriamo la UserForm, le Textbox sono tutte vuote. Se vorremo inserire un nuovo nominativo, dovremo
scrivere i dati nelle rispettive TextBox, DOPODICHE' cliccheremo sul pulsante. L'istruzione comincia con
un controllo sulla TextBox2, quella destinata a contenere il "Nominativo": se la trova vuota, avvisa con
un messaggio, riposiziona il focus sella textbox2, ed esce dalla routine senza eseguire il resto delle
istruzioni. Se invece la textbox2 conterr dei dati , viene posta una domanda di conferma registrazione
dati (questo per evitare, mentre siamo in modalit "consultazione dati", di premere inavvertitamente il
pulsante che senza un controllo di conferma, registrerebbe di nuovo i dati gi presenti), se si risponder
Si, inizia la copia dei dati presenti dalle textbox alle celle sul foglio di lavoro. Dopo la copia, avvisa con
un messaggio l'avvenuta esecuzione, indi pulisce le textbox. Vediamo nel dettaglio le istruzioni:
Range("B1").End(xlDown).Offset(1, 0).Select - questo il comando che, seleziona la cella B1, si sposta
verso il basso (End(xlDown) cercando l'ultima cella occupata, trovata questa, si sposta di una riga
sotto, stessa colonna (Offset(1, 0)), e la seleziona (Select) e la rende Attiva; questa cella ovviamente
vuota.
ActiveCell.Value = TextBox2 - comincia a copiare il contenuto delle textbox sulla userform con un
semplice segno di uguale (=), cio :la cella sul foglio di lavoro in quel momento attiva, viene resa
uguale ai dati contenuti nella textbox2, poi a seguire:
ActiveCell.Offset(0, 1).Value = TextBox3 - viene cercata con Offset la prima cella a destra di quella
attiva in quel momento, e viene resa uguale al contenuto della textbox successiva, la 3. Si continua
proseguendo con lo "scarto" (Offset) di una cella, stessa riga, per ogni textbox interessata. Completate
queste istruzioni, appare il messaggio di esecuzione completata, indi
TextBox2 = "" - si puliscono le celle predisponendole per nuovi inserimenti.
Private Sub CommandButton2_Click()
If TextBox2 = "" Then
MsgBox "Devi Inserire almeno il nominativo"
TextBox2.SetFocus
Exit Sub
End If
'questa l'istruzione per la domanda di conferma
Dim irisposta As Integer
irisposta = MsgBox("Confermi la registrazione" _
& " di " & TextBox2.Value & " ?", vbYesNo)
If irisposta = vbYes Then
Range("B1").Value = "-"
Range("B1").End(xlDown).Offset(1, 0).Select
ActiveCell.Value = TextBox2
ActiveCell.Offset(0, 1).Value = TextBox3
ActiveCell.Offset(0, 2).Value = TextBox4
ActiveCell.Offset(0, 3).Value = TextBox5
ActiveCell.Offset(0, 4).Value = TextBox6
ActiveCell.Offset(0, 5).Value = TextBox7
MsgBox "Ok Capo, eseguito!"
TextBox2 = ""
TextBox3 = ""
TextBox4 = ""
TextBox5 = ""
TextBox6 = ""
TextBox7 = ""
End If
End Sub
Ad ogni click sul pulsante assegnato, ripeteremo la stessa procedura.
Passiamo ad esaminare le istruzioni legate al pulsante "Cerca". Ho inserito due OptionButton (pulsanti di
opzione), che ci consentono di scegliere, selezionando uno dei due Optbutton, se vorremo una ricerca
basata sull' esatto nome che scriveremo nella textbox sottostante (la textbox1), oppure una ricerca
basata su parte del nome che andremo cercando: se scriveremo "ci" verranno trovati tutti quei nomi in
http://ennius.interfree.it/ Pagina 134
MANUALE VBA X EXCEL
cui appare la coppia di lettere "ci", siano posizionate all'inizio o all'interno del nome cercato (per
esempio: Ciccillo Gaetano oppure Romboni Placido, ecc.). Ho usato quindi due istruzioni diverse,
anche per mostrare che i cicli di ricerca si possono impostare usando diverse modalit di
programmazione, ogni procedura legata alla selezione di un opzione. Vediamo quindi la procedura
legata al primo pulsante di opzione, quella che ci trova il dato se avremo scritto il nome esatto. Poich,
credo, risulter nel tempo, difficile ricordarsi se avremo registrato un nominativo usando lettere
maiuscole o minuscole, (la ricerca sarebbe CaseSensitive, cio riconosce le lettere e se non sono
scritte uguali non vengono identificate : Ennius diverso da ennius) ho usato in questo caso la funzione
Option Compare Text che ci consente di riconoscere una parola indipendentemente dalle
maiuscole/minuscole usate. Solo che questa funzione, NON pu lavorare al di fuori di un "Modulo"
(vba), cio esterno alle istruzioni che invece sono posizionate tutte nella UserForm. Per cui sufficiente
inserire un modulo nel progetto, e nella zona "Dichiarazioni" - "Generale" del modulo stesso, inserire la
funzione, e subito sotto, posizionare la routine (assegnandoli un nome) su cui agir la funzione Option
Compare Text. Sulla Userform, nell'evento Click del pulsante "Cerca", sar sufficiente richiamare detta
routine semplicemente scrivendo il nome della routine stessa. Ci penser il codice, ad andarsi a
leggere le istruzioni di questa routine, (sotto), in verde sono le spiegazioni. Unica precisazione:
trattandosi di istruzioni contenute in un Modulo, per identificare dove si trovano le TextBox, necessario
identificare l'"oggetto" che le contiene, e quindi la riga d'istruzione v cos impostata:
UserForm1.TextBox2 = CL.Value . (nelle istruzioni contenute nella userform, sarebbe stato sufficiente
TextBox2 = CL.Value). Questo il codice inserito nel Modulo :
Option Compare Text
____________________________________________
Sub primo()
Dim CL As Object 'dichiarazione del tipo di variabile per CL

For Each CL In Range("B3:B152") 'per ogni CL (cella) tra B3 e B152


Dim X As String 'dichiar. di var. per la X
X = UserForm1.TextBox1.Value 'la X sar uguale al dato nella textbox1 che il
'nominativo da cercare
If CL = X Then 'se la cella (CL) uguale a X
CL.Select 'faccio selezionare (fermo il ciclo) questa cella
Y = CL.Value 'con Y prelevo il dato contenuto nella cella(CL)
'sotto: carico le textbox della userform con i dati nella cella in quel momento
selezionata, e 'nelle celle adiacenti, sulla stessa riga, ma con "scarto" di una rispetto
alla selezionata
UserForm1.TextBox2 = CL.Value
UserForm1.TextBox3 = CL.Offset(0, 1).Value
UserForm1.TextBox4 = CL.Offset(0, 2).Value
UserForm1.TextBox5 = CL.Offset(0, 3).Value
UserForm1.TextBox6 = CL.Offset(0, 4).Value
UserForm1.TextBox7 = CL.Offset(0, 5).Value
Dim irisposta As Integer 'Imposto la msgbox e relativa domanda
irisposta = MsgBox("Trovato " & Y & ". Vuoi fermarti ?", vbYesNo)
If irisposta = vbYes Then 'se rispondo SI allora
Exit For 'esco dal ciclo
End If
End If
Next CL 'altrimenti proseguo alla successiva cella

End Sub
Ed ora vediamo tutto il codice inserito nel CommandButton1_Click. Cominciamo con le spiegazioni:
intanto viene inserito il controllo se la textbox1, quella che dovr contenere la parola da cercare, sar
vuota, allora avvisa con un messaggio, pone il focus sella textbox1, ed esce dal ciclo senza continuare
l'esecuzione delle istruzioni sottostanti, in caso contenga del testo, avvia l'esecuzione del codice
sottostante
Private Sub CommandButton1_Click()
'controlla che la textbox1 contenga dati
If TextBox1 = "" Then
http://ennius.interfree.it/ Pagina 135
MANUALE VBA X EXCEL
MsgBox "Inserisci Nominativo da cercare"
TextBox1.SetFocus
Exit Sub
End If
'se la textbox1 contiene dati, controlla quale optionbutton attiva (selezionata).La
'propriet che attiva la optionbutton la propriet Value, che dovr essere
impostata a 'True (di default impostata a False). In questo esercizio, ho impostato a
True questa 'propriet, per avere un opzione attivata all'avvio della userform.

If OptionButton1.Value = True Then 'quindi, se attiva la optionbutton1


'allora chiama ed esegue la sub "primo" contenuta nel modulo
primo
End If
'se invece sar la optionbutton2 ad essere attiva, esegue queste altre istruzioni:
If OptionButton2.Value = True Then
'con il Foglio1, nella colonna B da B3 a B150 (zona su cui avviene la ricerca)
With Worksheets(1).Range("B3:B150")

Dim X As String 'dichiarazione del tipo di variabile assegnata ad X


X = TextBox1.Value 'la X sar uguale al dato nella textbox1 che il nominativo da
'cercare
'sotto: l'istruzione Set serve ad assegnare a C il riferimento a cui accedere da parte
del 'metodo Find (trova); cio cercher in C il valore rappresentato dalla X, e lo
cercher 'secondo l'istruzione LookIn=xlValues che consente di cercare dati che
contengano il 'valore di X. E' questa istruzione che consente di trovare una parola,
digitando anche solo 'una parte di essa. Se si volesse una ricerca esatta allora
bisognerebbe completare l'istruzione Find cos: Find(X, LookIn:=xlValues,
LookAt:=xlWhole)
Set C = .Find(X, LookIn:=xlValues) ', LookAt:=xlWhole
'a questo punto C corrisponder alla prima cella corrispondente al valore cercato,
se C corrisponde al valore cercato
If Not C Is Nothing Then
'viene memorizzato come primo indirizzo il riferimento alla cella rappresentata da C
firstAddress = C.Address
'inizia il ciclo Do....Loop. Le istruzioni Do...Loop consentono di eseguire un blocco di
'istruzioni per un numero indefinito di volte. Le istruzioni vengono ripetute fino a
quando 'una condizione True o fino a quando non diventa True
Do
'se la condizione cercata sar True, cio se viene rintracciata una cella che
corrisponde al 'valore cercato, allora questa cella viene selezionata
C.Cells.Select
'ora il contenuto della cella selezionata e di quelle adiacenti (scart) viene riportato
nelle textbox della userform, in modo che si possano visualizzare i dati
TextBox2 = C.Value
TextBox3 = C.Offset(0, 1).Value
TextBox4 = C.Offset(0, 2).Value
TextBox5 = C.Offset(0, 3).Value
TextBox6 = C.Offset(0, 4).Value
TextBox7 = C.Offset(0, 5).Value
Y = C.Value 'assegno a Y in valore contenuto nella cella selezionata e interrompo il
ciclo 'con una msgbox di domanda
irisposta = MsgBox("Trovato " & Y & " . Vuoi fermarti ?", vbYesNo)
If irisposta = vbYes Then 'se rispondo SI allora
GoTo 10 'esco dal ciclo andando a cercare l'istruzione End With
End If
'in caso risponda NO, continuo a cercare (FindNext(C))
Set C = .FindNext(C)
'sotto dico: gira (Loop) fintantoch (While) C non viene trovato e le celle sono
http://ennius.interfree.it/ Pagina 136
MANUALE VBA X EXCEL
successive alla prima (identificata con il riferimento firstAddress)
Loop While Not C Is Nothing And C.Address <> firstAddress
'nel caso la ricerca non abbia dato esito, allora (Else) viene dato il messaggio
Else
MsgBox "Nome non Trovato"
End If
10:
End With 'finisce il ciclo
End If
End Sub
Queste due routine, quella assegnata all'optionbutton1 e quella assegnata all'optionbutton2, sono simili
nell'uso pratico, solo che la prima cercando SOLO valori esatti, pu essere utilizzata in tutti quei casi
dove si voglia la corrispondenza esatta e basta, per esempio nella ricerca di un codice articolo, o di un
numero. In questi casi, se i valori saranno solo numeri, occorrerr modificare la prima istruzione: intanto,
sar possibile inserirla nella routine stessa attivata dal commandbotton1 (Cerca) e non in un modulo
(non ci sar pi la necessit di usare Option Compare Text), e andr posizionata al posto del richiamo
alla Sub primo contenuta appunto nel modulo), e poi, trattandosi di una ricerca Numerica, bisogna
che il codice sappia che il valore da cercare non sar pi un Testo, ma un Numero, e adopereremo
questa modifica nell'assegnazione della variabile alla X
anzich
Dim X As String 'dichiar. di var. per la X
X = UserForm1.TextBox1.Value 'la X sar uguale al dato nella textbox1 che ec.ecc.
si user
Dim X 'dichiar. di var. per la X di tipo Variant
X = Val(TextBox1) 'la X sar uguale al numero nella textbox1 che il
______________________________________________________
Ora vediamo rapidamente le istruzioni collegate agli altri pulsanti. Condizione essenziale comune a
due di queste routine seguenti, (Modificare o Cancellare) che tutte lavorano SE SI E' SVOLTA PRIMA
UNA RICERCA, e quindi la textbox2 conterr dei dati (nominativo). Quindi le procedure seguenti si
potranno attivare SOLO se prima si chiamato il record sul quale AGIRE, (non avrebbe senso infatti,
Modificare o Cancellare qualcosa che non si sia prima evidenziato. Due spiegazioni:
Pulsante "Modifica". Dato che avremo gi una cella "Attiva" e di cui vedremo i dati direttamente nelle
textbox, queste istruzioni si limitano a "riscrivere" nelle stesse celle, i valori che si trovano nelle textbox,
compreso quei valori che nel frattempo possiamo aver modificato.
Pulsante "Cancella record" . Anche in questo caso vedremo gi i dati nelle textbox perch "trovati" col
pulsante "Cerca", e quindi avremo una cella attiva sulla quale intervenire col metodo "Delete". Faccio
eliminare l'intera riga, compreso quindi la cella nella colonna A, quella dove esiste il N riga progressivo,
e quindi ho inserito una semplice istruzione, che cancella tutto il range della colonna A, poi assegna il
valore 1 alla prima cella (A3) e poi aggiunge 1 alle celle seguenti.
Queste le due routine, in sequenza:
Private Sub CommandButton3_Click() 'Pulsante "Modifica"
If TextBox2 = "" Then
MsgBox "Devi Cercare un nominativo per modificarlo"
Exit Sub
End If
ActiveCell.Value = TextBox2
ActiveCell.Offset(0, 1).Value = TextBox3
ActiveCell.Offset(0, 2).Value = TextBox4
ActiveCell.Offset(0, 3).Value = TextBox5
ActiveCell.Offset(0, 4).Value = TextBox6
ActiveCell.Offset(0, 5).Value = TextBox7
MsgBox "Ok! Eseguito!"
End Sub
Private Sub CommandButton4_Click() 'pulsante "Cancella"
If TextBox2 = "" Then Exit Sub 'se la textbox2 vuota, esce dalla routine
'se la textbox2 contiene un dato perch ottenuto con la ricerca, allora seleziona la
cella 'attiva per confermare l'eliminazione dell'intera riga, facendo prima una
domanda
http://ennius.interfree.it/ Pagina 137
MANUALE VBA X EXCEL
ActiveCell.Select
Dim irisposta As Integer
irisposta = MsgBox("Vuoi cancellare il Nominativo: " & ActiveCell.Value & " ?", _
vbYesNo)
If irisposta = vbYes Then
ActiveCell.EntireRow.Delete
'poi pulisce la colonna A, seleziona la cella A3, inserisce 1 e incrementa le celle sotto
di 1 'fino alla fine del range previsto (A3:A152)
Dim CA As Object
Range("A3:A152").ClearContents
Range("A3").Value = 1
For Each CA In Range("A3:A152")
If CA.Offset(1, 0) = "" Then
CA.Offset(1, 0) = CA + 1
End If
Next

End If
End Sub

I pulsanti per la navigazione tra i record, sfruttano entrambi la selezione di una cella, e con la cella
attiva, si muovono verso l'alto o verso il basso sfruttando lo "scarto" (Offset) verso l'alto (-1) o verso il
basso (+1). Per renderli funzionanti anche se non si eseguita nessuna ricerca, faccio selezionare
all'apertura della UserForm, la cella B3, quella nella quale si trover il primo nominativo. Ho inserito due
controlli perch avvisino e si fermino se saremo a inizio o a fine elenco.
questa l'istruzione nell'Initialize della UserForm:
Private Sub UserForm_Initialize()
Worksheets(1).Range("B3").Select
End Sub
e queste le istruzioni inserite nei pulsanti di navigazione:
Private Sub CommandButton5_Click() 'pulsante per "Scorri in Su"
If ActiveCell.Offset(-1, 0).Value = "Nominativo" Then
MsgBox "Siamo a inizio elenco, impossibile salire oltre"
Exit Sub
End If

ActiveCell.Offset(-1, 0).Select
TextBox2 = ActiveCell.Offset(0, 0).Value
TextBox3 = ActiveCell.Offset(0, 1).Value
TextBox4 = ActiveCell.Offset(0, 2).Value
TextBox5 = ActiveCell.Offset(0, 3).Value
TextBox6 = ActiveCell.Offset(0, 4).Value
TextBox7 = ActiveCell.Offset(0, 5).Value

End Sub
Private Sub CommandButton6_Click() 'pulsante per "Scorri in Gi"
If ActiveCell.Offset(1, 0).Value = "" Then
MsgBox "Siamo a fine elenco, impossibile proseguire"
Exit Sub
End If

ActiveCell.Offset(1, 0).Select
TextBox2 = ActiveCell.Value
TextBox3 = ActiveCell.Offset(0, 1).Value
TextBox4 = ActiveCell.Offset(0, 2).Value
TextBox5 = ActiveCell.Offset(0, 3).Value
TextBox6 = ActiveCell.Offset(0, 4).Value
TextBox7 = ActiveCell.Offset(0, 5).Value
http://ennius.interfree.it/ Pagina 138
MANUALE VBA X EXCEL
End Sub
File consultabile e scaricabile : MioDB2-2000.zip 28 Kb

http://ennius.interfree.it/ Pagina 139


MANUALE VBA X EXCEL
Database per Gestione Magazzino e Vendite.
Presento un progetto completo (o quasi) per la gestione di un magazzino prodotti, con registrazione
della quantit venduta e saldo quotidiano dei ricavi. Adatto a tutte quelle attivit dove si voglia una
gestione semplice e veloce dove si voglia amministrare il carico/scarico prodotti con visualizzazione del
venduto e registrazione delle cifre incassate. Scopo di questo esercizio di fornire una progetto
ampliabile e modificabile a piacere, per adattarlo alle varie necessit. Seguendo l'impostazione data
con il primo database presentato in questa sezione (vedi: "Database con spiegazioni") che si fonda
essenzialmente sulla selezione di una cella del database, rendendola quindi ActiveCell, e tramite
l'utilizzo degli Offset, reperire, dialogare, visualizzare, modificare tutti i dati correlati al dato contenuto
nell'ActiveCell. Il concetto molto semplice, pu essere facilmente assimilato leggendo le
spiegazioni fornite nel paragrafo sopra citato. Ovviamente a questo progetto sono state apportare le
modifiche necessarie che ora vedremo Sotto un immagine della form per la gestione dei dati:

All'utente viene lasciato il compito di inserire i seguenti dati: codice articolo, descrizione articolo, costo,
ricarico %, aliquota iva, e fornitore, mentre i calcoli per la determinazione del costo comprensivo del
ricarico, dell'importo iva, del prezzo di vendita, e del valore totale giacenza sono eseguiti dal codice
nel momento in cui si esegue un carico o uno scarico, e registrate in automatico sul database, e nel
caso dello scarico, anche registrate sul Foglio2, che il foglio dove si consulta il venduto della giornata.
Quando si apre la cartella di lavoro, appare la form, viene selezionata la cella A3 che corrisponde alla
prima cella di inizio elenco, e vengono caricate le textbox con i dati dei campi di questa prima riga.
Sar possibile scorrere l'elenco con gli appositi pulsanti, o decidere di eseguire altre operazioni:
Inserimento nuovi articoli
Poich la form si presenta sempre con i dati presenti nella prima riga dell'elenco, PRIMA di premere il
pulsante "Inserisci Nuovo", (che inserirebbe i dati presenti nel database cercando la prima riga libera
dove "scaricare" i dati delle textbox, creando quindi un "doppione" dei dati ivi gi presenti)
necessario premere la barra fucsia per pulire i campi, scrivere i dati nelle textbox abilitate (le textbox
relative ai calcoli non sono abilitate) e SOLO a questo punto premere il pulsante "Inserisci Nuovo". Sono
stanti inseriti gli opportuni controlli per evitare di dimenticare di inserire i dati necessari. I valori da inserire
nei campi "Ricarico" e "Aliquota Iva" DEVONO essere valori SENZA il segno di percentuale (%).
Provvedono le istruzioni a considerarli come tali.(per esempio, come ricarico, si pu inserire 70 MA NON
70%). (vedi foto della barra, sotto)

http://ennius.interfree.it/ Pagina 140


MANUALE VBA X EXCEL
Carico
Una volta che i dati sono stati inseriti nel database, sar possibile agire sul pulsante "Carico". Apparir
un'altra form, nella quale si viene avvisati che si sta eseguendo un carico sull'articolo in quel momento
attivo, si inseriranno i valori e si premer "Conferma". Il codice provvede a fare tutti i calcoli dovuti, ad
aggiornare la form "Magazzino" e il database. Tutti i dati numerici inseriti, vengono trattati come "tipo"
di dati Double, quindi "decimali". Questo per consentire di trattare quantit anche con decimali e
prezzi in euro.

Scarico
La form per lo scarico la form pi densa di istruzioni; intanto controlla che la quantit da scaricare sia
"coperta" dalla giacenza: non si pu scaricare pi di quanto si ha in giacenza. Poi esegue tutti i calcoli
per l'aggiornamento dei valori, sia sulla form "Magazzino", sia sul database; provvede inoltre a
"raccogliere" i dati dell'articolo scaricato ed a comporli in una zona non visibile del foglio1 , e da qui
copia i dati (non tutti) per riportarli nel Foglio2, il foglio dove vengono registrati l' articolo, la quantit
venduta, il prezzo unitario di vendita (quattro valori), con ricerca della prima riga libera per incollare i
dati.. Sul foglio2 sono presenti due formule, una conteggia il totale venduto per articolo, l'altro inserisce
la data del giorno. Una cella porta il totale giornaliero delle vendite. Le celle e le formule sono
predisposte per 300 righe: basta assegnare il formato celle e copiare le formule per quante righe in pi
si vorr. Sono presenti in questo foglio due pulsanti: con uno si pulisce la zona dei dati del giorno prima
(solo i dati, non le formule), e con l'altro pulsante si ritorna sul foglio database e si riattiva la form
"Magazzino". Sotto un immagine del foglio2

Un altra istruzione che viene eseguita dalla form "Scarico", il controllo della quantit giacente dopo lo
scarico: se il valore della giacenza sar zero, viene posta una domanda per l'eliminazione dell'intera
riga : in caso di risposta affermativa la riga dell'articolo con giacenza zero verr eliminata.
Un'ultima precisazione: sulla form "Magazzino" , il pulsante "Mostra Vendite" serve per passare a vista
(senza la form) sul foglio2 per consultare i dati; il pulsante "Esci e Salva" serve per salvare la cartella e
uscire chiudendo anche Excel.
Per le spiegazioni generali, vi rimando al paragrafo "Database con spiegazioni", mentre le istruzioni pi
significative sono spiegate nelle procedure sul file.

File consultabile e scaricabile : Gestione Magazzino.zip 125 Kb

http://ennius.interfree.it/ Pagina 141


MANUALE VBA X EXCEL
Un esercizio completo per la Gestione di un database su Excel

Inserisco questo programma, peraltro richiestomi, come esempio di cosa si possa ottenere con una
buona programmazione. Premetto che quasi tutto il codice NON mio, ma estratto da un articolo di
un "Maestro": Gianni Giaccaglini, che ha pubblicato diversi libri su Excel ed il Vba, (che invito ad
acquistare). E' comunque sintomatico che, aiutandosi con le istruzioni che leggiamo su i libri "guida", si
possa cominciare a capirle ed adattarle alle nostre esigenze.
Il programma consente la gestione di un database completo, basato su una Form di controllo, che
consente di:
Introdurre nuovi dati.
Modificare i dati esistenti.
Navigare tra i record, scalandoli uno per volta, selezionare l'ultimo record inserito o risalire al primo
record.
Ordinare l'elenco dati in base al Nominativo oppure al Numero progressivo.
Eliminare un record.
Tutto questo direttamente dalla Form di gestione. E' stato inserito un pulsante per la ricerca di un
nominativo che, se presente, viene selezionato sul foglio di lavoro, direttamente nel database.
L'esempio riportato nel file allegato, stato predisposto per l'inserimento fino a 600 nominativi. NON
sono stati inseriti n commenti n spiegazioni, e non intendo fornirne. Chi intende scaricare il file, dovr
possedere una certa conoscenza del Vba, e interpretare le istruzioni da solo. Sotto, un immagine del
programma:

File consultabile e scaricabile: Mio db2000.zip 29 Kb

http://ennius.interfree.it/ Pagina 142


MANUALE VBA X EXCEL
UserForm unica per Database su pi fogli
Presento un esempio di come si possa con un'unica UserForm, gestire pi elenchi (database) all'interno
della stessa cartella, ma su pi fogli. Condizione necessaria richiesta: le tabelle che formano il
database dovranno tutte mantenere la stessa "struttura": riferimenti alle celle, numero di campi, riga
inizio elenco, ecc.ecc. per ogni foglio. Questo ci consente quindi di usare un'unica form, sulla quale
saranno posizionati dei pulsanti per spostarsi tra i vari fogli. Una volta sul foglio voluto, gestiremo i dati
presenti su quel foglio, senza avere legami agli altri fogli. Utile quando si voglia, per pi utenti, sfruttare
database personali, diversi nel contenuto, ma simili nella gestione, oppure quando si vogliano tenere
separati per tipologia di appartenenza, nominativi e relativi dati. Nell'esempio preparato, ho usato i
fogli per tipologia di nominativi : amici, nemici, parenti, altri. Ma si possono creare elenchi divisi per
regione, hobby, interessi, affinit, prefisso telefonico, cap, ideologia, religione e chi pi ne ha pi ne
metta. Baster predisporre tanti fogli quante sono le diversificazioni. Sar possibile, per ogni
tabella/foglio, cambiare il nome (NON il numero) dei campi, avendo cura di far cambiare le propriet
Caption delle Label che indicano il contenuto delle relative textbox sulla form, allorch la Form si apre
su quel determinato foglio. (basta inserire le istruzioni nell'evento Click del CommandButton che porta a
quel foglio) . Insomma, c' solo da sbizzarrirsi.
Sfrutteremo il database MioDB2-2000.xls, presente in questa sezione, paragrafo "Database con
spiegazioni", che ben si presta a questa modifica. (Potete consultare la pagina, per accedere alle
spiegazioni relative alle istruzioni impiegate). Sono sufficienti poche modifiche, per ottenere questo
MultiDB2-2000. Grazie alla impostazione, sia per la ricerca, sia per l'inserimento, o la cancellazione di
dati, basata essenzialmente sull'ActiveCell (cella attiva) e sulle celle adiacenti reperite con l'uso di
Offset (Scarto), senza usare riferimenti o nomi di Fogli su cui operare (o quasi), possibile usare il foglio
attivo in quel momento, per ottenere la completa gestione dei dati sopra menzionati, all'interno del
foglio. Questa un immagine del file:

Vediamo le modifiche rispetto all'altro database:


intanto stato cambiato il nome all'UserForm1 in Indirizzario, quindi sono state modificate tutte le
istruzioni che facevano riferimento al nome UserForm1 (nelle chiamate dei pulsanti, all'apertura della
cartella di lavoro, e nel modulo1)
Al posto dell' istruzione che fa riferimento al Worksheet(1) (che l'unico foglio su cui lavora l'altro
database) stato usato ActiveSheet, pi generico, e si riferisce al foglio attivo in quel momento,
adatto quindi ad una multiselezione (uniche due istruzioni, la prima nel commandbutton1, che diventa
With ActiveSheet.Range("B3:B150"), e la seconda nel UserForm_Initialize che diventa
ActiveSheet.Range("B3").Select ).
Per favorire la ricerca dei dati, ho inserito una ComboBox, che "pesca" i dati nel campo "Nominativo".
Selezionando un nominativo presente nella lista, trasferiamo lo stesso nella textbox1, che quella che
serve il pulsante "Cerca". Essendo un nominativo "completo", si potr usare l'opzione di default per una

http://ennius.interfree.it/ Pagina 143


MANUALE VBA X EXCEL
ricerca immediata. Unico accorgimento: dovendo "pescare" i dati che per ogni foglio sono o possono
essere diversi, occorre "istruire" la propriet RowSource della combobox in modo che legga i dati dal
foglio in quel momento attivo, quindi ho usato l'evento Click di ogni pulsante che serve a selezionare
un foglio, quindi dopo aver selezionato il foglio con Sheets(1).Select , faccio prendere il nuovo
riferimento con la seguente istruzione:
If ActiveSheet.Name = ("Foglio1") Then
Indirizzario.ComboBox1.RowSource = "" 'vuoto la combobox dei precedenti dati
Indirizzario.ComboBox1.RowSource = "B3:B152" 'ricarico la combobox con i dati del foglio attivo
Per segnalare all'utente su quale foglio ci troviamo nel momento, ho usato delle CkeckBox che
porterranno un segno di spunta se il foglio attivo in quel momento il foglio x, e lo toglieranno agli altri
fogli (queste sono per il foglio1, ad ogni foglio cambiano da False a True e viceversa).
CheckBox1.Value = True
CheckBox2.Value = False
CheckBox3.Value = False
CheckBox4.Value = False
End If
Poich quando si uscir da Excel, salvando, lo potremo fare da qualunque foglio, ho previsto questa
istruzione che riattiva sia la RowSource della ComboBox sia le Chekbox quando riapriremo il file, e ho
usato l'evento Activate della UserForm, che faccio, ricordo, aprire all'apertura della cartella di lavoro:
Private Sub UserForm_Activate()
Indirizzario.ComboBox1.RowSource = ""
Indirizzario.ComboBox1.RowSource = "B3:B152"
If ActiveSheet.Name = ("Foglio1") Then
CheckBox1.Value = True
CheckBox2.Value = False
CheckBox3.Value = False
CheckBox4.Value = False
End If
If ActiveSheet.Name = ("Foglio2") Then
CheckBox1.Value = False
CheckBox2.Value = True
CheckBox3.Value = False
CheckBox4.Value = False
End If
If ActiveSheet.Name = ("Foglio3") Then
CheckBox1.Value = False
CheckBox2.Value = False
CheckBox3.Value = True
CheckBox4.Value = False
End If
If ActiveSheet.Name = ("Foglio4") Then
CheckBox1.Value = False
CheckBox2.Value = False
CheckBox3.Value = False
CheckBox4.Value = True
End If
Mi sembra di non scordarmi niente, e comunque potete scaricare il file e, se credete, divertirvi.

File consultabile e scaricabile : MultiDB2-2000.zip 42 Kb

http://ennius.interfree.it/ Pagina 144


MANUALE VBA X EXCEL
Realizzare un DataBase senza usare il VBA (o quasi)
In seguito ad alcune richieste e per offrire un'alternativa a tutti coloro che intendono realizzare una
gestione dei propri dati (elenchi di dati) ma hanno poca o nessuna dimestichezza con il Vba, presento
questa soluzione gestibile da chiunque. Si basa sul comando Modulo, attivabile dal men Dati/Modulo.
Un DataBase altro non che un insieme di dati organizzati in campi e in record: cio in colonne e
righe. La struttura di Excel si presta bene quindi alla realizzazione di database, cio di elenchi di dati.
Ogni database che si rispetti porta le "intestazioni di colonna" (campi) cio la descrizione di cosa si
inserir nelle righe sottostanti della colonna stessa. Una agenda indirizzi il classico esempio di in
database che conterr le "intestazioni di colonna" come: numero progressivo, nominativo, indirizzo,
citt, telefono, ecc.ecc; ognuno di questi sar un "campo" e dovr impegnare tante colonne quanti
sono i campi, senza lasciare colonne vuote tra un campo e l'altro. Le righe ospiteranno i dati veri e
propri relativi al campo di appartenenza.. prendendo come esempio la struttura del "Mio Db2000" del
paragrafo precedente, procederemo come segue:
selezioniamo la cella A2, (primo campo del nostro elenco) poi ci spostiamo sul menu Dati, clicchiamo
su Modulo, ed apparir la maschera che vediamo nell'immagine seguente:

Se vi appare un messaggio in cui Excel comunica di non riuscire a determinare quale riga contiene le
etichette di colonna, proseguite premendo sul pulsante OK. (questo messaggio non apparir pi
appena inserito il primo dato). Intanto esaminiamo la maschera: nella barra di intestazione viene
riportato in automatico il nome del foglio di lavoro, sulla sinistra ci sono i nomi dei "campi" (le intestazioni
di colonna che vediamo sul foglio nella riga 1), a lato si possono leggere i dati contenuti nei rispettivi
campi, una barra verticale di scorrimento che serve per una scorsa veloce dei dati presenti nell'elenco;
sulla destra notiamo dei pulsanti di chiaro significato, servono per: aggiungere nuovi dati (Nuovo):
premendo questo pulsante sar possibile inserire, nelle apposite caselle che si presenteranno vuote, i
nuovi dati: premendo il tasto INVIO (Enter) sulla tastiera, i dati verranno registrati su una riga vuota. Gli
altri tasti si commentano da soli: eliminare dati, scorrere le righe alla ricerca di un dato: dato
precedente, dato successivo. Il pulsante "Criteri" serve per una ricerca mirata basata su uno dei campi
presenti, per esempio per cercare un determinato nominativo. Premuto il pulsante: la maschera
assumer questa immagine:

http://ennius.interfree.it/ Pagina 145


MANUALE VBA X EXCEL

Ci troveremo in modalit "Criteri": sar possibile digitare un nome o parte di un nome perch si attivi la
ricerca premendo su uno dei pulsanti "Trova", oppure ritornare alla maschera precedente, premendo il
pulsante "Modulo". Se avessimo inserito nel campo Nominativo la parola "pec", e premuto il pulsante
"Trova succ." ci saremmo trovati con la maschera che mostra il record trovato, come sotto nella foto:

Ecco quindi un pratico sistema per ottenere una maschera di introduzione, modifica, ricerca dati,
senza avere fatto ricorso a nessuna "subdola" pratica Vba. Unica concessione. un pulsante per
risparmiarci il "fastidio" di richiamare la maschera dal menu Dati, usando il pulsante stesso collegato ad
una semplice macro:
Sub Apri()
Range("A2").Select
ActiveSheet.ShowDataForm
End Sub
che serve ad attivare la maschera (ShowDataForm).

File scaricabile e consultabile: Modulo2000.zip 21Kb

http://ennius.interfree.it/ Pagina 146


MANUALE VBA X EXCEL

http://ennius.interfree.it/ Pagina 147


MANUALE VBA X EXCEL
UserForm unica per pi Database sulla stessa cartella
Ancora una variante realizzata sullo "scheletro" del Multi DB2-2000, dove, a differenza di quest'ultimo
che sfrutta la struttura di una tabella di partenza (stesso numero di campi, stessa intestazione dei
campi, stesse impostazioni per inizio riga delle tabelle), e che si muove sui fogli grazie alle istruzioni
collegate a dei commandbutton, ma che rimane, come base, impostata sulla gestione di pi
database TUTTI inerenti per solo a indirizzari, in questo caso si vuole diversificare la tipologia di dati da
inserire, in modo da avere sempre un'unico file, un'unica userform per introdurre i dati, ma la possibilit
di gestire insieme, una Agenda Indirizzi, una Libreria, una Musicoteca, ed una Videoteca. Anche in
questo caso, condizione comune ai quattro database, il mantenimento dello stesso NUMERO di
campi. (E' possibile, per i pi volenterosi, aumentare il numero di campi desiderati, variando
opportunamente le istruzioni, in particolare per la lettura/scrittura dei campi event. aggiunti, tramite
l'aggiunta di nuove TextBox (da rendere visibili/non visibili alla bisogna) e dei riferimenti relativi agli
Scarti (Offset) dell'ActiveCell aggiunte per i nuovi campi, abbinate ai pulsanti che porteranno alle
pagine dove queste modifiche sono state fatte). Per questo nuovo database sono state apportate
alcune modifiche : intanto facciamo ridurre ad icona la finestra di Excel, in modo che resti visibile solo
la form per la gestione dei dati, e per questo sufficiente inserire nel WorkBook_Open, questa
istruzione:
Application.WindowState = xlMinimized
poi, per essere sicuri che quando si preme sul pulsante ESCI, vengano salvate tutte le modifiche fatte ai
vari fogli, e ripristinata la posizione della Finestra di Excel come in origine, nell'evento Click del Pulsante
Esci sono state aggiunte queste istruzioni:
For Each cartella In Application.Workbooks
cartella.Save
Next cartella
Application.WindowState = xlMaximized
Application.Quit
End
La propriet Caption del pulsante ESCI stata modificata in ESCI & SALVA. In questo modo si esce
dalla cartella e si chiude anche Excel.
Sono stati rinominati i campi dei vari fogli, in modo da corrispondere al tipo di dati che inseriremo per
es. in Libreria, non esiste Nominativo, ma Titolo del libro, non Indirizzo ma Autore, ecc.ecc. Per far s che
anche sulla UserForm. al variare del tipo di database ospitato nel foglio selezionato, vengano
aggiornate anche le etichette che indicano il tipo di dati da introdurre o presenti nelle textbox, per
ogni pulsante che ci sposta ad un foglio, sono state aggiunte le istruzioni opportune, vediamo un
esempio per quando selezioniamo il foglio3 (pulsante "Musica"):
Sheets(3).Select
If ActiveSheet.Name = ("Foglio3") Then
TextBox2 = ""
TextBox3 = ""
TextBox4 = ""
TextBox5 = ""
TextBox6 = ""
TextBox7 = ""
Indirizzario.ComboBox1.RowSource = ""
Indirizzario.ComboBox1.RowSource = "B3:B152"
CheckBox1.Value = False
CheckBox2.Value = False
CheckBox3.Value = True
CheckBox4.Value = False
Label1.Caption = "Cantante"
Label2.Caption = "Titolo"
Label3.Caption = "Genere"
Label4.Caption = "CD-titolo"
Label5.Caption = "Anno Pubblic."
Label6.Caption = "Prezzo"
Label7.Caption = "Scrivi il Cantante da cercare:"
Label10.Caption = "MUSICA"
OptionButton1.Caption = "Cerca Cantante (esatto)"
http://ennius.interfree.it/ Pagina 148
MANUALE VBA X EXCEL
OptionButton2.Caption = "Cerca Cantante (parziale)"
End If

Come si vede, vengono reimpostate le propriet Caption delle Label con le nuove intestazioni dei
campi presenti sul foglio3. Vengono altres pulite tutte le textbox, per evitare di vedere dei dati che
appartengono ad un foglio precedente. Queste istruzioni saranno presenti in ogni pulsante di
navigazione tra i fogli, ovviamente con le giuste modifiche. Questa un immagine se si su Agenda:

e questa un immagine di quando saremo su Musica

Come si nota le Label sono aggiornate per i nuovi campi. Altrettanto succeder per gli altri fogli.

File consultabile e scaricabile : VariusDB2-2000.zip 61 Kb

http://ennius.interfree.it/ Pagina 149


MANUALE VBA X EXCEL
Dichiarazione Variabili - accorgimenti

Non molti sanno che quando in una istruzione in codice vb (e quindi anche Vba) si usano variabili,
eseguendo l'istruzione, si occupa memoria del computer (RAM), e che quando l'istruzione arrivata
alla fine (End Sub), questa memoria non viene "scaricata" dalle variabili che si accumulano e
continuano ad occupare memoria. Esiste un'istruzione che si pu usare, e che serve a cancellare dalla
memoria le variabili prima create. Facciamo un esempio, vediamo una macro in cui si usa una
variabile per assegnare un valore che potr cambiare:
Sub Esempio()
Dim X 'in assenza del "tipo" di variabile, il codice interpreta la variabile come Variant
X = Range("A1").Value 'X la variabile
...seguono le istruzioni
End Sub
Bene, sufficiente inserire prima di "End Sub" questa riga:
Set X = Nothing
e lo spazio in memoria occupato dalla X sar cancellato. L'istruzione andr ripetuta per tutte le variabili
caricate nella routine. Un'altro accorgimento, se si lavora con le UserForm, visto che anche l'apertura di
una form costringe il computer a "caricare" in memoria tutti i dati che riguardano la Form stessa
(compreso gli "oggetti" inseriti (TextBox, CommandButton, ecc.)) sar quella di usare la stessa istruzione
vista sopra, ma per azzerare la form dalla memoria. Se si chiude la form con in classico "UnLoad Me",
opportuno scrivere una riga in pi di codice: Set UserForm1 = Nothing prima di End Sub. Oppure uscire
con l'istruzione "End" prima di "End Sub", e questa istruzione provvede da sola a chiudere la form ed
azzerare la form dalla memoria.

http://ennius.interfree.it/ Pagina 150


MANUALE VBA X EXCEL
Doppi cicli For .. Next per eseguire ricerche, somme, numero di "presenti", ecc..
Un interessante esercizio, almeno lo spero, indirizzato all'intercettazione di dati, presenti su righe di un
elenco, e contemporaneamente, su colonne dello stesso elenco, per restituzione di somme dei dati
trovati, oppure di numero di dati simili presenti. L'esercizio si presta ad una molteplicit di utilizzi,
variando i termini della ricerca, e del tipo di restituzione del risultato, oppure lo schema di come
effettuare la ricerca. Presento quindi due varianti:
una per la restituzione del numero di presenze di una variabile (una cella vuota, ma poteva essere su
celle contenente il valore "pippo", oppure un numero specifico, o ancora su numeri superiori o inferiori
ad un determinato valore, ecc.ecc.)
l'altra, per ottenere il totale dei valori presenti in ogni colonna.
In entrambi i casi, eseguiremo il controllo su un'intere colonne, iniziando dalla prima colonna
richiamata dal ciclo,ottenendo il risultato in una cella della colonna adiacente, poi ci sposteremo sulla
colonna successiva a quella su cui abbiamo ottenuto il totale, e cos via per quante colonne vorremo.
Se controlliamo la colonna A, otterremo il risultato nella colonna B, poi ci sposteremo a controllare la
colonna C, otterremo il risultato nella colonna D, si sposteremo a controllare la colonna E, ecc. ecc.
Visto che useremo una colonna intera, di volta in volta, e non sapendo quanto potr essere lungo, in
termini di righe il nostro elenco, dovremo ricorrere ad un accorgimento. Poich nell'esempio simulo la
presenza di celle vuote, e non possiamo usare la funzione End, per determinare la lunghezza elenco,
useremo un "interruttore" che "stoppi" il ciclo di ricerca sulla colonna, dandoci il risultato e passando al
controllo della colonna a lato. Questo "interruttore" potremo inserirlo manualmente in qualsiasi cella si
preveda come limite massimo di un elenco, o al limite nell'ultima cella della colona, che la 65536.
L'importante inserirlo, e come "interruttore" potremo usare qualsiasi valore, numero, testo o data,
possibilmente diverso dal tipo di dati che la nostra colonna conterr. Ma vediamo il primo esempio:
Controllare e Contare il numero di celle vuote. Useremo il valore 2 come "interruttore". La routine
prevede due cicli di ricerca (il primo per le colonne, con salto di una colonna (Step 2), con all'interno
"annidato" un secondo ciclo che cercher all'interno della colonna i dati voluti. Controlleremo le
colonne dalla 1 alla 11 (cio dalla A alla K) con il ciclo For X = 1 To 11.
Sub ContaVuote()
'dichiarazione di una variabile (CL = Cella) come Object
Dim CL As Object
'inizializzazione di un contatore cv (celle vuote)
cv = 0
'inizio ciclo per spostarsi tra le colonne, saltandone una
For X = 1 To 11 Step 2
'assegnazione alla variabile y dell'indirizzo di colonna X (la prima sar quindi A:A)
y = ActiveSheet.Columns(X).Address
'inizio del ciclo di ricerca del valore o cella, cercati per ogni cella della colonna y
For Each CL In Range(y)
'in questo caso cerchiamo le celle vuote, se la cella sar vuota, allora
If CL.Value = "" Then
'incrementiamo di una unit il contatore
cv = cv + 1
'se invece troviamo una cella col valore uguale a 2 ("interruttore"), allora
ElseIf CL.Value = 2 Then
'nella cella a destra (offset) e quindi colonna B, scriviamo il valore del contatore, che
a 'questo punto corrisponde al numero di celle vuote trovate.
CL.Offset(0, 1).Value = cv
'riazzeriamo il contatore
cv = 0
'usciamo da questo ciclo
Exit For
End If
Next
'finito il ciclo sulla colonna appena controllata, continuiamo con Next il primo ciclo
sulle 'colonne, che ci porter alla colonna C, e poi a seguire per quante volte
previsto (1 to 11 'Step 2)
Next
End Sub
http://ennius.interfree.it/ Pagina 151
MANUALE VBA X EXCEL
Se anzich celle vuote, avessimo voluto controllare quante volte una parola, ad esempio "Rossi", come
in un elenco di Clienti, fosse presente, sarebbe bastato cambiare l'istruzione di ricerca, cos:
If CL.Value = "Rossi" Then
e sarebbe stato riportato il numero di quante volte "Rossi" era presente, dall'inizio colonna fino
all'interruttore.
Secondo esempio:
Controllare e Sommare i valori presenti nelle celle per ottenere un totale. Diversificando il criterio di
ricerca del secondo ciclo interno, potremo ottenere un totale personalizzato. In questo caso,
operando su numeri, come "interruttore" sar opportuno usare del testo. Nell'esempio mi limito a
sommare tutti i valori presenti, colonna per colonna:
Sub SommaValori()
'vedi sopra
Dim CL As Object
'dichiarazione del tipo di variabile (totale) come Long. Se i numeri fossero con
decimali, 'sarebbe necessario usare Double
Dim totale As Long
'inizzializzazione di totale con valore = zero
totale = 0
''inizio ciclo per spostarsi tra le colonne, saltandone una
For x = 1 To 11 Step 2
'assegnazione alla variabile y dell'indirizzo di colonna X (la prima sar quindi A:A)
y = ActiveSheet.Columns(x).Address
'inizio del ciclo di ricerca del valore, cercati per ogni cella della colonna y
For Each CL In Range(y)
'qui iniziamo prima con la ricerca dell'interruttore, e useremo un nome (pippo), nel
caso 'venga trovata la cella con questo testo, allora
If CL.Value = "pippo" Then
'inseriamo il totale che si sar formato dagli incrementi di totale, nella cella a lato
CL.Offset(0, 1).Value = totale
'azzeriamo totale
totale = 0
'usciamo dal ciclo interno
Exit For
'se invece il valore di una cella sar diverso da vuoto (quindi contiene un numero),
allora
ElseIf CL.Value <> "" Then
'sommiamo questo valore a totale
totale = totale + CL.Value
End If
'passiamo alla cella successiva, stessa colonna
Next
'terminato il controllo fino alla cella interruttore, passiamo alla colonna successiva
Next
End Sub

Sar possibile eseguire controlli su ogni colonna, eliminando il comando Step 2 all'inizio del primo ciclo,
ed ottenere il risultato, sia nel primo esempio, sia nel secondo, facendo scrivere il risultato NON nella
colonna a lato, ma nella stessa colonna dove si effettua la ricerca, spostando con Offset la cella di
destinazione: stessa colonna della ricerca, una riga sotto la cella dove st l'interruttore, esempi:
CL.Offset(1, 0).Value = cv (primo esempio)
CL.Offset(1, 0).Value = totale (secondo esempio)

http://ennius.interfree.it/ Pagina 152


MANUALE VBA X EXCEL
Controllare dati doppi con sostituzione del dato duplicato con dati presenti su altra cartella chiusa.
(23/03/03)
L'esercizio:
In due colonne di una tabella (che chiameremo Tab1 per nostra comodit di riferimento) su un foglio
di lavoro, (colonna A e B, per esempio) si possono trovare, per ogni riga, due valori eguali nelle due
colonne.
Vogliamo controllare la colonna B: se il valore presente sar uguale al valore presente nella stessa riga
della colonna A, vogliamo che il valore doppio della colonna B venga sostituito con il valore presente
in un'altra tabella (che chiameremo TabOrigine) posta sul Foglio1 di una altra cartella chiusa presente
sul nostro HD.
Nella cartella chiusa presente un elenco su pi colonne (TabOrigine) : la prima colonna (a sinistra, la
A), contiene valori univoci uguali ai valori presenti nella colonna A della Tab1. Vorremo quindi reperire il
valore correlato posto nella seconda colonna ( la B ) della TabOrigine, e sostituirlo al valore doppio
presente nella colla B della Tab1. Per fare questo sfrutteremo la Funzione CERCA.VERT posta all'interno
del nostro ciclo di ricerca dati doppi.
Il ciclo eseguir un controllo dei valori presenti in ogni riga della colonna B della Tab1; nel caso che il
valore a lato (colonna A) sia uguale, si effettua la funzione CERCA.VERT e si sostituisce il valore cos
trovato. Per evitare che Excel, trattandosi di un "collegamento" ad un altro foglio (e chiuso), presenti la
finestra di conferma provenienza dati, inseriamo un semplice : Application.DisplayAlerts = False
Sotto le immagini delle due tabelle; i nomi e i valori sono d'esempio.
Tab1 TabOrigine

Come vediamo in Tab1, esistono valori uguali nelle righe 1, 2. 4, 6, 10. La routine controller i valori nelle
due colonne, e nel caso siano uguali svolger la Funzione CERCA.VERT sulla TabOrigine andando a
"pescare" il dato correlato al valore uguale al dato cercato nella colonna B (colore). Faremo inoltre
controllare se il valore presente nella colonna B di Tab1 diverso dal valore della stessa riga colonna A:
in questo caso faremo scrivere in B la parola "Sconosciuto". Facciamo anche controllare se le celle
della colonna B e rispettiva cella della colonna A saranno vuote: in questo caso passeremo alla riga
successiva fino al termine del ciclo. Nel caso di dati doppi nella Tab1, ma il cui valore non venga
trovato nella TabOrigine, nella cella colonna B apparir il messaggio #N/D : valore non disponibile.
E questo il risultato prodotto dalle nostre istruzioni nella Tab1:

http://ennius.interfree.it/ Pagina 153


MANUALE VBA X EXCEL
e queste le istruzioni. Come si nota, nella Funzione CERCA.VERT (in inglese VLOOKUP), si deve indicare il
percorso dove risiede il file con la TabOrigine. Attenzione alla sintassi.
Sub TrovaeSostituisci()
Dim CL As Object
'sotto: indichiamo al ciclo For Each CL (per ogni cella) su quale Range agire
For Each CL In Range("B1:B10")
'se la cella vuota passa a Next (successivo)
If CL.Value = "" Then GoTo 10
'se il valore della cella uguale al valore della cella a destra (colonna A)
If CL.Value = CL.Offset(0, -1).Value Then
'sotto: evita l'apparizione della finestra di conferma
Application.DisplayAlerts = False
'allora nella cella (CL) poni la funzione cerca.vert (che inizia la ricerca in TabOrigine
a 'partire dalla quinta riga colonna A, fino alla riga 65530 colonna B, e riporta il
valore contenuto nella seconda colonna (2)
CL.FormulaR1C1 = _
"=VLOOKUP(RC[-1],'C:\Archivio\[Dati.xls]Foglio1'!R5C1:R65530C2,2,FALSE)"
'sotto: se invece il valore nella celle B diverso dalla cella in A (CL.Offset(0, -1)
ElseIf CL.Value <> CL.Offset(0, -1).Value Then
'allora mi scrivi nella cella B la parola "SCONOSCIUTO"
CL.Value = "SCONOSCIUTO"
'sotto: se invece (ancora) le due celle sono vuote, esci dalla routine. ATTENZIONE a
'questa istruzione: lo scopo quello di far terminare il ciclo se saremo a fine elenco,
'istruzione necessaria specie se abbiamo impostato un Range lungo, e vogliamo
appunto 'uscire quando saranno finiti i dati, altrimenti il ciclo prosegue fino alla fine
anche se 'trovasse celle vuote, che per il codice vengono viste "uguali". E'
NECESSARIO quindi 'NON lasciare righe vuote in A e in B se esistono dati nelle righe
successive perch la 'routine terminerebbe senza controllare i dati sottostanti.
ElseIf CL.Value = "" And CL.Offset(0, -1).Value = "" Then
Exit Sub
End If
10:
Next
End Sub
E' evidente che se i dati da riportare (TabOrigine) non fossero su un'altra cartella, ma sulla stessa
cartella aperta dove risiede la Tab1, sar ancora pi semplice e baster modificare il percorso che
mira alla TabOrigine; quindi se questa fosse sulla stessa cartella sul foglio2, baster scrivere:
CL.FormulaR1C1 = "=VLOOKUP(RC[-1],Foglio2!R5C1:R65530C2,2,FALSE)"
e non sarebbe pi necessaria l'istruzione: Application.DisplayAlerts = False

http://ennius.interfree.it/ Pagina 154


MANUALE VBA X EXCEL
Estrarre dati da un elenco e formare una tabella di riepilogo dati estratti
Quando abbiamo necessit, e capita spesso, di volere un riepilogo di dati presenti in una tabella
(elenco), estratti in base ad un nostro criterio di ricerca, possiamo adoperare una routine realizzata in
vba. Ottenere una tabella che sia il frutto di un filtraggio di dati esistenti, sicuramente interesser pi di
un "pellegrino", per questo propongo una routine che, nella sua semplicit, potr essere adattata e
modificata da chiunque. Facendo il solito esempio, supponiamo di avere un elenco di fatture da cui
vorremo estrarre solo quelle relative ad un certo nominativo, e delle fatture, ci interessi avere l'importo
di ognuna, per farne anche il totale. Potrebbe essere altres un elenco di agenti, con a lato il fatturato,
e di voler conoscere quanto ha fatturato un determinato agente. Di situazioni similari sono pieni i fogli
di excel, quindi procediamo con l'esempio delle fatture. Nell'esempio avremo la colonna A da A1 a
A200 dove avremo il nome del cliente o del fornitore, e nella colonna B l'importo di ogni fattura.
Sfrutteremo la colonna E per ottenere il nostro riepilogo, ed useremo la cella C1 per scrivere il nome di
cui vogliamo eseguire la ricerca. La cella F2 invece ci servir per ottenere la somma totale degli importi
delle fatture estratte(filtrate). Ognuno sar libero di adattare i propri riferimenti sia alle colonne che
contengono l'elenco dati, sia alla colonna dove creare la tabella riassuntiva, come pure alle celle che
ospiteranno il criterio di ricerca (C1) o il totale (F2). Alcune considerazioni su come lavora la routine:
dato un valore in C1 assegnato alla variabile X, per ogni cella del range A1:A200 verr svolta la ricerca
dello stesso valore (X), se trovato, verr copiato il valore che nella cella a destra (Offset), e verr
copiato nella colonna E, dove col metodo End, verr cercata la prima cella libera e l, incollato il
valore copiato. Ricordo che con End(xlDown).Offset ecc. E' necessario far trovare le prime due celle
da inizio selezione (E1) occupate da qualsiasi cosa ( per chiarimenti leggere eventualmente il
paragrafo "Copia/Incolla2" in questa sezione). Ad ogni lancio routine, facciamo pulire le celle in E,
prima di iniziare il ciclo di ricerca, copia, incolla. Nella cella F2 metteremo la funzione =SOMMA(F3:F203)
per avere il totale degli importi filtrati. A posto di scrivere un nome nella cella C1, sar possibile inserire
una casella di riepilogo (combobox) con le propriet LinkedCell = C1 e ListFillRange = A1:A200. Questo
l'esempio:

E queste le istruzioni:
Sub riassumi()
Dim CL As Object
Dim X
Application.ScreenUpdating = False
Range("E3:E200").ClearContents
X = Range("C1").Value
For Each CL In Range("A1:A200")
If CL = X Then
http://ennius.interfree.it/ Pagina 155
MANUALE VBA X EXCEL
CL.Offset(0, 1).Select
Selection.Copy
Range("E1").Select
Selection.End(xlDown).Select
ActiveCell.Offset(1, 0).Select

'incollo i dati.
With ActiveCell
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End With
End If
Next
Application.CutCopyMode = False
End Sub

http://ennius.interfree.it/ Pagina 156


MANUALE VBA X EXCEL
Elenchi zebrati. (11/05/03)
Ovvero: come differenziare il colore delle righe di un elenco, alternando una riga colorata ed una no
oppure una riga di un colore e un'altra di un'altro colore.
Prendendo spunto da una domanda postami sulla Formattazione Condizionale, nasce questo articolo
che presento con varie soluzioni, la prima delle quali mi ha sorpreso non poco. Premesso che il buon
vecchio Excel ci consente a volte di crearci le nostre istruzioni in molte maniere, per ottenere lo stesso
risultato, questa volta, seguendo una procedura che sfruttando il metodo Add, consente di definire
una condizione nella creazione di una Formattazione Condizionale tramite vba, venuto fuori che la
sintassi della formula usata per definire la condizione, DEVE ESSERE IMPOSTATA CON FUNZIONI IN
ITALIANO. Strano ma vero, e non so il perch, se uso la normale sintassi in inglese tipica del vba, non si
ottiene il risultato voluto. Ma vediamo l'origine del caso :
Si vuole alternare il colore delle righe di un elenco, in modo che i dati siano pi facilmente leggibili o
stampabili, cio desideriamo creare un "elenco zebrato". Un ragionamento logico : identifichiamo le
righe che corrispondono al numero pari, per esempio, e coloriamo quelle (quindi la 2,4,6,8,,10, ecc).
Allora sfruttiamo la Funzione "RESTO" (in inglese=MOD) la quale fornisce come risultato di una divisione,
soltanto il resto. Sapendo questo, facile impostare l'istruzione : se un numero di riga diviso 2 d come
resto zero, allora......infatti tutti i numeri pari diviso 2 danno sempre come resto un bello zero, cio non ci
sono decimali. (stiamo parlando di Resto, non di Quoziente), e quindi nasce la formula, vediamola
prima in italiano:
=SE(RESTO(RIF.RIGA();2)=0;VERO;FALSO)
la stessa in inglese, da usare nel codice:
=IF(MOD(ROW(),2)=0,TRUE,FALSE)
Impostiamo quindi tutta la procedura:
'Reperiamo la zona di cui vogliamo l'elenco zebrato
Range("A1:J20").Select
'cancelliamo nella zona selezionata eventuali formattazioni condizionali presenti,
istruzione 'comunque necessaria per poter applicare il metodo Add
Selection.FormatConditions.Delete
'impostiamo la format. condiz. tramite la formula
Selection.FormatConditions.Add Type:=xlExpression, Formula1:= _
"=IF(MOD(Row(),2)=0,true,false)"
'e a seguito del reperimento delle righe, applichiamo il colore alle righe
Selection.FormatConditions(1).Interior.ColorIndex = 35
Orrore, Orrore, il debugger si lamenta immediatamente indicando un errore nella composizione della
formula; strano, si controlla, ci sembra scritta correttamente, virgole comprese (in vba i punti e virgola
della stessa formula in versione Foglio di lavoro, si devono scrivere come virgole). Vuoi vedere che il
debugger protesta proprio per le virgole? Allora le sostituiamo con punti e virgola e proviamo. Questa
volta il debugger non dice niente, ma neanche succede niente. Allora tento l'ultima carta, vacca
miseria, un controsenso, ma tanto vale...e...cos funziona. Giuro che non so perch. Questa la macro:
Sub Colora()
Range("A1:J20").Select
Selection.FormatConditions.Delete
Selection.FormatConditions.Add Type:=xlExpression, Formula1:= _
"=SE(RESTO(RIF.RIGA();2)=0;VERO;FALSO)"
Selection.FormatConditions(1).Interior.ColorIndex = 35
End Sub
e questo il risultato:

http://ennius.interfree.it/ Pagina 157


MANUALE VBA X EXCEL

Esistono comunque altre procedure che si possono attivare per ottenere lo stesso risultato; una
procedura che propongo, semplice da capire, e in due versioni: colorare una sola riga, o colorare le
righe a colori alterni, inoltre tratteggiando le celle delle righe selezionate per migliorare la vista a video;
la prima:
Sub Zebrauno()
Set zona = Range("A1:F15") 'si imposta la zona su cui agire
For Each rw In zona.Rows 'per ogni riga delle righe presenti in zona
If rw.Row Mod 2 = 0 Then 'se il numero riga diviso 2 come resto da zero, allora
rw.Interior.ColorIndex = 35 'si colora la riga
rw.Borders.LineStyle = xlDashDotDot 'si contornano le celle delle righe con il
tratteggio
End If
Next rw 'si passa alla riga successiva
End If
e questo il risultato:

la procedura a due colori, simile alla precedente:


Sub Zebradue
Set zona = Range("A1:F15")
For Each rw In zona.Rows
If rw.Row Mod 2 = 0 Then
rw.Interior.ColorIndex = 35
rw.Borders.LineStyle = xlDashDotDot 'xlContinuous
Else 'con Else si interviene sulle altre righe (che forniscono un resto diverso da zero)
rw.Interior.ColorIndex = 36 'cambia il colore
rw.Borders.LineStyle = xlDashDotDot 'xlContinuous
End If
Next rw
End Sub
e questo il risultato:

http://ennius.interfree.it/ Pagina 158


MANUALE VBA X EXCEL

Se poi si volessero togliere le zebrature e ripristinate il foglio all'origine, baster predisporre queste
semplici istruzioni da collegare ad un altro pulsante:
per l'elenco ad una sola riga colorata:
Sub canctut()
Set zona = Range("A1:F15")
For Each rw In zona.Rows
If rw.Row Mod 2 = 0 Then
rw.Interior.ColorIndex = xlNone
rw.Borders.LineStyle = xlNone
End If
Next rw
End Sub
per l'elenco con entrambe le righe colorate:
Sub canctutdue()
Set zona = Range("A1:F15")
For Each rw In zona.Rows
If rw.Row Mod 2 = 0 Then
rw.Interior.ColorIndex = xlNone
rw.Borders.LineStyle = xlNone
Else
rw.Interior.ColorIndex = xlNone
rw.Borders.LineStyle = xlNone
End If
Next rw
End Sub
Se poi preferite lavorare di meno, date in occhiata all'articolo "Elenchi zebrati" presente sul sito, sezione
"Primi passi".
Buon Lavoro.

http://ennius.interfree.it/ Pagina 159


MANUALE VBA X EXCEL
Eliminare dati doppi di coppie di nuneri.
Ovvero: ricerca ed eliminazione righe se i valori di due celle contigue sono uguali a valori di due altre
celle contigue, nelle stesse colonne di un elenco. esempio
A B
1 10 20
2 7 32
3 10 20
4 8 15
I valori nelle due celle della riga 3 sono uguali ai valori nelle due celle della riga 1. Andr eliminata la
riga 3.
Una problematica peraltro evidenziata da alcune richieste, di cui viene presentata una soluzione, non
unica, ma che possiede il grande pregio della eccezionale velocit di esecuzione utilissima in
particolare con lunghi e lunghissimi elenchi (50.000 e oltre righe) dove le coppie valori da controllare
impegnano notevole tempo se si usano i normali cicli a due variabili.
Questa routine stata realizzata da MICHELE email mic1947@libero.it
Il sistema escogitato da Michele, in pratica, utilizza una colonna esterna all'elenco (la H) dove
"concatena" i valori presenti nelle coppie di celle da esaminare, ottenendo un unico numero non
confondibile, ma uguale ad altre "concatenazioni" di stesse coppie di numeri se presenti nelle righe
dell'elenco, e crea quindi un elenco di pari lunghezza rispetto all'origine. Poi lavora su questa colonna :
identifica il valore della prima cella di questa zona (assegnata alla variabile "MioIntervallo"), e con un
ciclo For Each .... Next controlla partendo dalla fine (Step -1) e a salire, se trova un valore uguale alla
prima cella dell'elenco; se la trova uguale, viene eliminata l'intera riga. Finito il controllo dei valori della
prima cella, si passa alla riga successiva (alla prima (Riga + 1)), ripetendo il controllo dalla fine, a salire.
Finito il ciclo dei controlli, seleziona tutta la colonna usata come "MioIntervallo", e cancella i contenuti
rimasti. La soluzione di Michele, oltre che intelligente, veramente veloce: su un Pentium4 1800, su un
elenco di 48 coppie di numeri ripetute 10 volte, accodando fino ad ottenere un elenco di 480 righe, ha
totalizzato 1 secondo nell'eliminazione di tutte le righe ripetute. Un bel risultato!!! Questa la routine,
comprensiva delle istruzioni per il conteggio dei tempi di esecuzione.
Sub elidodue()

Dim Riga
Dim MioIntervallo As Range
Dim CL As Object
Dim D1, D2 As Date
Dim tempoimpiegato As String
D1 = Time

Application.ScreenUpdating = False
Range("A1").End(xlDown).Select
R = ActiveCell.Row
For Y = 1 To R
Cells(Y, 8).Select
ActiveCell = Cells(Y, 1).Value & Cells(Y, 2).Value
Next
Set MioIntervallo = Range(Cells(1, 8), Cells(R, 8))
Riga = 2
For Each CL In MioIntervallo

For z = R To Riga Step -1


If CL.Value = Cells(z, 8) Then Sheets(1).Cells(z, 8).EntireRow.Delete
Next
Riga = Riga + 1
Next
Riga = 2
Columns("H:H").Select
Selection.ClearContents
Range("A1").Select

http://ennius.interfree.it/ Pagina 160


MANUALE VBA X EXCEL
D2 = Time
tempoimpiegato = Format(D2 - D1, "hh:mm:ss")
MsgBox "Tempo impiegato: " & tempoimpiegato

End Sub
L'interpretazione delle istruzioni, anche se presuppone una certa conoscenza del codice vba, non
difficile, quindi gli interessati potranno facilmente adattare le istruzioni ai propri riferimenti.
Un grazie a Michele, specie da quei "pellegrini" che gradiranno questa sua interpretazione di un
problemino comune a molti.

http://ennius.interfree.it/ Pagina 161


MANUALE VBA X EXCEL
Eliminazione dati doppioni da un elenco
Impiego: ricerca ed eliminazione intera riga di dati doppi contenuti in un elenco (tabella)

A gentile richiesta (??), pensando che potr interessere altri visitatori, propongo questa macro
realizzata in seguito ad una domanda rivoltami: automatizzare con il Vba, la ricerca in un elenco, di
dati doppi, e loro eliminazione insieme ad eventuali dati correlati (quindi eliminazione dell'intera riga).
E' un applicazione utile quando si debba avere a che fare con lunghi elenchi di dati, come per
esempio una gestione di articoli di un magazzino, dove pu capitare di inserire pi volte una stessa
voce, e dove quindi sia necessario rivedere e correggere l'elenco. Il funzionamento di queste istruzioni
semplice: si basa prima su un ordinamento A-Z dei dati presenti, basato su una chiave di
ordinamento, che potrebbe essere il codice articolo (contenuti in questo esempio nella colonna B)
con scartamento di eventuali righe vuote (che bloccherebbero il ciclo Do While...Loop) e nella ricerca
del valore di ogni cella (a scalare) con i valori delle successive : nel caso vengano riscontrati valori
uguali, la riga che contiene il doppione verr eliminata. Ognuno potr modificare i Range su cui
eseguire il controllo, adattandoli alle proprie esigenze. Questo il codice da associare ad un pulsante
che risieder nelle stesso foglio su cui si esegue la ricerca
:
Sub EliminaDoppioni()
'Questo codice ordina i dati nella seconda
'colonna del foglio Dati ed elimina le righe che
'contengono dati duplicati.
Application.ScreenUpdating = False
Range("B4:B800").Select
Selection.Sort Key1:=Range("B4"), Order1:=xlAscending, Header:=xlGuess, _
OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom, _
DataOption1:=xlSortNormal

Set currentCell = Worksheets("Dati").Range("B4")


Do While Not IsEmpty(currentCell)
Set nextCell = currentCell.Offset(1, 0)
If nextCell.Value = currentCell.Value Then
currentCell.EntireRow.Delete
End If
Set currentCell = nextCell
Loop
Range("B4").Select

End Sub

http://ennius.interfree.it/ Pagina 162


MANUALE VBA X EXCEL
Estrarre dati casuali da un elenco o tabella. (29/03/03)
Trovo interessante segnalare un esercizio scaturito da una richiesta ricevuta : l'estrazione casuale di
nomi, (propri, di citt, di animali, di piante, ecc.ecc.), ma vale anche per l'estrazione di numeri. Mentre
per i numeri la Funzione ROUND() specifica, proprio perch valori numerici, per i nomi (o comunque
testo o date) bisogna creare un Indice (e quindi un numero) che identifichi un determinato valore in
formato testo o data. Potremmo creare degli Array i quali restituiscono il valore dichiarato in funzione
dell'indice rappresentato, ma sceglieremo una strada diversa, che ci consenta di poter modificare non
solo il nostro testo come pi ci piace, ma di decidere a piacere da quante parole sar formato il nostro
elenco. Useremo quindi o una sola colonna dove scrivere, riga dopo riga, le parole che vorremo
randomizzare creando un elenco o tabella, oppure pi righe e pi colonne per avere una tabella
ancora pi ampia. In questo modo con il numero di riga e/o di colonna, avremo i nostri numeri da
poter randomizzare. Vediamo quindi i passaggi dei due casi.
Area posta su una sola colonna, la colonna A che la prima
identificazione dell'area che contiene i dati; con UsedRange identifichiamo l'area qualunque sia la
lunghezza.
Set zona = ActiveSheet.UsedRange
trovare da quante righe formata l'area cos reperita, ed assegnazione del valore numerico ad una
variabile ( la x )
x = zona.Rows.Count
(*)estrazione di un numero casuale compreso tra 1 ed il valore che la variabile x conterr; poich per il
vba i numeri partono da zero (e noi non avremo una riga zero, ma partiremo sempre da riga uno),
aggiungiamo + 1 al valore casuale estratto (infatti, supponendo di avere 50 righe, in realt l'intervallo
sarebbe da zero compreso a quarantanove compreso, che fanno appunto 50 numeri). Il valore
numerico cos trovato rappresenter il numero di riga. Questo valore lo assegnamo ad una variabile
(quale)
quale = Int(x * Rnd) + 1
ora preleviamo con un'altra variabile ( la Y ) il valore presente nella cella rappresentata dalla riga
quale indicando la colonna 1 ( Cells(quale, 1), supposto di avere l'elenco nella colonna A ) che sar
un nome, e formiamo un messaggio che mostrer il nome cos trovato.
Y = Cells(quale, 1).Value
MsgBox Y
Precisazione: se l'elenco fosse invece in un'altra colonna, la C per esempio ( che la numero 3 )
dovremmo nell'istruzione sopra descritta, indicare con 3 l'indice colonna, cos:
Y = Cells(quale, 3).Value
Per evitare la ripetitivit nella sequenza dei valori restituiti dovremo adoperare la funzione Randomize
che utilizza numero per inizializzare il generatore di numeri casuali della funzione Rnd assegnandogli un
nuovo valore. Se numero viene omesso, il valore restituito dal timer di sistema verr utilizzato come
nuova base.
Se Randomize non viene utilizzata, quando la funzione Rnd (senza argomenti) viene chiamata per la
prima volta, utilizza come base lo stesso numero. Per le chiamate successive la funzione utilizzer
l'ultimo numero generato.

E questa la routine:
Sub Acaso()
Set zona = ActiveSheet.UsedRange
x = zona.Rows.Count
Randomize
quale = Int(x * Rnd) + 1
Y = Cells(quale, 1).Value
MsgBox Y
End Sub
Se invece la tabella sar stata creata su pi colonne, sempre supponendo di avere l'inizio elenco nella
colonna A (la prima) avremo bisogno di contare anche da quante colonne formata , sempre
rintracciando la nostra area con l'UsedRange, con queste modifiche:
z = zona.Columns.Count
e di creare una casualit anche per le colonne, con:
dove = Int(z * Rnd) + 1
e di reperire quindi un indice cella che oltre al numero di riga porter anche il numero di colonna, con
http://ennius.interfree.it/ Pagina 163
MANUALE VBA X EXCEL
Y = Cells(quale, dove).Value
ed alla fine la routine completa in questo caso sar:
Sub Acasodue()
Set zona = ActiveSheet.UsedRange
x = zona.Rows.Count
z = zona.Columns.Count
Randomize
quale = Int(x * Rnd) + 1
dove = Int(z * Rnd) + 1
Y = Cells(quale, dove).Value
MsgBox Y
End Sub
ATTENZIONE: tutte queste routine si basano su una tabella che inizi dalla riga 1 e dalla colonna A. La
variabile Y identifica il numero di riga e di colonna generati dalla randomizzazione, e quindi numeri
casuali compresi tra 1 e il numero di righe e di colonne che formeranno la nostra tabella. Poich
l'istruzione Cells (Cells(quale, dove).Value) usata su un foglio di lavoro inizia a contare dalla prima cella
(la A1) per trovare la cella Y rappresentata dai valori quale e dove, SE LA TABELLA iniziasse dalla riga 3
e dalla colonna C (anch'essa la numero 3), avremo bisogno di aggiungere questi numeri (3 e 3) al
numero indice che serve a generare il numero casuale. Il motivo di ci anticipato al punto con
l'asterisco rosso (*) pi sopra, e quindi le nostre istruzioni verrebbero modificate su queste due righe:
quale = Int(x * Rnd) + 4
dove = Int(z * Rnd) + 4
anzich
quale = Int(x * Rnd) + 1
dove = Int(z * Rnd) + 1
Infatti, sempre rifacendo l'esempio delle 50 righe, avremmo bisogno di partire dalla riga 3, e quindi
avremo 3 righe, + 1 per correggere l'indice zero, = 4. in questo modo otteniamo che se la
randomizzazione del valore 50 (rappresentato da x) generasse zero, avremo 0 + 4 che indica la riga 3,
se invece il numero casuale generato fosse 49 (limite superiore del valore 50 visto con inizio da zero), il
numero di riga corrispondente sarebbe 53. Lo stesso vale per l'indice colonna se la colonna fosse la C.
Spero di essere stato sufficientemente chiaro.

http://ennius.interfree.it/ Pagina 164


MANUALE VBA X EXCEL
Estrarre dati da un elenco e formare una tabella di riepilogo dati estratti
Quando abbiamo necessit, e capita spesso, di volere un riepilogo di dati presenti in una tabella
(elenco), estratti in base ad un nostro criterio di ricerca, possiamo adoperare una routine realizzata in
vba. Ottenere una tabella che sia il frutto di un filtraggio di dati esistenti, sicuramente interesser pi di
un "pellegrino", per questo propongo una routine che, nella sua semplicit, potr essere adattata e
modificata da chiunque. Facendo il solito esempio, supponiamo di avere un elenco di fatture da cui
vorremo estrarre solo quelle relative ad un certo nominativo, e delle fatture, ci interessi avere l'importo
di ognuna, per farne anche il totale. Potrebbe essere altres un elenco di agenti, con a lato il fatturato,
e di voler conoscere quanto ha fatturato un determinato agente. Di situazioni similari sono pieni i fogli
di excel, quindi procediamo con l'esempio delle fatture. Nell'esempio avremo la colonna A da A1 a
A200 dove avremo il nome del cliente o del fornitore, e nella colonna B l'importo di ogni fattura.
Sfrutteremo la colonna E per ottenere il nostro riepilogo, ed useremo la cella C1 per scrivere il nome di
cui vogliamo eseguire la ricerca. La cella F2 invece ci servir per ottenere la somma totale degli importi
delle fatture estratte(filtrate). Ognuno sar libero di adattare i propri riferimenti sia alle colonne che
contengono l'elenco dati, sia alla colonna dove creare la tabella riassuntiva, come pure alle celle che
ospiteranno il criterio di ricerca (C1) o il totale (F2). Alcune considerazioni su come lavora la routine:
dato un valore in C1 assegnato alla variabile X, per ogni cella del range A1:A200 verr svolta la ricerca
dello stesso valore (X), se trovato, verr copiato il valore che nella cella a destra (Offset), e verr
copiato nella colonna E, dove col metodo End, verr cercata la prima cella libera e l, incollato il
valore copiato. Ricordo che con End(xlDown).Offset ecc. E' necessario far trovare le prime due celle
da inizio selezione (E1) occupate da qualsiasi cosa ( per chiarimenti leggere eventualmente il
paragrafo "Copia/Incolla2" in questa sezione). Ad ogni lancio routine, facciamo pulire le celle in E,
prima di iniziare il ciclo di ricerca, copia, incolla. Nella cella F2 metteremo la funzione =SOMMA(F3:F203)
per avere il totale degli importi filtrati. A posto di scrivere un nome nella cella C1, sar possibile inserire
una casella di riepilogo (combobox) con le propriet LinkedCell = C1 e ListFillRange = A1:A200. Questo
l'esempio:

E queste le istruzioni:
Sub riassumi()
Dim CL As Object
Dim X
Application.ScreenUpdating = False
Range("E3:E200").ClearContents
X = Range("C1").Value
For Each CL In Range("A1:A200")
If CL = X Then
http://ennius.interfree.it/ Pagina 165
MANUALE VBA X EXCEL
CL.Offset(0, 1).Select
Selection.Copy
Range("E1").Select
Selection.End(xlDown).Select
ActiveCell.Offset(1, 0).Select

'incollo i dati.
With ActiveCell
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End With
End If
Next
Application.CutCopyMode = False
End Sub

http://ennius.interfree.it/ Pagina 166


MANUALE VBA X EXCEL
Estrarre dati da un elenco e inviare il nuovo elenco in stampa.
A seguire dall'esempio della precedente pagina (Estrarre dati da elenco), propongo un esercizio un p
pi articolato, e che spesso ci troviamo ad affrontare: disponendo di un database (elenco clienti,
elenco fornitori, agenda indirizzi, elenco prodotti, ecc.ecc), vogliamo un riepilogo (o se preferite un
"elenco filtrato") in modo da formare un nuovo elenco da mandare in stampa.
Premesso che ci sono diversi modi per ottenerlo, (compreso un ordinamento basato su chiave di
ricerca che possiamo variare di volta in volta (agendo sulla chiave di ricerca), con selezione anche
manuale dell'area che ci interessa e stampare poi questa selezione), questo esercizio basato sulla
ricerca di tutti i nomi che iniziano per una determinata lettera dell'alfabeto.
Una InputBox ci chieder di quale lettera desideriamo eseguire il filtraggio ed estrazione dati , e le
istruzioni provvederanno a comporre la nuova tabella con i nomi e i dati correlati che vorremo. Ho
diviso le istruzioni in due macro: una per l'estrazione dati ed una per la stampa, ma possibile unire le
istruzioni in unica macro: estrarre i dati e mandarli in stampa in un colpo solo.
Attenzione!!: la ricerca CaseSensitive, cio sensibile alle maiuscole/minuscole. Se formiamo il
database con nomi di cui la prima lettera scritta in maiuscolo (per esempio: Bellini) e nella inputbox,
per la ricerca scriveremo b (minuscolo) saranno trovati solo i nomi con la b minuscola (e i Bellini no).
Ricordatevi quindi di definire un sistema di ricerca che corrisponda al sistema usato per l'archiviazione
dati.
In questo esempio posizioniamo il database su un foglio (foglio2) mentre il riepilogo lo facciamo sul
foglio 1 .Va bene qualunque altro foglio, solo per lavorare con la ricerca dati da eseguire su un foglio
"remoto" in modo da accontentare anche coloro che si chiedono come "pescare" i dati se si trovano
non sullo stesso foglio del riepilogo. La foto sotto mostra un elenco a tre campi, (nominativo, indirizzo,
citt) sul foglio2:

Queste sotto invece mostrano la InputBox con la richiesta di quale lettera immettere (nell'esempio la
"b"), e il foglio1 con l'elenco dei dati estratti relativi a tutti i nomi che nel database cominciano con la
"b", ed i pulsanti associati alle due macro:

http://ennius.interfree.it/ Pagina 167


MANUALE VBA X EXCEL

Sotto vediamo la zona che va in stampa. La macro interessata alla stampa, individua, a partire dalla
riga 3, e per le tre colonne, l'ultima riga occupata, seleziona l'area cos identificata, e la invia alla
stampante. Soluzione necessaria visto che non possibile stabilire a priori quanto sar lungo l'elenco
degli estratti.

Queste le due macro e relative spiegazioni:


Sub Riassumi()
Dim CL As Object
Dim x, messaggio, titolo
'questa sotto evita il saltellamento dei fogli a schermo
Application.ScreenUpdating = False
'siamo sul foglio1, si pulisce un'area da A3 a C200. Se gli elenchi estratti fossero pi
'lunghi, baster aumentare il range
Range("A3:C200").ClearContents
'si imposta il messaggio e il titolo della inputbox
messaggio = "Scrivi l'iniziale dei nomi da estrarre"
titolo = "Estrai dati"
'sotto: rendiamo x uguale a ci che scriveremo nell'inputbox
x = InputBox(messaggio, titolo)
If x = "" Then Exit Sub 'se non scriviamo niente (x = vuoto) si esce dalla routine
'sotto: per ogni cella (CL) sul foglio2 nel range che va da A1 a A200
For Each CL In Sheets(2).Range("A1:A200")
Sheets(2).Select 'riseleziono il foglio2 al rientro del ciclo (Next)
'sotto: se la prima lettera a sinistra del valore che sar nella cella uguale alla prima
lettera in x, (con 'Left(CL, 1) si confronta la prima lettera del nome che nelle celle),
allora
If Left(CL, 1) = Left(x, 1) Then
'sotto: si seleziona sul foglio2 dalla cella trovata alla 3^ cella, stessa riga
Sheets(2).Range(CL, CL.Offset(0, 2)).Select
Selection.Copy 'si copia la selezione

Sheets(1).Select 'ci si sposta sul foglio1


Range("A1").Select 'si seleziona la prima delle celle del nostro elenco di
destinazione. (ricordo le prime due celle da far trovare occupare usando l'istruzione
End)
Selection.End(xlDown).Select 'si cerca l'ultima cella occupata (la seconda)
ActiveCell.Offset(1, 0).Select 'si seleziona la cella sotto che vuota

'incollo i dati (continuando a cercare (sopra) la prima cella libera.


http://ennius.interfree.it/ Pagina 168
MANUALE VBA X EXCEL
With ActiveCell
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False

End With
End If
Next 'continuo il ciclo

Sheets(1).Select 'alla fine dell'estrazione ritorno sul foglio1


Range("C1").Select 'seleziono la cella C1
Application.CutCopyMode = False
End Sub
quella per la stampa:
Sub stampa()
Worksheets("Foglio1").Select
Dim x, y 'dichiarazione di variabili
y = Range("A3:C3").Address 'con y prendo i riferimenti dalla colonna A alla C riga 3
x = Range("A3").End(xlDown).Address 'con x prendo il riferimento alla ultima cella
'occupata nella colonna A partendo dalla cella A3
Range(y, x).Select 'seleziono tutta l'area identificata dai riferimenti y x
PrintArea = Selection 'dichiaro che l'area di stampa corrisponde alla selezione
Selection.PrintOut Copies:=1, Collate:=True 'invio la selezione alla stampante
Range("C1").Select
End Sub
20/02/03. L'amico Michele ( mic1947@libero.it ) mi suggerisce di fornire la soluzione alla limitazione
maiuscole/minuscole che limita l'uso della routine di ricerca, con l'impiego delle funzioni LCase e
UCase in modo che qualunque sia il formato della lettera scritta nell'inputbox, la ricerca venga
comunque effettuata. Ritengo giusto il suggerimento e a questo punto aggiungo anche le istruzioni per
l'ordinamento alfabetico con chiave di ordinamento basato sul nome, in modo che l'elenco degli
estratti si presenti per ordine alfabetico. Questa la routine modificata, aggiungo le spiegazioni solo alle
nuove istruzioni :
Sub riassumiordina()
Dim CL As Object
Dim x, messaggio, titolo

Application.ScreenUpdating = False
Range("A3:C200").ClearContents
messaggio = "Scrivi l'iniziale dei nomi da estrarre"
titolo = "Estrai dati"
x = InputBox(messaggio, titolo)
If x = "" Then Exit Sub

W = LCase(x) 'con LCase si assimila la variante x come lettera minuscola


Z = UCase(x) 'con UCase si assimila la variante x come lettera maiuscola

For Each CL In Sheets(2).Range("A1:A200")


Sheets(2).Select
'sotto: se la prima lettera del nome trovato minuscola o maiuscola....
If Left(CL, 1) = Left(W, 1) Or Left(CL, 1) = Left(Z, 1) Then

Sheets(2).Range(CL, CL.Offset(0, 2)).Select


Selection.Copy

Sheets(1).Select
Range("A1").Select
Selection.End(xlDown).Select
ActiveCell.Offset(1, 0).Select

http://ennius.interfree.it/ Pagina 169


MANUALE VBA X EXCEL
'incollo i dati.
With ActiveCell
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False

End With

End If
Next
Sheets(1).Select
'ritornati sul foglio1 si seleziona l'elenco estratti e si ordina alfabeticamente
y = Range("A3:C3").Address
x = Range("A3").End(xlDown).Address
Range(y, x).Select
Selection.Sort Key1:=Range("A3"), Order1:=xlAscending, Header:=xlGuess, _
OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom, _
DataOption1:=xlSortNormal
'volendo mandare subito in stampa l'elenco, senza usare il secondo pulsante, e visto
che 'l'elenco gi selezionato, possiamo aggiungere anche le istruzioni per la
stampa:
PrintArea = Selection 'dichiaro che l'area di stampa corrisponde alla selezione
Selection.PrintOut Copies:=1, Collate:=True 'invio la selezione alla stampante
Range("C1").Select
Application.CutCopyMode = False
End Sub
File scaricabile e consultabile (prima routine) : Estraidati2000.zip 14 Kb

http://ennius.interfree.it/ Pagina 170


MANUALE VBA X EXCEL
Evitare Ripetizioni (nell'inserimento di dati in una tabella) (14/01/03)
Praticamente si tratta di un "Controllo inserimento dati". Un'altra dimostrazione che tramite Vba, si
possono comporre istruzioni che mirino allo stesso scopo, variando completamente il modo di controllo.
Questa volta ci occuperemo della trasposizione in codice di una funzione del foglio di lavoro : la
funzione =CONTA.SE
Questa funzione, l'abbiamo gi vista impiegare in " Usare Convalida (2)" , nella sezione "formule". L'
istruzione controlla se le celle di un determinato Range contengono lo stesso valore che si trover in
una cella (che useremo come vettore per la ricerca), se tale vettore sar trovato sar pari a 1, e la
formula riscontra VERO, altrimenti restituisce FALSO. L'istruzione andrebbe compilata cos e verrebbe
posta in una cella, per esempio la C1:
=CONTA.SE(A1:A100;B1)=1
e dice praticamente: controlla se il valore che in B1 presente nel range che va da A1 a A100, se lo
trovi scrivi (in C1) VERO, altrimenti scrivi FALSO.
Questo potrebbe essere un modo alternativo per il controllo dell'inserimento dati, peraltro ottenibile
usando la "Convalida Dati" di Excel. In genere questi controlli si eseguono quando si debbano
introdurre dati "univoci", come un numero di fattura, oppure un codice articolo. Volendo quindi
applicare in Vba questa funzione, faremo un esempio: supponiamo di avere una colonna dove
inseriremo il numero di fattura, e lo posizioniamo nella colonna A, a partire dalla prima cella. Seguendo
la falsariga della funzione sopracitata, avremo bisogno di una cella che funzioni da vettore, e di una
cella dove "alloggiare" la formula stessa. Visto che ci apprestiamo ad usare del codice, perch non
usare una finestra di introduzione dati, una InputBox, che render un p pi "professionale" il nostro
lavoro? Avremo bisogno anche di "convertire" il risultato della funzione (VERO, FALSO) in un istruzione
che ci consenta di annullare la scrittura se il numero fattura che vorremo inserire esiste gi, mentre
vorremo che il numero stesso venga scritto, se non presente, e venga scritto nella riga successiva
all'ultimo numero presente nel range previsto. Ecco quindi una routine che ci consente di fare quanto
detto (in verde sono le spiegazioni):
Sub introduzionedati()
'dichiarazione delle variabili per la InputBox
Dim messaggio, titoto, Valore
titolo = "Introduzione dati" 'ci che vedremo nella barra del titolo dell'inpputbox
messaggio = "Introduci il numero" 'il testo che appare come istruzione da seguire
Valore = InputBox(messaggio, titolo) 'Valore sar uguale al dato inserito nella casella
di 'testo della inputbox.
If Valore = "" Then Exit Sub 'se non scriveremo niente, si esce dalla routine

'anzich una cella visibile, assegno la cella B60000 a contenere il valore che funger
da 'vettore (valore), cio il secondo argomento della funzione Cerca.Se (CountIf)
Range("B60000") = Valore
'assegno a X la cella A60000 (una cella sicuramente non visibile), che sar la cella
dove 'avremo il risultato della funzione (come per la C1 della formula iniziale)
Set X = Range("A60000")
'pongo in A60000 (X) la formula =CONTA.SE
X.Formula = "=COUNTIF(A1:A100,B60000)=1"
'inizio il ciclo di controllo sulla X, cio la cella A60000
If X.Value = True Then 'se il valore sara uguale a vero, cio sar stato trovato il
numero 'nell'elenco previsto A1:A100
MsgBox "Valore Gi presente" 'si viene avvisati da un messaggio
X = "" 'viene pulita la cella A60000
Range("B60000") = "" 'viene pulita la cella B60000
Exit Sub 'si esce dalla routine
Else 'invece (in caso contrario, cio se il numero non presente nell'elenco)
Range("A1").End(xlDown).Select 'seleziono l'ultima cella occupata a partire dalla A1
ActiveCell.Offset(1, 0).Select 'seleziono la cella sotto che vuota
ActiveCell = Valore 'nella cella attiva copio il vettore (valore) scritto nella inputbox
X = "" 'poi viene pulita la cella A60000
Range("B60000") = "" 'poi viene pulita la cella B60000
End If
End Sub
http://ennius.interfree.it/ Pagina 171
MANUALE VBA X EXCEL
E questa la variante con la descrizione nel messaggio della InputBox dell'ultimo numero presente, in
modo che si sappia comunque qual' l'ultimo numero inserito (non ripeto le spiegazioni gi fornite nella
routine sopra):
Sub introducicontrolla()
Dim Z
Z = Range("A1").End(xlDown).Value 'a Z viene assegnato il valore presente nell'ultima
'cella occupata partendo dalla A1
Dim messaggio, titoto, Valore
titolo = "Introduzione dati"
messaggio = "Introduci il numero, l'ultimo usato il N " & Z & "" 'ho aggiunto nel
'messaggio l'ultimo numero presente (Z)
Valore = InputBox(messaggio, titolo)

If Valore = "" Then Exit Sub

Range("B60000") = Valore
Set X = Range("A60000")

X.Formula = "=COUNTIF(A1:A100,B60000)=1"
If X.Value = True Then
MsgBox "Valore Gi presente"
X = ""
Range("B60000") = ""
Exit Sub
Else
Range("a1").End(xlDown).Select
ActiveCell.Offset(1, 0).Select
ActiveCell = Valore
X = ""
Range("B60000") = ""
End If
End Sub

Usare la Funzione Timer


Esempio di Utilizzo : Fare lampeggiare celle per richiamare attenzione.

Pu necessitare di volere richiamare l'attenzione dell'operatore sul verificarsi di un determinato evento.


Oltre al sistema di avvisare tramite un suono (Beep), pu essere di maggiore efficacia usare dei colori
che si attivino e lampeggino, come se fosse una luce che si accende e si spenge richiedendo
attenzione. Questo effetto come un "Lampeggiatore" lo potremo attivare usando la funzione Timer,
con la quale possibile stabilire il tempo di durata assegnando un valore che rappresenta il numero di
secondi di "accensione". Come al solito presento un esempio, in cui faccio lampeggiare due Range di
celle, alternativamente, di rosso e di giallo. Ho scelto un Range esteso per ottenere un maggior
richiamo visivo. Ognuno potr definire le zone che vorr. La routine si basa sull'ipotesi che, quando in
una determinata cella (ho considerato la E1) compare un certo valore (ho usato "Pippo"), si deve
attivare la routine e quindi il lampeggiare. Va da s che ognuno potr variare le condizioni di
attivazione secondo le proprie necessit. Il ciclo si ripete secondo l'istruzione For x = 1 To 5, cio per 5
volte, desiderando cicli diversi, baster variare il 5 con altro numero. Quando la routine termina il
numero di cicli previsti, faccio apparire un messaggio (io ho usato "Attenzione!!!") che blocca l'uscita e
lascia le celle con i colori assegnati dall'ultimo ciclo. Solo premendo Ok sulla finestra del messagio, si
sblocca il codice che prosegue l'istruzione, riportando le celle all'origine (senza colore), ed esce dalla
routine. Questo il codice da provare associando la macro ad un pulsante:
Sub Lampeggia()
If Range("E1").Value = "Pippo" Then
Dim PauseTime, Start, Finish
For x = 1 To 5 'inizia il ciclo e lo ripete per 5 volte
PauseTime = 0.5 ' Imposta la durata in secondi. ho messo 1/2 secondo
Start = Timer ' Imposta l'ora di inizio.
http://ennius.interfree.it/ Pagina 172
MANUALE VBA X EXCEL
Do While Timer < Start + PauseTime
DoEvents ' Passa il controllo ad altri processi.
Range("A1:D7").Cells.Interior.ColorIndex = 3 'colora il range di celle di rosso
Range("A12:D21").Cells.Interior.ColorIndex = 6 'colora il range di celle di giallo
Loop
Finish = Timer ' Imposta l'ora di fine della pausa.

PauseTime = 0.5 ' Imposta la durata.


Start = Timer ' Imposta l'ora di inizio.
Do While Timer < Start + PauseTime
DoEvents ' Passa il controllo ad altri processi.
Range("A1:D7").Cells.Interior.ColorIndex = 6
Range("A12:D21").Cells.Interior.ColorIndex = 3
Loop
Finish = Timer ' Imposta l'ora di fine della pausa.
Next x

'finisce il ciclo, appare un messaggio


'che blocca i colori
MsgBox "ATTENZIONE!!!!"
'premuto ok sul messaggio, vengono eliminati i colori
Range("A1:D7").Cells.Interior.ColorIndex = xlNone
Range("A12:D21").Cells.Interior.ColorIndex = xlNone
'finisce
End
End If
End Sub

http://ennius.interfree.it/ Pagina 173


MANUALE VBA X EXCEL
Far lampeggiare (blinking) i Fonts (i caratteri). (09/06/03)
Un modo di evidenziare determinate situazioni che si verificano sul foglio di lavoro, potrebbe essere
affrontato con l'esercizio che sto presentando : intervenire sui fonts alternando colori diversi dei fonts in
modo da creare l'effetto "lampeggio", che richiamerebbe inevitabilmente l'attenzione di chi sta
lavorando.
Classici esempi di utilizzo potrebbero essere controlli su elenchi di numeri (se il valore che si avr in una
cella o range di celle, non sia maggiore o minore di determinati valori, oppure se in una somma totale
si raggiunge o si supera un certo valore, oppure ancora se compare un determinato numero, ecc.),
controlli su testo o ancora su date, insomma, le condizioni da poter valutare sono talmente tante che
ognuno adatter i concetti alle proprie esigenze.
Intanto vediamo le condizioni necessarie per usare le routine:
L' area su cui intervenire - potremo assegnarla su una singola cella, oppure su pi celle anche non
contigue, oppure su un Range di celle, o ancora su tutto il foglio di lavoro.
L'evento per attivare - potremo affidarci ad un pulsante che lanci la macro, oppure scegliere un
automatismo come l'evento WorkSheet_Change per richiamare la macro ad ogni cambiamento nella
celle/celle o area predefinita.
Interruzione della macro - in questo caso realizzeremo una routine che ci consenta manualmente,
tramite un pulsante, di interrompere l'effetto "lampeggio" .
Le istruzioni per ottenere il "lampeggiare" si basano sul metodo OnTime di cui riporto la descrizione
reperibile sulla guida in linea del VBE:
Metodo OnTime
Programma una routine affinch venga eseguita a una determinata ora futura, vale a dire a una
determinata ora del giorno o dopo un determinato periodo.
Sintassi :
espressione.OnTime(EarliestTime, Procedure, LatestTime, Schedule)
Osservazioni
Utilizzare Now + TimeValue(time) per una programmazione in un'ora successiva all'ora corrente.
un esempio che esegue la macro my_Procedure 15 secondi dopo l'ora corrente:
Application.OnTime Now + TimeValue("00:00:15"), "my_Procedure"

il concetto semplice: OnTime basa la partenza sull'ora attuale (Now che corrisponde ad ADESSO())
alla quale aggiunge un tempo che decideremo noi, in questo esempio 15 secondi, dopodich lancia
la macro (il cui nome racchiuso tra doppi apici e preceduta da una virgola). Impostando il tempo ad
1 secondo, otterremo l'effetto "lampeggio". Ma modificheremo opportunamente queste istruzioni per
farle rispondere alle nostre esigenze, non vogliamo infatti lanciare nessuna macro tramite OnTime,
bens inizializzarla. Vediamo le istruzioni, in verde i soliti commenti:
Usando un Modulo per ospitare le macro, inseriamo nella sezione "Generale - Dichiarazioni" del
modulo la variabile NextTime come Date, comune ad entrambe le macro.
Dim NextTime As Date
__________________________________________________________________
Sub Lamp()
'sotto : impostiamo l'area sulla quale intervenire settando la variabile "zona"
Set zona = Range("E1:G20") 'un'area presa ad esempio
'impostiamo la variabile NextTime che sar uguale a Now pi un secondo
NextTime = Now + TimeValue("00:00:01")
'sotto: Con i caratteri nelle celle nell'area scelta (zona)
With zona.Cells.Font
'se il colore dei fonts nero, lo colori rosso, altrimenti lo colori nero, questo che
crea 'l'effetto "lampeggio" ogni secondo
If .ColorIndex = 1 Then .ColorIndex = 3 Else .ColorIndex = 1
End With 'fine Con....
'sotto: trascorso il primo secondo, si rilancia la stessa macro "Lamp" sfruttando
ancora il 'metodo OnTime
Application.OnTime NextTime, "Lamp"
End Sub
ora vediamo la routine per interrompere l'istruzione appena vista. Anche in questo caso si ricorre al
metodo OnTime, ma sfruttando l'argomento Schedule che, impostato a False, consente di "cancellare"
una (la) routine impostata precedentemente (Lamp). Oltre all'interruzione della routine, abbiamo
http://ennius.interfree.it/ Pagina 174
MANUALE VBA X EXCEL
bisogno di inserire un'istruzione che ripristini il colore dei fonts a nero, nel caso che si sia interrotta la
routine mentre i fonts erano colorati in rosso. Queste le istruzioni:
Sub Stoppa()
Set zona = Range("E1:G20")
'sotto: si richiama col metodo OnTime la macro "Lamp", ma con "schedule" uguale a
'False, la interrompiamo, cancellandola
Application.OnTime NextTime, "Lamp", schedule:=False
'si ripristina il colore nero nei fonts
zona.Cells.Font.ColorIndex = xlAutomatic
End Sub
Quindi, viste le due routine, che potranno essere entrambe attivate da pulsante (la macro "Stoppa"
dovr essere comunque sempre attivata manualmente), prendiamo in esame come automatizzare
l'avvio della macro "Lamp". Come gi detto, diverse sono le necessit di essere avvisati, con il
lampeggio, per cui prendiamo in esame un evento solo il Worksheet_Change, ma con due diverse
istruzioni:
Lampeggiare dei fonts su tutta l'area al verificarsi anche in una sola cella di una determinata
condizione.
Lampeggiare dei fonts solo su due celle nell'area al verificarsi di una determinata condizione, uguale e
anche diversa per ognuna delle due celle.
Prima ipotesi: se in una qualsiasi cella della zona scelta, sar immesso un valore superiore a 3500
Private Sub Worksheet_Change(ByVal Target As Range)
' necessario creare un ciclo For Next per controllare i valori di tutte le celle dell'area
Dim C As Object
Set zona = Range("E1:G20") 'impostiamo la zona
For Each C In zona 'per ogni cella in zona
If C.Value > 3500 Then 'se il valore in una cella maggiore di 3500
Lamp 'si chiama la macro Lamp
End If
Next
End Sub
E' pacifico che se i criteri per l'attivazione fossero pi di uno, dovremo modificare le istruzioni If con
l'aggiunta degli operatori And oppure Or, o con l'inserimento di altre condizioni tramite ElseIf.
Seconda ipotesi: se in due celle ben definite si verificher una certa condizione: attiveremo la macro
Lamp se nella cella F2 oppure nella cella F7 ci sar un valore superiore a 3500
Private Sub Worksheet_Change(ByVal Target As Range)
Set X = Range("F2")
Set Y = Range("F7")
If X > 3500 Or Y > 3500 Then
Lamp
End If
End Sub
Se invece si volesse che in entrambe le celle si verifichi che un valore superi 3500 per attivare il
lampeggio, baster modificare la riga:
If X > 3500 Or Y > 3500 Then
con
If X > 3500 And Y > 3500 Then
Per interrompere il lampeggio cliccheremo sul pulsante associato alla macro "Stoppa".

http://ennius.interfree.it/ Pagina 175


MANUALE VBA X EXCEL
Uso del Filtro personalizzato in vba, con le date.
Ancora un esercizio basato sull'applicazione del filtro personalizzato, basato sulla ricerca di dati
compresi tra una data ed un altra, il tutto realizzato in vba.
Supponiamo di voler filtrare tutti i record compresi tra due date, il 10/01/03 e il 15/02/03. Applicheremo
quindi il filtro sul campo "data", selezioneremo "personalizzate" nel men del campo, e si aprir la
finestra per la selezione dei "criteri di ricerca". Ovviamente sceglieremo il primo criterio "uguale o
maggiore" del 10/01/03, e come secondo criterio "minore o uguale" a 15/02/03. Se ci aiutiamo usando
il "Registratore di macro", vedremo che nelle istruzioni compilate da Excel, alle voci "Criteria1" e
"Criteria2", viene usata la seguente sintassi:
omissis...AutoFilter Field:=10, Criteria1:=">=10/01/2003", Operator:= _
xlAnd, Criteria2:="<=15/02/2003"
cio per l'assegnazione del criterio le date vengono scritte tra doppi apici, con i segni di maggiore (>),
o minore (<) e uguale (=). Con queste istruzioni per il filtro "statico", se non si creano le routine per
poter rendere i "criteri" variabili a piacere. Useremo quindi delle InputBox per l'introduzione delle date,
che assegneremo a delle variabili da richiamare come "argomento" dei "Criteria". E qui casca l'asino,
almeno per me. Non sono riuscito a trovare la giusta sintassi perch i "Criteria" riconoscano le stringa di
concatenazione che lega i simboli maggiore-minore e la variabile data ottenuta dalle inputbox. Anzi,
dir di pi, mentre sul foglio di lavoro, l'applicazione del filtro personalizzato attraverso la procedura
attraverso i men, fornisce i risultati voluti, se si cerca di replicare il filtro, pari pari come lo ha scritto
Excel, usando il codice stesso scritto da Excel, il filtro non funziona. Non capisco perch, ma a me
succede cos.
Avrei una soluzione da proporre, in attesa che qualcuno riesca a spiegarmi cose che non so, soluzione
che serve ad aggirare l'ostacolo, e funziona egregiamente. Riprendiamo la tabella esempio gi usata
in altri esempi:

Volendo applicare il filtro sulle date, e visto le motivazioni sopra descritte, ho seguito questa procedura:
ho destinato due celle, formattate a "data" del tipo "13/01/02", in cui inserisco i dati che reperisco con
due InputBox, e che corrisponderanno alla data di inizio del range di ricerca, e alla data finale.
In una colonna a lato della tabella, iniziando dalla stessa riga in cui inizia la tabella, ho inserito una
formula condizionale che controlla se la data nella colonna "data", stessa riga, sar uguale o maggiore
rispetto alla data che avremo ottenuto con la prima InputBox, e che sar stata immessa nella prima
delle due celle per questo predisposte, e controlla anche se la data ottenuta con la seconda InputBox
e inserita nella seconda cella sar minore o uguale alla data nella colonna "data" stessa riga. Nel caso
di una corrispondenza, nella cella della formula verr riportato il valore 1, in caso contrario il valore
zero.
A questa colonna dove ho inserito le formule, applicheremo il filtro. A questo punto avremo bisogno di
citare come valore da assegnare a Criteria1, il valore 1, e il gioco fatto, il filtro in questo modo
funziona egregiamente, nascondendo tutte le righe che non corrispondono a 1. Vediamo la tabella:

http://ennius.interfree.it/ Pagina 176


MANUALE VBA X EXCEL

Le celle evidenziare in giallo, sono le celle che "ospitano" le date introdotte con le InputBox, e potranno
essere utilizzate celle "fuori vista", in altra zona del foglio, come pure le formule che ho inserito nella
colonna H solo per mostrarle. A partire dalla cella H4, c' la formula : =SE(E(F4>=$G$1;F4<=$H$1);1;0)
che andr inserita col "trascinamento" anche nelle celle sottostanti, per quanto sar lunga la tabella. E
questo sar l'effetto del filtro una volta applicato:

Ed ora vediamo le procedure per le InputBox e per l'applicazione del filtro. Premetto che queste
routine sono specifiche per la ricerca sulle date di questa tabella. Se si volesse gestire la libert di
scegliere su quale colonna applicare il filtro, dovremo modificarle.
Sub Filtradata()
'dichiarazione delle variabili che conterranno le date introdotte nelle due InputBox
Dim Crituno
Dim Critdue
'assegnazione a Crituno della prima data
Crituno = InputBox("Inserire la prima data")
'se non scriviamo niente si uscir dalla routine
If Crituno = "" Then Exit Sub
'rendiamo la cella G1 uguale a Crituno, con assegnazione del tipo di dati (CDate) e
'formattazione della data
Range("G1").Value = CDate(Format(Crituno, "dd/mm/yy"))
'si ripete per la seconda InputBox con inserimento della seconda data (Critdue)
nell'altra 'cella H1
Critdue = InputBox("Inserire la seconda data")
If Critdue = "" Then Exit Sub
Range("H1").Value = CDate(Format(Critdue, "dd/mm/yy"))
'ora selezioniamo la cella H3 (colonna con le formule) e applichiamo il filtro
Range("H3").Select
Selection.AutoFilter
Selection.AutoFilter Field:=1, Criteria1:=1
'poi selezioniamo la cella A1 per deselezionare la cella del filtro
ActiveSheet.Cells(1, 1).Select
End Sub

http://ennius.interfree.it/ Pagina 177


MANUALE VBA X EXCEL
Usare il Filtro Automatico con scelta libera del campo e del criterio di ricerca.
Quando usiamo il Filtro Automatico di Excel, sappiamo che dobbiamo selezionare la prima a sinistra
delle celle che formano le intestazioni di colonna, celle che rappresentano i "campi" della tabella o
database che dir si voglia, dopodich sceglieremo il "campo" che intendiamo filtrare applicando un
"criterio" di ricerca tra i valori presenti in quel campo. Non altres difficile realizzare una macro che ci
consenta di automatizzare tramite codice vba le operazioni volute, semplicemente usando il
"registratore di macro".
L'esercizio che presento si diversifica da una macro realizzata nel modo su esposto, in quanto
lasceremo al vba il compito di identificare l'area del database, di contare il numero di colonne (
campi ) che formano il database, di chiederci tramite una InputBox il numero di campo ( o colonna )
su cui vorremo applicare il filtro, di trovare quanto lungo l'elenco in modo da definire tutte le righe in
cui faremo cercare, tramite un'altra InputBox, il criterio di ricerca sul quale applicare il filtro, e una volta
accertato che il criterio presente, filtrare tutti i dati. Vediamo i passaggi, e alla fine la routine
completa:
come prima condizione sar quella di inserire nella sezione Generale - Dichiarazioni del Modulo che
conterr la nostra routine ( o macro che dir si voglia ) una semplice istruzione che ha lo scopo di
rendere indifferente l'uso di maiuscole/minuscole nelle Inputbox che useremo per reperire le variabili.
(Diversamente la ricerca sarebbe CaseSensitive, cio sensibile alle maiusc/minusc. in quanto le
istruzioni risiedono su un Modulo)
Option Compare Text
identificare la posizione della tabella (o database ) sul foglio di lavoro; per fare questo ci affideremo all'
UsedRange, (di cui esistono spiegazioni in questa sezione, paragrafo "Copia/Incolla 4") e assegneremo
con l'istruzione Set, un nome alla tabella (zona) dell'UsedRange nel foglio attivo:
Set zona = ActiveSheet.UsedRange
identificazione del numero di colonne da cui formata la tabella. Questo ci consentir di usare il
numero colonna per scegliere il campo su cui applicare il filtro, anzich il nome del campo, e di poter
controllare poi se abbiamo richiesto un numero di colonna che non esiste. Assegneremo ad una
variabile, la X, il numero di colonne ottenuto con questa istruzione:
X = zona.Columns.Count
dichiarazione dei nomi delle variabili che memorizzeranno il numero di campo (Campo) ed il criterio di
ricerca (Criterio) .
Dim Campo
Dim Criterio
assegnazione alla prima variabile ( campo ) del valore che scriveremo nella prima finestra di dialogo (
InputBox )
Campo = InputBox("Inserire il numero del campo di ricerca")
inserimento di un ciclio If...Then...End If per controllare due eventi: il primo controlla che il valore
restituito dalla inputbox non sia vuoto, nel qual caso si uscirebbe dalla routine; precauzione necessaria
per evitare proteste del debugger che se si proseguisse con l'esecuzione delle altre istruzioni si
genererebbe un errore per mancanza di dati (la variabile Campo non conterrebbe nessun valore). Il
secondo ciclo invece controlla se il valore numerico della variabile Campo ( Val(Campo) ) maggiore
del numero di colonne che la variabile X iniziale ha memorizzato. Se il valore sar maggiore, verremo
avvisati con un messaggio e si uscir dalla routine anche in questo caso.
If Campo = "" Then Exit Sub
If Val(Campo) > X Then
MsgBox "N Campo non presente"
Exit Sub
End If
ora si passa ad assegnare alla seconda variabile ( Criterio ) il valore che inseriremo nella seconda
InputBox. Anche qui eseguiremo il controllo per uscire se Criterio sar vuoto. Trattandosi di testo da
assegnare a Criterio, non sar necessario dichiarare il "tipo" di dato numerico ( Val(Criterio) ),
necessario peraltro nel caso che anche Criterio sia un valore numerico.
Criterio = InputBox("Inserire il criterio di ricerca")
If Criterio = "" Then Exit Sub
a questo punto avremo bisogno, se vogliamo controllare la presenza del valore (Criterio) da filtrare nel
campo gi deciso, di un ciclo di ricerca che partendo dall'inizio della colonna identificata con
Campo, trovi quante righe sono presenti nella colonna, e in questo Range effettui la ricerca. Per
questo istruiremo un ciclo For Each....Next , usando la procedura gi vista tante volte su questo sito.
http://ennius.interfree.it/ Pagina 178
MANUALE VBA X EXCEL
Dim CL As Object
dovremo far sapere da quale riga e quale colonna iniziare, rendendo "pippo" uguale alla riga 1
dell'area "zona", colonna numero Campo
Set pippo = zona.Cells(1, Val(Campo))
ora possiamo inizializzare il ciclo "per ogni cella (CL)" presente tra "pippo" e la fine di "pippo" in basso
(End(xlDown)
For Each CL In Range(pippo, pippo.End(xlDown))
se il valore di una cella sar uguale al valore memorizzato in Criterio, allora...
If CL.Value = Criterio Then
in questo caso (che il valore Criterio esista nell'elenco della colonna scelta) avremo bisogno di
interrompere il ciclo, passando alle istruzioni di applicazione del filtro, ed useremo il vecchio GoTo
indicando a quale indice riga spostarsi
GoTo 10
nel caso che il valore del Criterio non sia presente, il compilatore proseguir cercando in tutte le celle e
alla fine concluder la ricerca, e qui inseriremo un messaggio che ci avviser che il valore non
presente, uscendo dalla routine:
End If
Next
MsgBox "Criterio Non presente"
Exit Sub
dopo questa istruzione troveremo il riferimento all'indice riga a cui il compilatore sarebbe saltato se il
Criterio veniva trovato, con a seguire l'istruzione per l'applicazione del filtro alla prima cella della prima
riga dell'area tabella ( zona ), e l'indicazione del Campo e del Criterio da applicare.
10:
zona.Cells(1, 1).Select
Selection.AutoFilter
Selection.AutoFilter Field:=Campo, Criteria1:=Criterio
una volta applicato il filtro riselezioniamo la prima cella e terminiamo l'istruzione
zona.Cells(1, 1).Select
End Sub

e questa l'intera routine:


Sub RicercaeFiltra()
Set zona = ActiveSheet.UsedRange
X = zona.Columns.Count
Dim Campo
Dim Criterio

Campo = InputBox("Inserire il numero del campo di ricerca")


If Campo = "" Then Exit Sub
If Val(Campo) > X Then
MsgBox "N Campo non presente"
Exit Sub
End If

Criterio = InputBox("Inserire il criterio di ricerca")


If Criterio = "" Then Exit Sub
Dim CL As Object
Set pippo = zona.Cells(1, Val(Campo))
For Each CL In Range(pippo, pippo.End(xlDown))
If CL.Value = Criterio Then

GoTo 10
End If
Next
MsgBox "Criterio Non presente"
Exit Sub
10:
http://ennius.interfree.it/ Pagina 179
MANUALE VBA X EXCEL
zona.Cells(1, 1).Select
Selection.AutoFilter
Selection.AutoFilter Field:=Campo, Criteria1:=Criterio

zona.Cells(1, 1).Select
End Sub
Nota per quanto riguarda l'"UsedRange", faccio solo presente che l'esempio sopra impostato su un
foglio in cui sia presente solo il database, completo delle intestazioni dei "campi". Se invece sul foglio,
prima del database, avessimo usato celle per scrivere altre cose, tipo "Ufficio Statistiche", o altre
amenit del genere, l'UsedRange comprenderebbe nell'area anche queste celle, sballando
completamente i valori dell'identificazione dei riferimenti riga, colonna, ecc.ecc.
Un'altra cosa: visto che con l'applicazione di un filtro, compaiono i famosi men su ogni campo,
sarebbe opportuno prevedere di poterli togliere e ripristinare il database dopo la consultazione. Per
fare questo, suggerisco di usare un CommandButton delle ActiveX (Strumenti di controllo o Casella
degli strumenti) sfruttando la sua propriet Caption, in modo da differenziare nell'evento Click le
istruzioni da seguire. Questo un esempio(dopo aver impostato la sua propriet Caption a "Filtro"):
Private Sub CommandButton1_Click()
If CommandButton1.Caption = "Filtro" Then
CommandButton1.Caption = "Ritorno" 'cambia la caption "Filtro" in "Ritorno"
RicercaeFiltra 'chiama la routine sopra esposta
Else 'se invece la caption sar diversa da "Filtro", e quindi "Ritorno"
CommandButton1.Caption = "Filtro" 'reimposta la caption a "Filtro"
Set zona = ActiveSheet.UsedRange 'e toglie dalla cella 1 di "zona" il filtro
zona.Cells(1, 1).Select
Selection.AutoFilter
End If
End Sub

http://ennius.interfree.it/ Pagina 180


MANUALE VBA X EXCEL
Le Userform e la X di chiusura.
Quando si progetta una UserForm, in genere inseriamo sicuramente almeno due commandbutton di
cui uno preparato per uscire dalla form e chiuderla. Questo perch, oltre ad ottenere una
presentazione un p pi "professionale", possiamo inserire, appunto prima della chiusura, una serie di
controlli che impediscano la chiusura se non stato eseguito un determinato passaggio, per esempio il
controllo se in una textbox stato inserito un nome invece di una data. Questa verifica avrebbe il
compito di impedire la chiusura fintantoch non si sia corretto l'errore. Ma l'utente, anzich adoperare
il commandbutton preposto alla chiusura, potrebbe adoperare la famosa X posta a destra, in alto, che
serve, in tutte le finestre di Windows, a chiudere la finestra stessa, e questo manderebbe alle ortiche
tutto il costrutto predisposto al controllo. Presto fatto : eliminiamo la X cos non si potr utilizzare. Ma le
Userform di Excel non possiedono la propriet " ControlBox " che, impostata a False, eliminerebbe detta
X, come succede sulle Form di VisualBasic, e quindi sar "dura" eliminarle. Per fortuna esiste per il
modo, se non di eliminare la X, di IMPEDIRNE la chiusura. Quando si chiude una form, sia che si usi la X,
sia che si usi l'istruzione " UnLoad Me " nel commandbutton di uscita, richiamiamo l'evento "QueryClose"
della UserForm, che quindi sfrutteremo per impedire la chiusura : richiamando detto evento nella
UserForm, scriveremo questa semplice istruzione : Cancel = vbNo, e questa sar la nostra routine:
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
Cancel = vbNo
End Sub
Premendo sulla X della form in esecuzione, sar impossibile chiuderla, ma Attenzione!!, poich come
detto, lo stesso evento verrebbe richiamato anche dall'istruzione posta nel commandbutto preposto
all'uscita, e quindi non si uscirebbe pi, dovremo sostituire, in questo commandbutton, l'istruzione
"UnLoad Me" con l'istruzione " End ", che salta tutto e chiude la finestra liberando anche la memoria.
Un altro metodo da seguire, quello di inserire nell'evento "QueryClose", la seguente istruzione, che
attiverebbe una finestra di messaggio con due pulsanti, SI e NO, lasciando quindi all'utente la libert di
scelta, ma avvisandolo opportunamente di ci che sta facendo. Con questa soluzione, l'istruzione nel
commandbutton preposto all'uscita dovrebbe essere " UnLoad Me " anzich " End ", che sortirebbe lo
stesso effetto richiamando "QueryClose". Questa la routine:
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
Cancel = (MsgBox("Sicuro di voler chiudere la finestra ?", vbYesNo) = vbNo)
End Sub
Potrete decidere ovviamente, quale messaggio far apparire. Buon lavoro.

http://ennius.interfree.it/ Pagina 181


MANUALE VBA X EXCEL
Usare il Vba per impostare il Formato celle sul foglio di lavoro. (02/04/03)
Utilizzo della propriet "NumberFormat"
Sappiamo quanto sia importante predisporre il Formato Celle sul foglio di lavoro in modo da
corrispondere al tipo preciso di dati che dovranno contenere. Quando poi questi dati sono il risultato di
un'istruzione vba, diventa ancora pi necessario far corrispondere il formato cella al "tipo" di dati
restituito dal codice stesso. Sappiamo anche che il Formato Celle preimpostato da Excel per tutte le
celle il formato "Generale", che appunto perch "Generale" dovrebbe accettare qualsiasi tipo di
dato immesso. Esistono tuttavia delle condizioni di formato che devono essere impostate
manualmente perch il "Generale" da solo non riuscirebbe a darci il dato cos come lo vorremmo.
Prendiamo il caso di volere in una cella, una cifra a due decimali mentre il risultato di un'operazione
eseguita tramite codice sia a pi decimali, esempio 13,4578, nella cella predisposta a ricevere il dato,
se impostata col formato cella a "Generale" vedremmo il numero cos come restituito dal vba.
Dovremo quindi selezionare la cella, scegliere "Formato celle", e nella scheda "Numero" selezionare
"numero" e impostare manualmente il numero di decimali (2) e se vogliamo, anche il separatore delle
migliaia. Torna utile quindi poter disporre di istruzioni via codice in modo da predisporre il Formato cella
nella cella che conterr il dato restituito dal codice senza farlo manualmente dal foglio di lavoro.
Premesso che se definiamo gi via codice il "tipo" di dati che il codice restituisce, Excel predispone
automaticamente il Formato Cella quando riceve il dato, esistono tuttavia istruzioni nelle quali o
perch ci dimentichiamo di definire il tipo di dato, o perch non lo sappiamo, o per altri motivi, il
risultato che vediamo nella cella non quello che ci aspettavamo. Facciamo un esempio per capire
cosa si intende per "tipo di dato":
cella A1 con Formato Cella impostato a "Generale"
istruzione che assegna alla variabile X il valore 13,4578 (ricordo che il codice usa il sistema di separatori
inglesi, esattamente l'opposto del sistema basato sul SMD, il nostro, e cio il punto (.) per indicare i
decimali, e la virgola ( , ) per indicare il separatore delle migliaia)
X = 13.4567 (sarebbe il nostro 13,4567)
istruzione per predisporre il formato del valore rappresentato da X, con due decimali :
X = Format(X, "#,###.00") (X ora sarebbe uguale al nostro 13,46 per via degli arrotondamenti che fa
Excel, anche se in realt non cos, ma lo vedremo un'altra volta)
assegnazione alla cella A1 del valore rappresentato da X :
Range("A1") = X
e vedremmo la cella A1 in questa maniera: il numero scritto a due decimali, ma allineato a sinistra
come se fosse testo, infatti viene evidenziato come "errore" e cio : "numero memorizzato come testo",
ed in pi Excel continuerebbe ad avere il Formato Cella impostato a "Generale". Se invece
modifichiamo l'ultima riga dell'istruzione dichiarando il "tipo" di dato rappresentato da X, Excel ora lo
accetter come numero:
Range("A1") = CDbl(X) (CDbl un "tipo" di dato Double, cio numero con decimali)
e questa la nostra istruzione completa:
X = 13.4567
X = Format(X, "#,###.00")
Range("A1") = CDbl(X)

ora s che vedremo il nostro numero allineato a destra nella cella e senza che Excel rilevi un errore. Ma
nonostante tutto, se controlliamo il Formato Cella, vedremo che ancora impostato a "Generale".
Riallacciandoci quindi al tema dell'argomento, per avere anche il Formato cella che desideriamo,
dovremo usare un'istruzione appropriata per definire il formato cella voluto; inseriremo quindi l'istruzione
prima di assegnare alla cella il valore X (possiamo mettere la seguente istruzione anche a inizio
routine). Useremo quindi la propriet "NumberFormat" che una propriet degli oggetti CellFormat e
Range.
Range("A1").NumberFormat = "#,##0.00"
In questo modo non solo otteniamo che il Formato Cella sar quello voluto (cio Formato cella
impostato a numero con due decimali e separatore delle migliaia) ma potremo evitare anche
l'istruzione di formattazione del valore X e anche la dichiarazione del "tipo" di dato, come esemplificato
sotto:
Range("A1").NumberFormat = "#,##0.00"
X = 13.4567
Range("A1") = X

http://ennius.interfree.it/ Pagina 182


MANUALE VBA X EXCEL
Ma vediamo quali sono le istruzioni da usare in Vba per i formati cella pi comuni. Uso la cella A1 come
esempio, ma sar possibile istruire istruzioni per ogni cella e anche per Range di celle o aree.
per formattare una cella con numero a 2 decimali e separatore delle migliaia
Range("A1").NumberFormat = "#,##0.00"
per formattare una cella in formato testo
Range("A1").NumberFormat = "@"
per formattare una cella in formato data con anno a due cifre ( tipo: 01/02/03)
Range("A1").NumberFormat = "m/d/yyyy"
per formattare una cella in formato data con anno a quattro cifre ( tipo: 01/02/2003)
Range("A1").NumberFormat = "mm/dd/yyyy"
per formattare una cella in formato percentuale (%)
Range("A1").NumberFormat = "0.00%"
oppure usando Cells al posto di Range (per la A1 possiamo usare Cells(1, 1) (cella riga 1 colonna 1))
Cells(1, 1).NumberFormat = "#,##0.00"
o ancora per un insieme di celle da A1 a A10
Range("A1:A10").NumberFormat = "#,##0.00"
oppure usando Cells (in questo caso si deve usare Cells non come oggetto, ma come propriet di un
oggetto Range) per il solito insieme di celle (da A1 a A10):
Range(Cells(1, 1), Cells(10, 1)).NumberFormat = "#,##0.00"
Un ultima cosa: per ottenere la trasposizione in codice di altri Formati Cella, usate il "registratore di
macro": avviate il registratore, selezionate una cella, scegliete da Formato celle il formato desiderato,
date Ok, stoppate il registratore, e andate a vedere cosa ha compilato Excel per voi: quella
l'istruzione da adoperare assegnandola poi alla o alle celle che vi interessano.

http://ennius.interfree.it/ Pagina 183


MANUALE VBA X EXCEL
Le Formule viste dal Codice.
Quando in Excel si usa il codice per compilare istruzioni che contemplino formule, queste si possono
scrivere usando due stili : lo stile notazione A1 o lo stile R1C1 (a parte le Array). Vediamo due esempi:
stile notazione A1 : tutte le seguenti formule compilate in maniera diversa, sono identiche nella
sostanza : hanno tutte in comune una cosa: portano i "riferimenti diretti" alle celle da moltiplicare; il
gruppo delle prime tre definisce anche la cella di destinazione del risultato, mentre le seconde tre
porteranno il risultato nella cella in quel momento attiva, cio selezionata. Tutte queste danno lo stesso
risultato:
Range("J1") = Range("H1") * Range("I1")
Range("J1").Formula = "=(H1 * I1)"
Cells(1, 10) = Cells(1, 8) * Cells(1, 9)
------------------
ActiveCell = Range("H1") * Range("I1")
ActiveCell.Formula = "=(H1 * I1)"
ActiveCell = Cells(1, 8) * Cells(1, 9)
E' evidente che formule del genere non si prestano a conteggi da svolgere su celle diverse da quelle
indicate nei riferimenti (a parte le seconde tre che danno il risultato dove vogliamo noi, baster
selezionare una qualsiasi cella per renderla attiva). Comunque tutte e sei moltiplicheranno sempre e
solo H1 per I1. Queste istruzioni andranno inserite, per provarle, una sola per volta, in una macro che
piazzeremo in un modulo e che assoceremo ad un pulsante per l'attivazione della macro stessa.
Attenzione!! il risultato lo avremo solo quando premeremo il pulsante, se cambiamo i valori da
moltiplicare, dovremo di nuovo premere il pulsante per ottenere il nuovo risultato : questo perch la
cella di destinazione riceve il risultato MA NON LA FORMULA CHE L'HA GENERATO.
stile R1C1 : le formule realizzate in questo stile (che quello impiegato da Excel quando si fa uso del
"Registratore di Macro") utilizzano "riferimenti indiretti" alle celle che dovranno essere moltiplicate ( o
sommate, divise, ecc.). Data una cella di partenza, le celle da moltiplicare saranno individuate tramite
la posizione che queste celle avranno rispetto alla cella di partenza(che varr 0), e cio il numero di
quante righe e colonne le distanziano dall'origine (partenza) anteponendo a questo numero il segno
pi, riferito sia alla riga, sia alla colonna, se saranno sotto o a destra rispetto allo zero(0) o il segno meno
se saranno a sinistra o sopra; usano cio il cosiddetto "scarto" (Offset). Il vantaggio di questo stile che
NON usando un "riferimento diretto" potremo ottenere la moltiplicazione di volta in volta, delle celle
indicate nello "scarto" che varieranno se varier la cella di partenza. Vediamo un esempio:
Range("F5").FormulaR1C1 = "=RC[-2]*RC[-1]"
intanto notiamo che stato definito lo stile: FormulaR1C1 - l'istruzione si legge : Nel
Range F5 voglio la formula stile R1C1 che sar uguale al valore presente nella cella
che sta (sulla stessa riga) meno 2 colonne rispetto alla F5 ( RC[-2] ) cio la F3,
moltiplicato il valore che sta meno 1 colonna rispetto alla F5 ( RC[-1] ) cio F4. (Cio i
valori che sono nelle due celle precedenti la F5)
Se al posto di un riferimento diretto per indicare la cella di destinazione (
Range("F5")), avessimo usato ActiveCell :
ActiveCell.FormulaR1C1 = "=RC[-2]*RC[-1]"
avremmo ottenuto che qualunque fosse la cella selezionata, avrebbe dato il
risultato della moltiplicazione delle due celle precedenti quella selezionata. Questo
comportamento l'avremmo potuto ottenere lo stesso senza bisogno di ricorrere allo
stile R1C1, (che con tutti quei RC, parentesi quadre, ecc.ecc. spesso genera
incomprensione e difficolt di orientarsi ) infatti la seguente istruzione lavora sullo
stesso principio, ma risulta pi comprensibile ed ottiene lo stesso risultato:
ActiveCell = ActiveCell.Offset(0, -2) * ActiveCell.Offset(0, -1)

Vorrei concludere, dopo aver "intorbidito" un p le acque, che lo stile R1C1 ha il


grosso vantaggio che nella cella di destinazione, oltre al risultato dell'operazione,
pone ANCHE LA FORMULA, col beneficio che SE si variano i valori del moltiplicando
e del moltiplicatore, la cella di destinazione aggiorna il risultato senza bisogno di
rilanciare la macro perch la formula residente, anche se si cambia selezione.

http://ennius.interfree.it/ Pagina 184


MANUALE VBA X EXCEL
Funzione Format
Utilizzo: Formattare dati da visualizzare sullo schermo (per esempio: textbox) o sulla stampante. In Excel
pu essere utilizzato anche nelle Funzioni utente per impostare il formato di dati che il codice trasmette
al foglio di lavoro. Da non confondere con il "tipo" di dati assegnati ad una variabile o ai "formati di
conversione" dati. (Ricordo poi che in un foglio di Excel il formato dati pu essere impostato
scegliendo, per ogni cella, da "Formato celle", che determina il formato con cui visualizzare i dati).
Il termine "formattare" significa controllare l'aspetto con cui verr visualizzato l'output, cio viene
utilizzato per determinare il "come" visualizzare un dato. Esistono "Formati predefiniti" e "Formati
personalizzati". Vedremo i due tipi e relative spiegazioni, in particolare per i formati numerici (esistono
anche i formati data e i formati stringa).
Sintassi della funzione Format
Format[$] (Espressione(op. oggetto)da formattare, "Descrizione formato")
esempio:
Miovalore = 10725
Miovalore = Format$(Miovalore, "#,###.00") restituisce: 10.725,00
oppure
TextBox1 = 10725
TextBox1 = Format(TextBox1, "Standard") restituisce: 10.725,00
Il simbolo del dollaro ($) opzionale specifica che il valore formattato deve essere una stringa. Senza
simbolo del dollaro, il valore restituito di Tipo Variant (sia stringa sia numero). Nella maggior parte
delle situazioni i risultati sono uguali, ma l'uso del simbolo del dollaro pi efficiente. La formattazione
in genere non necessaria se i valori numerici sono valori interi, non decimali.
Formati Predefiniti.
Tipo Formato Descrizione
Currency visualizza un numero con il separatore delle migliaia; visualizza due
cifre a destra del separatore decimale.
visualizza almeno una cifra a sinistra e due cifre a destra del
Fixed
separatore decimale.
General Number visualizza il numero lasciando la sua forma invariata.
visualizza l'ora nel formato breve di 12 ore, indicando le ore, i
Medium Time
minuti, e l'identificatore AM/PM.
On/Off visualizza la parola Off se il valore zero, altrimenti scrive On.
numeri moltiplicati per 100 con il segno di percentuale sulla destra;
Percent
due cifre decimali.
Scientific notazione scientifica standard (notazione esponenziale).
Short Date visualizza una data usando il formato data breve del sistema.
Short Time visualizza l'ora usando il formato di 24 ore.
visualizza un numero con il separatore delle migliaia, almeno una
Standard
cifra a sinistra e due cifre a destra del separatore decimale.
True/False visualizza False se il valore zero, altrimenti True
Yes/No visualizza No se il valore zero, altrimenti Si.
Quindi questa funzione risulta utile perch arrotonda i valori frazionari al numero di decimali
specificato. Ci che viene arrotondato, per, solo l'output (a video), non il valore memorizzato che
rimane inalterato, ecco perch in Excel opportuno non scordarsi del "formato cella", e/o usare il
formato di conversione dati per passare i dati al foglio di lavoro.(Esistono indicazioni e suggerimenti sul
sito, per il "formato di conversione" sezione vba, paragrafo "Gestione degli errori", alla fine della
pagina.).
Creazione di Formati Personalizzati.
Se i formati predefiniti non forniscono i risultati desiderati, possibile crearne di propri. Vediamo come
creare formati numerici personalizzati. (per i "formati data e ora" rimando ai paragrafi "il vba e le date"
e seguenti, in questa stessa sezione). Vediamo i simboli che permettono la creazione di formati
personalizzati:
Simbolo Descrizione Descrizione
visualizza una cifra o uno zero nella posizione;se
0 segnaposto di cifra
non c' alcuna cifra, viene visualizzato uno zero.
visualizza una cifra o non visualizza niente; se non
# segnaposto nullo
c' alcuna cifra, non viene visualizzato nulla.
http://ennius.interfree.it/ Pagina 185
MANUALE VBA X EXCEL
. segnaposto decimalevisualizza il separatore decimale nella posizione.
, separatore migliaia inserisce il separatore delle migliaia.
l'espressione moltiplicata per 100. Il carattere di
segnaposto
% percentuale (%) appare nella posizione
percentuale
specificata.
Ricordo che la formattazione deve seguire il sistema inglese con la virgola come separatore delle
migliaia e il punto come separatore dei decimali. Provveder Excel e farcelo vedere e a convertirlo nel
nostro sistema.
Esempi di formati numerici personalizzati:
Istruzioni Risultato
TextBox1 = 1987,788
TextBox1 = Format(TextBox1, "###.#") 1987,8
TextBox1 = Format(TextBox1, "#,###.##") 1.987,79
TextBox1 = Format(TextBox1, "\\ . #, ###.##") . 1987,79
TextBox1 = 888
TextBox1 = Format(TextBox1, "###") 888
TextBox1 = Format(TextBox1, "###.##") 888,
TextBox1 = Format(TextBox1, "###.00") 888,00
TextBox1 = Format(TextBox1, "#,###.##") 888,
TextBox1 = 0,5571
TextBox1 = Format(TextBox1, "##.#%") 55,7%
TextBox1 = Format(TextBox1, "00.00%") 55,71%
TextBox1 = Format(TextBox1, "#%") 55%

http://ennius.interfree.it/ Pagina 186


MANUALE VBA X EXCEL
Cercare una stringa testo in una stringa di parole.
Ovvero: come trovare una parola all'interno di un testo.
Per coloro che usano UserForm per la gestione di insiemi di dati, pu necessitare eseguire ricerche di
una determinata parola all'interno di una textbox collegata ad un campo dati "ridondante" di parole.
Premesso che le funzioni che impiegheremo NON sono disponibili su un foglio di lavoro (tranne Len),
ma solo attraverso l'impiego di UserForm, vediamo con quale esempio impostare i presupposti.
Simuliamo il solito database nel quale gestiremo la nostra biblioteca, e di avere un campo del
database destinato alla voce "Descrizione" che si occuper di contenere tutte le nostre osservazioni sul
contenuto del libro. E' evidente che inseriremo sicuramente una breve trama, oltre a ev. note personali.
La scrittura di queste "Descrizioni" sar composta da diverse parole, scritte magari su molte righe.
Useremo quindi una TextBox con la prorpriet "MultiLine" impostata a True, per avere la possibilit di
scrivere molto e su pi righe, e la propriet "ScrollBars" impostata a "2" (barre verticali). Per quanto
riguarda la cella del database collegata a questa textbox nessun problema, visto che le celle possono
contenere un'infinit di parole. Supponiamo ora di voler trovare un libro del quale, non ricordiamo il
titolo, ma ricordiamo che nel campo "Descrizione" avremo utilizzato la parola "estate43"; unica
soluzione: cercare nel campo "Descrizione" dove avremo scritto quella parola. Anzich leggerci tutte le
descrizioni, una per una, "alla ricerca del bene perduto", potremo usare una routine che cerchi per noi,
e ci evidenzi in pi il testo cercato, se trovato. Sotto le istruzioni da inserire in un commandbutton sulla
form, e queste le Funzioni impiegate, di cui rimando i "volenterosi" a cercarsi sulla guida in linea le
spiegazioni:
InStr
SelStart
SelLength
Len
Private Sub CommandButton1_Click()
Dim Cercaparola, Cerca, dove
Cercaparola = TextBox2 'text che contiene la "Descrizione"
Cerca = TextBox1 'textbox con parola da cercare (estate43)
dove = InStr(Cercaparola, Cerca)
If dove Then 'se "dove" esiste, allora
TextBox2.SelStart = dove - 1 ' l'inizio della selezione e
TextBox2.SelLength = Len(Cerca) ' seleziono la lunghezza di "cerca"
TextBox2.SetFocus
End If
End Sub
e questa l'immagine del risultato:

Al posto di una textbox per l'inserimento della parola da cercare, si pu usare una InputBox, nella
quale scrivere la parola, il risultato non cambia. L'interessante che pu essere rintracciata una parola
anche solo inserendo una parte della parola da cercare, o una intera frase; avremmo potuto scrivere
solo "43" e sarebbe stato evidenziato il "43" della parola "estate43", sufficiente peraltro a identificare ci
che stavamo cercando. Variante con InputBox:
Private Sub CommandButton1_Click()
Dim messaggio, titolo
Dim Cercaparola, Cerca, dove
Cercaparola = TextBox2 'text che contiene la "Descrizione"
http://ennius.interfree.it/ Pagina 187
MANUALE VBA X EXCEL
messaggio = "Scrivi la parola o la frase da trovare"
titolo = "Ricerca"
Cerca = InputBox(messaggio, titolo) 'inputbox con parola da cercare (estate43)
If Cerca = "" Then Exit Sub
dove = InStr(Cercaparola, Cerca)
If dove Then
TextBox2.SelStart = dove - 1 ' l'inizio della selezione e
TextBox2.SelLength = Len(Cerca) 'seleziono la lunghezza di "cerca".
TextBox2.SetFocus
End If
End Sub

http://ennius.interfree.it/ Pagina 188


MANUALE VBA X EXCEL
Utilizzo delle funzioni del foglio di lavoro di Microsoft Excel in Visual Basic.
Utilizzo dell'oggetto : WorksheetFunction
Nei nostri lavori ci troviamo spesso a dover "trasformare" formule e funzioni del foglio di lavoro in codice
vba. In genere ci affidiamo al "Registratore di macro". Attiviamo il registratore, compiamo i passi
necessari (selezione di una cella e inserimento formule e/o funzioni con indicazione dei riferimenti
come argomenti per ci che vogliamo sia fatto, ecc. ) e poi stoppiamo il registratore. A questo punto
la trasformazione in codice di ci che abbiamo fatto, ce l'ha scritta il registratore in un modulo:
andiamo a vedere cosa ha scritto, e diventiamo matti perch il codice stato compilato, per quanto
riguarda la formula impiegata, in puro stile R1C1. E cominciano i nostri drammi a rinvenirsi, se vogliamo
modificare dei riferimenti, in quella babele di parentesi quadre, tonde, R, C, numeri col meno davanti,
ecc.ecc. Gli smaliziati, avranno sicuramente imparato a trasformarsi una formula da stile R1C1 in stile
A1, e conseguentemente a poter modificare, adattare i riferimenti come pi gli aggrada.
Esiste un'altra strada per utilizzare le formule e le funzioni del foglio di lavoro nel codice vba. Una strada
che pi simile come concetto di sintassi, al sistema che usiamo sul foglio di lavoro. Questa strada
passa attraverso l'utilizzo dell'oggetto WorksheetFunction.
WorksheetFunction rende disponibili in Visual Basic le funzioni del foglio di lavoro.
Alcune funzioni del foglio di lavoro sono superflue in vba. La funzione Concatena (Concatenate per il
vba), ad esempio, non necessaria poich in vba possibile utilizzare l'operatore & per concatenare
pi valori di testo. NON tutte le funzioni del foglio di lavoro, sono disponibili in vba. (vedi elenco).
(Dalla guida in linea:
Se viene utilizzata una funzione del foglio di lavoro che richiede un riferimento di intervallo quale
argomento, necessario specificare un oggetto Range. Tuttavia, in una routine Visual Basic possibile
specificare un oggetto Range per ottenere lo stesso risultato.
Nota: Le funzioni Visual Basic non utilizzano il qualificatore WorksheetFunction. Non detto che una
funzione Visual Basic con lo stesso nome di una funzione Microsoft Excel operi in modo identico. Ad
esempio, Application.WorksheetFunction.Log e Log restituiranno valori diversi).
Vediamo di fare qualche esempio che illustri meglio quanto detto a inizio pagina. Siamo su un foglio di
lavoro e supponiamo di volere il totale di tutti i valori legati ad una condizione. Per esempio in A1:A10
abbiamo dei valori, in B1:B10 abbiamo dei nomi: vogliamo sapere quanto il totale dei valori relativi
ad uno dei nomi (giona per esempio) e useremo C1 per ottenere il risultato; in C1 quindi inseriremo la
funzione =SOMMA.SE(B1:B10;"giona";A1:A10) che tradotta in "pellegrinese", vuol dire : per ogni nome
"giona" che trovi in B1:B10, somma il valore che trovi nella cella accanto, nel range A1:A10. Se usiamo il
registratore di macro per ottenere la corrispondente istruzione Somma.Se tradotta in vba, otterremmo
la seguente istruzione:
Range("C1").FormulaR1C1 = "=SUMIF(RC[-1]:R[9]C[-1],""giona"",RC[-2]:R[9]C[-2])"
e qui gli amanti dei geroglifici andrebbero a nozze, ma per noi, poveri mortali, sarebbe un supplizio
voler cambiare uno o pi riferimenti. Vediamo come possibile trasformarci l'istruzione sopra in modo
che ci si possa capire qualcosa. Intanto modifichiamo la parola FormulaR1C1 in una pi semplice
Formula, poi, ricordandoci la sintassi dell'istruzione messa sul foglio di lavoro dopo SOMMA.SE, la
ripeteremo effettuando una piccola modifica, e la sostituiremo a tutto ci che nell'istruzione sopra tra
parentesi, cos:
Range("C1").Formula = "=SUMIF(B1:B10,""giona"",A1:A10)"
La modifica consiste nell'aver messo altri due doppi apici alla parola, necessari perch in una formula
vba, a differenza di quanto accade sul foglio di lavoro, per indicare due doppi apice se ne devono
usare quattro. Oppure usare una variabile, che rende l'istruzione pi flessibile, in quanto ci
consentirebbe di poter scegliere di il nome di cui vogliamo il totale. Per questo abbiamo bisogno di
usare una cella del foglio di lavoro, dove di volta in volta scriveremo il nome. Assegneremo questa
cella alla variabile e sostituiremo nell'istruzione il nome con i 4 doppi apici, con la variabile senza apici,
cos :
X = Range("D1") 'una cella a caso dove scriveremo il nome di cui vogliamo i totali
Range("C1").Formula = "=SUMIF(B1:B10,X,A1:A10)"
E ora arriviamo al "piatto forte": all'impiego di WorksheetFunction, che secondo me rappresenta il
modo migliore di non impazzire con la sintassi. Vediamo la stessa istruzione compilata usando
WorksheetFunction. Visto quanto detto dalla Guida il linea (pi sopra riportata: riferimenti come
argomenti), useremo l'istruzione Set per restituire i Range di celle interessate:

Sub summase()
Dim myRange, tuoRange As Range 'questa riga si pu anche omettere
http://ennius.interfree.it/ Pagina 189
MANUALE VBA X EXCEL
X = Range("D1") 'una cella a caso dove scriveremo il nome di cui vogliamo i totali
Set myRange = Worksheets("foglio1").Range("A1:A10")
Set tuorange = Worksheets("foglio1").Range("B1:B10")
Range("C1") = WorksheetFunction.SumIf(tuorange, X, myRange)
End Sub
Decisamente pi comprensibile e meglio interpretabile. Praticamente (a parte un p di codice in pi)
l'istruzione la stessa usata sul foglio(come impostazione). Da notare una cosa: mentre con l'istruzione
a base formula, ci che viene riportato in C1 il risultato e la formula (visibile nella "barra della
formula"), con l'istruzione sopra vedremo SOLO il risultato. Questo torner sicuramente utile a tutti coloro
che, volendo nascondere le formule, in questa maniera hanno la formula non visibile senza dover
scegliere altre strade. (protezione foglio e quantaltro). Vediamo le differenze:

Ancora un esempio per esaltare la semplicit di questo metodo, una istruzione per ottenere la somma
di tutto un range di celle, non credo abbia bisogno di commenti:
Sub SommaMia()
'Dim myRange As Range 'questa riga si pu eliminare
Set myRange = Worksheets("Foglio1").Range("A1:C10")
Range("D1") = WorksheetFunction.Sum(myRange)
End Sub

ELENCO FUNZIONI DEL FOGLIO DI LAVORO DISPONIBILI IN VBA


ritorna
A E L Q T
Acos
Even Large Quartile Tanh
Acosh
ExponDist LinEst R TDist
And
F Ln Radians Text
Asin
Fact Log Rank TInv
Asinh
FDist Log10 Rate Transpose
Atan2
Find LogEst Replace Trend
Atanh
FindB LogInv ReplaceB Trim
AveDev
FInv LogNormDist Rept TrimMean
Average
Fisher Lookup Roman TTest
B
FisherInv M Round U
BetaDist
Fixed Match RoundDown USDollar
BetaInv
Floor Max RoundUp V

http://ennius.interfree.it/ Pagina 190


MANUALE VBA X EXCEL
BinomDist
Forecast MDeterm RSq Var
C
Frequency Median RTD VarP
Ceiling
FTest Min S Vdb
ChiDist
Fv MInverse Search VLookup
ChiInv
G MIrr SearchB W
ChiTest
GammaDist MMult Sinh Weekday
Choose
GammaInv Mode Skew Weibull
Clean
GammaLn N Sln X
Combin Y
GeoMean NegBinomDist Slope Z
Confidence ZTest
Growth NormDist Small
Correl
H NormInv Standardize
Cosh
HarMean NormSDist StDev
Count
HLookup NormSInv StDevP
CountA
HypGeomDist NPer StEyx
CountBlank
I Npv Substitute
CountIf
Index O Subtotal
Covar
Intercept Odd Sum
CritBinom
Ipmt Or SumIf
D
Irr P SumProduct
DAverage
IsErr Pearson SumSq
Days360
IsError Percentile SumX2MY2
Db
IsLogical PercentRank SumX2PY2
DCount
IsNA Permut SumXMY2
DCountA
IsNonText Phonetic Syd
Ddb
IsNumber Pi
Degrees
Ispmt Pmt
DevSq
IsText Poisson
DGet
J Power
DMax K
Ppmt
http://ennius.interfree.it/ Pagina 191
MANUALE VBA X EXCEL
DMin Kurt
Prob
Dollar
Product
DProduct
Proper
DStDev
Pv
DStDevP

DSum

DVar

DVarP
ritorna

http://ennius.interfree.it/ Pagina 192


MANUALE VBA X EXCEL
Funzioni Stringa. (20/02/03)
Il VBA dispone di una vasta raccolta di Funzioni che consentono la gestione di una gran parte delle
esigenze del programmatore: in questa pagina ci occuperemo delle funzioni necessarie alla
manipolazione di valori in formato testo ("Espressione testuale") o pi semplicemente "Stringhe". Alcune
funzioni le abbiamo gi viste (in questa sezione, paragrafo "Mid, Left e Right"), ora vediamo le altre.
Sotto una tabella completa di queste funzioni, peraltro rintracciabili nella guida in linea dall'editor di
visual basic :
Funzione Valore restituito Tipo di dato
LCase($) tutte le lettere di $ rese in minuscolo String
Len($) misura la lunghezza della stringa $ (quanti caratteri) Long
LTrim(&) elimina gli spazi iniziali dalla stringa $ String
RTrim($) elimina gli spazi finali dalla stringa $ String
Space(n) stringa composta da n spazi String
String(n, c) stringa composta da n volte del carattere c String
StrReverse($) rende a rovescio la stringa $ String
Trim($) rende la stringa $ privata degli spazi iniziali e finali String
Ucase($) tutte le lettere di $ rese in MAIUSCOLO String
Precisazione: lo "spazio" inserito tra due nomi (es.: Rossi Due ) viene contato come se fosse un
carattere; attenzione quindi agli "spazi" quanto si usano le funzioni Mid, Left, Right, Len. Eventualmente
usare prima una delle Funzioni Trim per rendere il valore stringa SENZA spazi iniziali o finali (con le
Funzioni Trim non vengono eliminati gli spazi "intermedi" che andranno quindi considerati nel numero
totale delle lettere).
In genere queste funzioni (tranne LCase e UCase) vengono usate quando si debbano eseguire dei
controlli sul contenuto di una cella o di una textbox ( sia testo che numeri o date ), e si voglia impedire
l'immissione di valori non conformi. Misurare la lunghezza (con Len()) di un valore stringa , per esempio,
pu servire a controllare che una data immessa sia nel formato "breve" : 01/01/03 oppure 01-01-03 ;
entrambe saranno formate da 8 caratteri, se scriveremo 01/01/2003 i caratteri salgono a 10, o ancora
per controllare che un valore stringa sia composta da un preciso numero di caratteri, per esempio un
codice articolo che deve essere di 11 caratteri e non vogliamo accettare codici con lunghezza
diversa, oppure....e qui gli esempi si sprecano, talmente tante possono essere le condizioni da
verificare che impensabile elencarne tutti gli esempi. L'importante vedere come impostare le
istruzioni ( i riferimenti seguenti alla cella A1 o alla textbox1 servono solo da campione, e riferiti alla
stringa " Rossi Due" (con uno "spazio" prima di Rossi) inserita in una cella o textbox):
MsgBox "il testo lungo" & Len(Range("A1")) & " caratteri"

ed avremo :

o ancora, usando anche Trim() per l'eliminazione di spazi iniziali e finali:


X = Trim(Range("A1"))
MsgBox "il testo lungo " & Len(X) & " caratteri"

ed avremo :

Il discorso degli "spazi" diventa importante se consideriamo che molte persone hanno l'abitudine di
premere la "barra spaziatrice" prima di iniziare a scrivere in una cella o in una textbox, o dopo aver
scritto, e lo fanno senza rendersene conto: visivamente (a schermo) spesso difficile poi intercettare la
presenza di uno spazio iniziale o finale. Provate a pensare a quanti di voi, dopo aver scritto "Rossi Due"
in una textbox, premono la "barra spaziatrice" PRIMA di premere "Invio" per passare al comando
successivo: in questo caso la lunghezza della stringa sarebbe formata ANCHE dallo spazio aggiunto
dopo "Due ". Il fatto pu essere ininfluente in molto casi, ma se, per fare un esempio, volessimo
controllare che un numero fosse composto da due soli decimali, e controllare che sia usata la virgola e
http://ennius.interfree.it/ Pagina 193
MANUALE VBA X EXCEL
non il punto, avremmo bisogno di un controllo che, leggendo da destra il numero di caratteri presenti,
intercetti la terzultima posizione per verificare la presenza della virgola ed in questo caso bloccasse la
routine e avvisasse di correggere. A questo punto, se avessimo inserito uno spazio alla fine, la ricerca
avverrebbe sul penultimo numero in quanto lo spazio verrebbe contato e falserebbe il controllo (infatti
il penultimo numero + uno spazio diventa il terzultimo). Vediamo un esempio diversificato: caso uno
senza il controllo RTrim - caso due con RTrim (toglie gli spazi a destra):
Usiamo la TextBox1
Numero da rendere con due decimali : 12345,88
Controllo per la presenza della virgola sfruttando la funzione Right() e Mid()
Numero scritto invece con uno spazio alla fine e con "l'errore" del punto 12345.88
istruzioni da inserire nell'evento Exit del TextBox1 (caso uno)
Private Sub TextBox1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
X = Right(TextBox1, 3)
If Mid(X, 1, 1) <> "," Then
MsgBox "Cuc"
Exit Sub
End If
End Sub.
L'istruzione, prima estrae gli ultimi 3 caratteri a destra e li assegna ad X (istruz. Right), poi controlla con
Mid il primo carattere (di X ) (1) per la lunghezza di 1 carattere (secondo 1) : se diverso da "virgola"
allora blocca la routine, noi controlliamo ci che abbiamo scritto e cambiamo il punto con la virgola:
tutto a posto? Neanche per idea, la routine continua a rifiutarsi di proseguire perch il codice conta
anche lo spazio (che noi continuiamo a non vedere) e al primo posto degli ultimi tre caratteri (di X)
legge 8, che non certamente una virgola. Ora vediamo il caso due, con l'utilizzo di RTrim
Private Sub TextBox1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
X = Right(RTrim(TextBox1), 3)
If Mid(X, 1, 1) <> "," Then
MsgBox "Cuc"
Exit Sub
End If
End Sub
In pratica ora X uguale agli ultimi tre caratteri MA abbiamo tolto gli eventuali spazi, annidando
l'istruzione RTrim all'interno di Right, e verr quindi letto effettivamente .88 .Trovato che esiste il punto al
posto della virgola, verremo bloccati, ma baster inserire la virgola e tutto andr bene. Una parentesi:
le funzioni Stringa, anche se nate per lavorare su testo, funzionano egregiamente su ogni tipo di dato
(nell'esempio: numeri).
Ricapitoliamo: abbiamo visto fino ad ora le funzioni Len($), Trim($), le Mid($), Left($) e Right($) sono
nella pagina a loro dedicata, vediamo ora le altre funzioni, i cui concetti sono facilmente assimilabili:
Space(n) la funzione inserisce tanti spazi quanti indicati da (n). Pu essere usata quando si voglia per
esempio, allineare a destra un testo rispetto ad altri, o ancora per avere del testo posizionato, sulle
righe successive, allineato alla fine del testo della riga precedente. Esempio: supponiamo di avere
allargato la dimensione della colonna A che dovr contenere dei nominativi e, non volendo usare
"allineamento delle celle a destra", vogliamo per che tutti i nominativi siano allineati alla fine del
nominativo pi lungo: in A1 abbiamo "Ermenegildo Brachelotti" (23 caratteri compreso lo spazio) in A2
invece avremo "Corrado Bianchi", pi corto (15 c.c.s.); bene per A2 useremo la funzione Space(n) con
il primo esempio: allineare la fine di un testo con la fine dell'altro:
Sub allinea()
Dim x, y, z As Long
x = Len(Trim(Range("A1")))
y = Len(Trim(Range("A2")))
z=x-y
Range("A2") = Space(z) & Range("A2")
End Sub
Misuriamo prima le lunghezze dei due testi e le "fissiamo" con le variabili x e y, indi ne facciamo la
differenza (z) che usiamo come numero di spazi (n di Space) e infine concateniamo al testo in A2, e
questo il risultato:

http://ennius.interfree.it/ Pagina 194


MANUALE VBA X EXCEL

Da notare che per avere l'esatto effetto di allineamento dei caratteri, si dovuto impiegare il carattere
"Courier", l'UNICO tra tutti i font, che mantiene gli stessi spazi per ogni tipo di lettera. Se si fosse lasciato il
font standard di Excel, l'Arial, si avrebbe avuto questo risultato, anche se gli spazi (n) sono gli stessi:

String(n, c) la funzione fornisce una stringa composta da tanti (n) di un carattere rappresentato dal
parametro (c). In pratica assomiglia alla funzione Space, ma anzich inserire "spazi" , inserisce n volte la
lettera indicata (c). Esempio: inserire 8 asterischi nella cella A1:
Range("A1") = String(8, "*") - e in A1 avremo: ******** (da notare nell'istruzione l'uso dei doppi apici
necessari per definire il valore ( * ) da ripetere. Anche se avessimo voluto inserire un numero anzich
l'asterisco, l'avremmo dovuto inserire tra doppi apici, come sotto, per ripetere 8 volte il numero 6 :
Range("A3") = String(8, "6")
StrReverse($) la funzione restituisce una stringa al contrario di come scritta. Esempio se in A4 scriviamo
"come" ed applichiamo la funzione, otterremo "emoc". Vedi istruzione:
Range("A4")=StrReverse(Range("A4"))
LCase la funzione restituisce tutte le lettere di una stringa, (siano esse maiuscole e minuscole), solo
minuscole. Esempio se in A5 scriviamo "BaraBBa" ed applichiamo la funzione, otterremo "barabba".
Vedi istruzione: Range("A5") = LCase(Range("A5"))
UCase la funzione restituisce tutte le lettere di una stringa, (siano esse maiuscole e minuscole), solo
maiuscole. Esempio se in A5 scriviamo "BaraBBa" ed applichiamo la funzione, otterremo "BARABBA".
Vedi istruzione: Range("A5") = UCase(Range("A5"))
Queste due ultime funzioni non hanno bisogno di tante spiegazioni: servono entrambe per avere
uniformit di caratteri nella composizione di stringhe testo, per esempio digitare nominativi senza
preoccuparsi delle maiuscole/minuscole, usando poi UCase, oppure per evitare test doppi nel caso di
controllo inserimento di lettere in cicli di ricerca.
Esistono anche altre funzioni per lavorare con le stringhe, ma ne parleremo un'altra volta, per ora
riporto una tabella di riscontro tra le Funzioni ora viste in vba, e le stesse disponibili sul foglio di lavoro:
Funzione VBA Funzione Foglio
LCase($) =MINUSC(testo)
Len($) =LUNGHEZZA(testo)
LTrim(&) n.d.
RTrim($) n.d.
Space(n) n.d.
String(n, c) =RIPETI(testo;volte)
StrReverse($) n.t.
Trim($) =ANNULLA.SPAZI(testo)
Ucase($) =MAIUSC(testo)
Mid($, n1, n2) =STRINGA.ESTRAI(testo;inizio;num_byte)
Left($, n) =SINISTRA(testo;num_caratt)
Right($, n) =DESTRA(testo;num_caratt)
Buon Lavoro.

http://ennius.interfree.it/ Pagina 195


MANUALE VBA X EXCEL
Funzioni Utente.
A seguito di una richiesta di un amico conosciuto sul web, provo a spiegare cosa una "Funzione" e
come sia possibile costruirsi da soli delle Funzioni, appunto le "Funzioni Utente".
In Excel abbiamo imparato cosa una Funzione: le funzioni sono formule predefinite che eseguono
calcoli utilizzando valori specifici, denominati argomenti, in un particolare ordine o struttura. Per
"formule predefinite" si devono intendere una serie di istruzioni predisposte (gi compilate da quei
Grandi Signori che hanno programmato Excel)) che ci aiutano nella composizione delle nostre formule,
evitandoci di scrivere tutta una lunga serie di istruzioni, inserendo semplicemente il nome della Funzione
preposta ad un determinato calcolo. (vedi anche sul sito, sezione "formule", paragrafo "formule e
funzioni - brevi cenni"). Queste Funzioni disponibili sul foglio di lavoro, hanno le corrispondenti Funzioni
disponibili anche nel Vba. Ma mentre sul foglio di lavoro non possibile creare delle Funzioni
"personalizzate" , con il Vba possibile. I vantaggi nell'impiego di una Funzione, dopo quanto detto,
appaiono evidenti: si compilano delle istruzioni, a volte anche lunghe, e poi, quando serviranno,
baster richiamare il Nome della Funzione perch le istruzioni in essa contenute siano disponibili, senza
quindi dover tutte le volte riscrivere le stesse istruzioni. Il bello che una Funzione (compilata in un
Modulo Vba), non solo sar disponibile in una istruzione macro o in un'altra funzione, ma sar
liberamente disponibile sui fogli di lavoro, proprio come faremmo con le funzioni tradizionali di Excel.
Ovviamente mi riferisco ai fogli che sono disponibili nella stessa cartella dove la funzione risiede. Una
volta chiuso il file, la nostra funzione non sar pi disponibile in Excel, ( possibile ovviare anche a
questo, ma lo vedremo in un altro momento), fino a quando non riapriremo la cartella che contiene la
funzione.
Diversit tra Procedure e Funzioni. Semplificando si pu dire che per Procedura si intende una macro
(routine o subroutine) cio una serie di istruzioni che compiono un'azione; per Funzione invece le
istruzioni non agiscono, ma forniscono un valore. Questo valore in stretta dipendenza agli argomenti
passati alla funzione stessa. Vediamo come si scrive una funzione (sintassi):
Function [nome che assegniamo alla funzione] ( argomenti (tipo dell'argomento) ) tipo di valore in
uscita
istruzioni
End Function
esempio della riga di dichiarazione funzione(tradotto in "pellegrinese"):
Function Pippo (Urca As Double) As Double
dove: Pippo = nome della funzione.
Urca = argomento (valore di tipo numerico con decimali (As Double) da "trattare" con le istruzioni
che inseriremo).
As Double = assegnazione del tipo di dato (intero con decimali) che Pippo restituisce.
E' sempre necessario rispettare le compatibilit tipologiche sia del dato trattato, sia del valore restituito,
pena arresto del programma e proteste del compilatore. Cio, se si dichiara che Urca una stringa (As
String) e gli si passa un numero, sar difficile che la funzione restituisca un valore Double da una stringa
(testo).
Ora, al di l delle istruzioni che inseriremo, come caspita useremo la funzione, e soprattutto, cosa si
intende per argomento (quell'Urca)?. Niente di pi facile: avete visto che su un foglio di Excel, se
vogliamo un certo risultato in una cella (la C1 per esempio) e vogliamo usare una Funzione di Excel,
scriveremo in C1 =NomeFunzione(A1) dove A1 il riferimento alla cella su cui la funzione dovr agire?
Bene, A1 l'argomento della funzione, o meglio il valore che si trover in A1 (il nostro Urca). Se in C1
avessimo quindi scritto =Pippo(A1) in pratica avremmo detto ad Excel : vatti a vedere le istruzioni
contenute nella Funzione Pippo, e applicale alla cella C1 usando il valore che sta in A1. Semplice, no?
Le cose non sono mai semplici, quando si fanno la prima volta, quindi proseguiamo col nostro esempio,
inserendo delle istruzioni che siano illustrative. Un accorgimento: nell'assegnazione del nome alla
funzione, evitiamo di usare nomi che siano gi di altre funzioni tipiche di Excel. Se decidessimo di farci
una Funzione personalizzata per la gestione dei decimali, evitiamo di dargli il nome ARROTONDA,
perch questo nome E' gi assegnato ad una funzione di Excel. (per visualizzare tutte le funzioni
presenti in Excel, dal men "Inserisci", scegliere "inserisci funzione", e nella finestra che si apre si potranno
vedere tutte le funzioni presenti, divise per categorie).
Le funzioni di Excel sono tranquillamente usufruibili nel vba (non tutte) (del come e quante sono ne
parlo nel paragrafo successivo, in questa stessa sezione), quindi l'esempio che faremo sar su una
funzione che NON esiste in Vba : la funzione del foglio di lavoro =TRONCA non esiste in vba, e ci
eserciteremo su quella (sto parlando di Funzione, da non confondersi con la trasposizione in Formula
vba della funzione =TRONCA, regolarmente gestibile in una routine del vba).
http://ennius.interfree.it/ Pagina 196
MANUALE VBA X EXCEL
La caratteristica della funzione =TRONCA, diversamente dalla funzione =ARROTONDA che appunto
arrotonda in +/- i decimali dell'ultimo decimale richiesto, che l'ultimo decimale viene preso cos come
st, SENZA arrotondamenti. Condizione necessaria ai calcoli fiscali dove esiste una disposizione
Ministeriale che precisa di "troncare" un valore al quarto decimale compreso. (faccio inoltre presente,
che non sufficiente impostare il formato celle a : numero con quattro decimali, perch lo vedremo
cos, a video, ma in realt il numero continua a possedere tutti i decimali che quindi sarebbero
conteggiati in calcoli successivi.)
La sintassi della funzione TRONCA sul foglio di lavoro :
=TRONCA(argomento1 ; argomento2)
dove: argomento1 il riferimento alla cella che contiene il numero da troncare, argomento2 un
numero che indica a quanti decimali effettuare il troncamento. Esempio con il numero 54789,8745712
in A1 e la funzione in C1
=TRONCA(A1;4) in C1 restituisce 54789,8745
se avessimo usato =ARROTONDA(A1;4) in C1 avremmo avuto 54789,8746
Ritornando alla nostra funzione, cercheremo di costruirla rispettando le impostazioni della versione
foglio di lavoro, cio con due argomenti in modo da poter decidere a quanti decimali effettuare il
troncamento; questo per avere una funzione adattabile nel caso venissero modificate le disposizioni.
Questa la funzione nella quale ho inserito anche due controlli: se la cella richiamata come primo
argomento sar vuota, si esce dalla funzione; se nella cella verr inserito un valore non numerico, si
viene avvisati con un messaggio e si esce dalla funzione:
Function Trunc(Numtot, Dex As Double) As Double
If Numtot = "" Then Exit Function 'se il valore vuoto si esce
If IsNumeric(Numtot) = True Then 'se il valore un numero, seguono istruzioni
num = Int(Numtot)
dec = Numtot - num
decim = Left(dec, Dex + 2)
Trunc = num + decim
Else 'altrimenti se non un numero si avvisa e si esce
MsgBox "Il valore immesso non un numero"
Exit Function
End If
End Function
Due spiegazioni: i nomi usati sono di fantasia: se avessimo usato Orazio e Clarabella per identificare gli
argomenti, anzich Numtot e Dex, non sarebbe cambiato niente: con Numtot si identifica il valore su
cui intervengono le istruzioni, e Dex identifica il numero di decimali che vogliamo. Per prima istruzione, a
parte i controlli, con num si ottiene l'intero dal valore; con dec si ottengono per differenza i decimali dal
valore; con decim si prelevano a partire da sinistra tanti decimali quanti richiesti con Dex, pi due (ne
dobbiamo contare 2 in pi perch in questo momento i decimali (dec) ottenuti sono visti dal codice
come un numero formato da uno zero, una virgola e tutti i numeri che formano i decimali: volendo 4
decimali, in realt ne dobbiamo prelevare (con Left) 6). A questo punto ci troviamo con un intero
(num) a cui sommiamo i decimali prelevati (decim) e otteniamo il risultato voluto che viene assegnato
alla funzione: infatti dichiariamo Trunc = num + decim. Se volete provarla, inserite la funzione in un
modulo vba, e richiamate la funzione sul foglio di lavoro, indicando la cella di cui volete il troncamento
del valore immesso, e quanti decimali volete, es.:
=TRUNC(D1;4)
Vediamo un altro esempio, questo fatto per modificare un impostazione di default
nell'Arrotondamento. Sappiamo che in Excel l'arrotondamento viene fatto per difetto se il decimale da
arrotondare uguale a 4 o inferiore, in caso contrario, cio dal 5 compreso in poi viene fatto per
eccesso. Noi vorremo un impostazione diversa, che il numero che provoca l'arrotondamento per
difetto non sia il 4 ma il 5, e quindi che per eccesso si consideri dal 6 compreso in pio (d'altra parte il 6
il primo numero oltre la met, almeno per noi comuni mortali, visto che consideriamo 1 come inizio
della decina, e quindi 5 la met di una decina, non 4, come invece considera il computer che vede i
numeri con base zero.) Al di l di questa disquisizione puramente discorsiva, ci siamo motivati la
necessit di realizzare la seguente funzione, che chiameremo Arrot per non confondere con la
funzione ARROTONDA, e di volere che ci restituisca una valore numerico con due decimali, tipico
esempio di un mondo fatto di euro. In questo caso useremo un solo argomento vista la decisione di
operare con due decimali fissi. Vediamo un esempio ed i soliti commenti (in verde):
Function Arrot(Numtot As Double) As Double
http://ennius.interfree.it/ Pagina 197
MANUALE VBA X EXCEL
Dim num, dec, dezero, X
num = Int(Numtot)
dec = Numtot - num
dezero = Left(dec, 4) 'estrae due decimali (scriviamo 4 per il motivo dello zero e della
'virgola spiegati nel precedente esempio)
X = Left(dec, 5) 'dobbiamo controllare se il terzo decimale 6 o maggiore per
decidere 'se arrotondare per eccesso il secondo decimale (anche qui usiamo 5 per
il motivo gi 'spiegato)
If Mid(X, 5) >= 6 Then 'se il terzo decimale 6 o maggiore, allora
dezero = dezero + 0.01 'incrementiamo di una unit il secondo decimale
Arrot = num + dezero ' e rendiamo la funzione uguale all'intero pi i decimali
Else 'in caso contrario
dezero = Left(dec, 4) 'ci teniamo il secondo decimale immutato (estrae due
decimali)
Arrot = num + dezero ' e rendiamo la funzione uguale all'intero pi i decimali
End If
End Function
Lascio ai "pellegrini" curiosi e volenterosi il compito di munire questo secondo esempio delle protezioni
necessarie ad impedire errori. Buon Lavoro.

http://ennius.interfree.it/ Pagina 198


MANUALE VBA X EXCEL
Funzioni Utente - creare una Aggiunta (.XLA) per Excel. (20/06/03)
Nell'articolo precedente (Funzioni Utente) abbiamo visto come creare funzioni personalizzate, e queste
funzioni risiedono nella cartella nella quale sono stata salvate. A volte per queste Funzioni, magari
costateci tempo e fatica nella realizzazione, ci tornerebbe utile poterle usare anche su altre cartelle,
sia su fogli di lavoro, sia inserite in procedure vba.
E' vero che possiamo usare il copia/incolla per reinserire la stessa funzione in altre cartelle, oppure
indicare nella nuova cartella, il percorso al file che contiene la funzione citando anche il nome della
funzione (in questo caso, devono essere aperte entrambe le cartelle), ma esiste un metodo pi valido,
che molti di voi sicuramente conoscono, la creazione di una Aggiunta (da salvare con l'estensione
.XLA).
Un Aggiunta (traduzione del termine inglese Add in) lo possiamo considerare un software che consente
di aumentare (aggiungere) nuove possibilit di esecuzione ad un programma.
Vediamo come fare:
Su una nuova cartella, inserire un modulo vba e scrivere (o copiare) la funzione che ci interessa
rendere disponibile.
Salvare la cartella, assegnandogli un nome, per esempio MieFunzioni, e scegliendo come "Tipo di file", il
formato .XLA - Nella finestra "Salva con nome" spostarsi nel men "Tipo di file" e selezionare
"Componente aggiuntivo di Microsoft Excel (*.xla)", vedi foto:

Una volta selezionato il tipo di file, come default viene presentata come cartella dove salvare, la
sottocartella "Addins" della cartella Documents and Settings/Nome utente/Dati Applicazioni/Microsoft.
Voi potrete scegliere la cartella che preferite.
Ora potremo rendere questa cartella disponibile su Excel, in modo che si possa usare la funzione
salvata il MieFunzioni su ogni altra cartella, vediamo come:
In Excel selezioniamo dal men Strumenti la voce Componenti Aggiuntivi e nella finestra che appare,
premere il pulsante Sfoglia per cercare il file e caricarlo. Ovviamente lo cercheremo nella cartella dove
l'avremo precedentemente salvato. Una volta acquisito il file, nella finestra "Componenti aggiuntivi
disponibili", vedremo il nome del nostro file. Ora potremo usare la o le funzioni in esso contenute.

Potremo a nostro piacere aggiungere sul file .XLA creato, tutte le funzioni che vorremo, in modo da
crearci "un'archivio" funzioni disponibile ora per tutte le cartelle che apriremo in Excel.. Per coloro che
http://ennius.interfree.it/ Pagina 199
MANUALE VBA X EXCEL
volessero usare queste procedure su computer in rete, dovranno dal pulsante "Sfoglia", selezionare il
percorso del file sul computer server, o meglio, ottenere una copia del file .xla da posizionare sul
computer client, e selezionare il percorso stabilito sul client.

http://ennius.interfree.it/ Pagina 200


MANUALE VBA X EXCEL
Il VBA e la gestione degli ERRORI

Istruzione On Error e Err.Number


Chiunque abbia iniziato a lavorare con il Vba, realizzando macro o routines, sicuramente incappato
in qualche "Errore" di programmazione. Queste note non vogliono essere un'analisi dei vari errori, ma
pi semplicemente una breve spiegazione di come poterli "addomesticare".
Gli "Errori" di cui ci occuperemo, non sono gli errori che vengono intercettati "mentre" si scrive del
codice (una macro), e che ci vengono immediatamente segnalati dal "compilatore", e che
riguardano esclusivamente errori di sintassi, (scrivendo male un istruzione, se omettiamo un carattere,
oppure una parentesi, o ancora il segno di uguale, ecc.), ma di quelli errori che ci vengono segnalati
quando, tutti soddisfatti lanciamo la nostra routine dal foglio di lavoro, e improvvisamente ci appare un
messaggio con su scritto : "Errore di Run-Time n xy", bloccando l'esecuzione delle istruzioni (in alcuni
casi anche il S.O.), e che ci lasciano frustrati e sgomenti. E' opportuno precisare che in Excel esistono
due tipi di intercettazione errori: uno gestito direttamente da Excel sul foglio di lavoro, attraverso i
purtroppo famosi messaggi nelle celle, tipo #N/D, opp. #DIV, ecc. ecc. (trovate una esauriente
spiegazione di questi errori nella sezione "Primi passi"), l'altro invece viene gestito dal Vba, e intercetta
gli errori di istruzioni inserite nel codice.
Intanto vediamo chi che ci avvisa, il Debugger, uno strumento di controllo delle istruzioni da
eseguire, presente in tutti i Programmi di compilazione, che ha il compito, appunto, di intercettare e
bloccare l'esecuzione di codice errato, segnalandoci il tipo di errore e l'eventuale numero di
identificazione. Esiste appunto una tabella, nella guida in linea, dove sono riportate le spiegazioni
relative ai numeri di errore. Qua sotto vi indico come arrivare alla tabella dei codici errore attraverso la
Guida in linea richiamabile dall'Editor di Visual Basic: nella cartellina "Indice", digitate la parola "errori",
premete "Cerca", e nella finestra "Selezione argomento" selezionate "Errori intercettabili", e nella pagina
a lato sulla destra appare l'elenco degli Errori Intercettabili, dove, per ogni errore, viene fornita una
spiegazione cliccando sul "messaggio".

Quando appare la finestra messaggio che ci avvisa dell'errore, troviamo due pulsanti : uno ci consente
di uscire dal blocco che si verificato a causa dell'errore stesso, l'altro, importante, dove c' scritto
"Debug", ci porta nella zona codice e ci viene evidenziata in giallo la riga dell'istruzione che sta
generando l'errore; questo ci consente di identificare l'istruzione incriminata, senza scervellarsi a
controllare tutte le istruzioni riga per riga. Potremo quindi (speriamo) capire cosa e come correggere,
evitando l'insorgere dell'errore.

http://ennius.interfree.it/ Pagina 201


MANUALE VBA X EXCEL
Esiste la maniera di poter gestire il verificarsi di un errore, attraverso un'istruzione appropriata, che On
Error. Si possono usare tre tipi di istruzioni basate su On Error, io vi segnalo quella, secondo me, pi
"universale", e che consente di evitare il blocco causato da un errore, con il vantaggio che le istruzioni
successive a quella che contiene l'errore, verranno comunque eseguite. ( ovvio che se l'errore si
verifica su un'istruzione che deve essere utilizzata dalle istruzioni successive, anche se le successive
verranno eseguite, il risultato voluto mancher, per l'assenza di un dato). L'istruzione On Error si
compone di due righe, la prima andr scritta cos On Error Resume Next e va posizionata subito sotto
l'inizio routine (che comincia sempre con il nome della macro o dell'oggetto il cui evento attiver le
istruzioni); la seconda riga invece : Resume e va posizionata a fine istruzioni, immediatamente
prima di End Sub. Tenere presente che la "visibilit" di queste istruzioni rimane di pertinenza della routine
che le incorpora. Per ogni routine andranno ripetute se vorremo un controllo errori su tutte. Facciamo il
classico esempio:
Sub Latua() 'nome macro o routine
On Error Resume Next
seguono tutte le righe di istruzioni
Resume
End Sub
Suggerirei di preparare le istruzioni On Error nella nostra/nostre macro, ma di tenerle disattivate (con un
apice ( ' ) ad inizio riga) durante la fase di compilazione del codice, perch dovendo provare se tutto
funziona bene, dovremo approfittare del Debugger perch ci segnali eventuali errori, cosa che non
avverrebbe se lasciamo operative le istruzioni On Error. Toglieremo poi l'apice una volta che avremo
verificato la correttezza della routine.
Abbiamo detto che l'uso di On Error ci consente di evitare il blocco delle istruzioni e l'uscita dal
programma. Esistono degli errori che si possono verificare DOPO che abbiamo controllato e trovato
esatte le nostre istruzioni, errori causati nella gestione del programma da noi fatto. L'istruzione On Error,
anche in questo caso interverrebbe per evitare il blocco, ma colui che sta lavorando e aspetta il
risultato di un operazione, non vede soddisfatta la sua richiesta, e non capisce il motivo. Imputa subito
la responsabilit al programma,senza pensare a cosa di sbagliato pu avere fatto lui. Vediamo di fare
un esempio : supponiamo di avere, in una UserForm, delle textbox nelle quali inseriremo dei valori da
moltiplicare, e in un'altra textbox, vogliamo il risultato. Useremo l'evento Click di un commandbutton
per attivare l'esecuzione del codice, queste le istruzioni:
Private Sub CommandButton1_Click
TextBox3 = (TextBox1) * (TextBox2)
End Sub
Apriamo la nostra Userform, scriviamo nella textbox1 un valore (18O) (ho scritto il numero 18 seguito
dalla o maiuscola, al posto dello zero), nella textbox2 un'altro valore (12)
Appena lanciamo l'esecuzione, apparir per un messaggio di errore: Errore di run-time 13; Tipo non
corrispondente.

Clicchiamo sul pulsante Debug, e ci ritroviamo nell'editor di visual basic, dove ci viene evidenziata la
riga dell'istruzione che ha causato l'errore :

http://ennius.interfree.it/ Pagina 202


MANUALE VBA X EXCEL

L'errore in questo caso, causato dal valore inserito nella textbox1, che non un numero, ma, per una
distrazione che accade spesso, una parte un numero (18) e parte una lettera dell'alfabeto (O).
Excel non pu eseguire una moltiplicazione se i valori non sono solo numeri. Questo, ovviamente un
esempio, ma che evidenzia la necessit di proteggere le nostre applicazioni non solo da errori di
compilazione di codice, ma da quegli errori che si possono verificare nell'uso del programma.
Inserendo quindi l'istruzione On Error nella nostra routine, avremmo evitato l'intervento del Debugger
con conseguente chiusura della form (premendo il pulsante "Fine"), o vederci catapultati nell'editor
con la sottolineatura della riga che ha generato l'errore (premendo il pulsante "Debug"). In tutti e due i
casi perderemmo eventuali dati gi scritti sulla form. Una modifica all'esempio precedente, con
l'inserimento di On Error, quindi sarebbe questa :
Private Sub CommandButton1_Click
On Error Resume Next
TextBox3 = (TextBox1) * (TextBox2)
Resume
End Sub
e otterremo di non far comparire la finestra del Debugger con la segnalazione dell'errore, e la
conseguente uscita dalla form.
Non avremmo per neppure ottenuto il risultato della moltiplicazione nella textbox3, perch si sarebbe
interrotta l'esecuzione del codice (grazie all'istruzione On Error.). E' evidente che un errore di scrittura
come quello esemplificato, pu lasciare perplessi e il "povero pellegrino", rimane l a fissare non
individuando subito il perch non viene il risultato. E' qui che possiamo "gestire" il verificarsi di un errore,
sfruttando l'istruzione Err.Number . (Premesso che un errore del genere pu essere intercettato prima
che si verifichi, usando la funzione IsNumeric con il ciclo If...Then) ma stiamo vedendo come usare una
gestione di errori, e quindi proseguendo con l'esempio sopra, potrebbe essere questa una giusta
compilazione che preveda l'uso della funzione Err.Number :

Private Sub CommandButton1_Click


On Error Resume Next
TextBox3 = (TextBox1) * (TextBox2)
If Err.Number = 13 Then
MsgBox "Il valore inserito non un numero"
End If
Resume
End Sub
Cosa succede quando il "pellegrino" lancia l'istruzione dopo aver scritto in una delle due textbox un
valore errato? Parte l'esecuzione delle istruzioni, viene trovato che uno dei due dati non un numero, si
genera l'errore n. 13, l'esecuzione continua fino alla riga If Err.Number = 13 Then che significa : SE il
numero dell'errore uguale a 13 ecc., mostra il messaggio che l'avvisa di correggere un valore, e poi
termina l'esecuzione fino a End Sub, senza bloccare niente n uscire dalla Form, avvisando inoltre che
qualcosa scritto male.
Un consiglio, quando si lavora usando valori numerici, sarebbe opportuno far conoscere al codice, che
tipi di numeri si stanno trattando, assegnando che "TIPO" di dati (numeri) una TextBox conterr.
Questo lo si pu fare dimensionando delle variabili con dichiarazione del "tipo" di variabile, esempio:
Dim X, Y, Z As Long
X = TextBox1
Y = TextBox2
Z = TextBox3
Z=X*Y

http://ennius.interfree.it/ Pagina 203


MANUALE VBA X EXCEL
Oppure, (e scriveremo di meno) sar sufficiente anteporre alla definizione dell'oggetto (textbox) una
definizione del tipo di dati numerici, per esempio: Integer, Long, Currency, Decimal, Single, Double ed
altri, usando le Funzioni di conversione relative. Esemplificando
CInt(TextBox1) - per numeri interi
CDbl(TextBox1) - per numeri decimali
Val(TextBox1) - riconosce numeri all'interno di stringhe
CCur(TextBox1) - Per formato valuta (e quindi anche con decimali)
Usate la Guida in Linea per prendere confidenza con questi concetti e leggere le caratteristiche di
ognuna. Nell'indice della Guida, scrivete "funzione", premete il pulsante "Cerca", e nella finestra
"Selezionare un argomento", cercate "Funzioni di conversione del tipo", selezionate questa voce, e sulla
destra appariranno le spiegazioni. Ricordo che la Guida diversa se si chiama dall'editor di visual basic
o dal foglio di lavoro. A voi in questo caso, serve quella dell'editor.

http://ennius.interfree.it/ Pagina 204


MANUALE VBA X EXCEL
Avere un Grafico sempre in vista.
Molto spesso, quando si usano grafici sui fogli di lavoro, diventa un problema mantenere nella stessa
videata, sia la zona di inserimento dati collegati al grafico, sia il grafico stesso, soprattutto per le
dimensioni che in genere si assegnano al grafico, e siamo quindi costretti a spostarci usando le barre di
scorrimento.
Esiste un modo, piuttosto semplice, di chiamare una finestra (nella stessa videata) che conterr il
grafico, e senza bisogno di spostarsi. Questa finestra si aprir nella videata attuale, e si potr tramite
due indicazioni, fare in maniera che la finestra si apra in posizione stabilita. Potremo quindi inserire il
grafico in una zona non visibile del foglio, inserire un pulsante nella zona della videata principale, e a
questo pulsante associare questa macro:
Sub Mostragrafico()
ActiveSheet.ChartObjects("Grafico 1").Activate
ActiveChart.ChartArea.Select
ActiveChart.ShowWindow = True
ActiveWindow.Left = 100
ActiveWindow.Top = 10
End Sub
Dove "Grafico 1" andr sostituito con il nome del vostro grafico, e 100 e 10 saranno valori da modificare
per centrare il vostro grafico. Il primo riferito alla distanza della nuova finestra dal margine sinistro
della videata "ActiveWindow.Left", il secondo riferito alla distanza dal bordo superiore del foglio di
lavoro (dove sono le intestazioni di colonna "ActiveWindow.Top"). Mancando questi riferimenti la
finestra del grafico si aprir a filo del margine destro del foglio di lavoro. Quando si premer il pulsante
associato, apparir le finestra con il grafico dentro.

http://ennius.interfree.it/ Pagina 205


MANUALE VBA X EXCEL
Il Metodo OnKeys. (12/05/03)
Ovvero : come utilizzare dei tasti della tastiera per attivare (lanciare) le macro.
Pu interessare prendere in esame un pratico sistema per il lancio delle nostre macro di una cartella di
lavoro, usando i tasti della nostra tastiera. Sar possibile usare sia un solo tasto (es: F3), sia una
combinazione di tasti insieme ai tasti ALT, CTRL o MAIUSC (es: ALT+G).
Questo metodo di semplice da capire; visto che OnKeys si applica solo all'oggetto Application (Excel
e la cartella di lavoro), potremo sfruttare l'evento WorkBook_Open perche si attivi l'istruzione, che
rester attiva da qualsiasi foglio poi si richiami premendo il tasto o la combinazione di tasti prescelta..
Cosa fa il metodo OnKeys: tramite la pressione sul/sui tasti, richiama il nome di una macro, e la lancia. Il
nome della macro va scritta tra due doppi apici. Vediamo subito l'esempio:
Su un modulo avremo una macro, semplice per esemplificare:
Sub pippo()
msgbox "Benvenuto"
End Sub
e questa sar l'istruzione che la richiamer, premendo il tasto F3
Private Sub Workbook_Open()
Application.OnKey "{F3}", "pippo"
End Sub
Volendo richiamare pi di una macro, inseriremo tante istruzioni in WorkBook_Open per quanti tasti
assegneremo. Fate solo attenzione a non usare i tasti che usa Excel come scorciatoie (F1, F6, F8 ecc.).
Precisazione: il metodo richiede che il nome del/dei tasti sia scritto tra due doppi apici e tra due
PARENTESI GRAFFE, importante, non usate le tonde perch si genera un errore. Per ottenere le graffe,
se non l'avrete sulla tastiera, le ottenete tenendo premuto il tasto ALT + 123 del tastierino numerico per
la graffa aperta "{" e ALT + 125 del t.n. per la graffa chiusa "}" . Vi riporto sotto, anche se trovate tutto
sulla guida in linea, la tabella dei tasti
TASTO CODICE DA USARE

AIUTO {HELP}
BACKSPACE {BACKSPACE} o {BS}
BLOC MAIUSC {CAPSLOCK}
BLOC NUM {NUMLOCK}
BLOC SCORR {SCROLLLOCK}
CANC {DELETE} o {DEL}
CANCELLA {CLEAR}
da F1 a F15 da {F1} a {F15}
ESC {ESCAPE} o {ESC}
FINE {END}
Freccia DESTRA {RIGHT}
Freccia GI {DOWN}
Freccia SINISTRA {LEFT}
Freccia SU {UP}
HOME {HOME}
INVIO {RETURN}
INVIO ~ (tilde)
INVIO (tastierino numerico) {ENTER}
INS {INSERT}
PAUSA {BREAK}
PGGI {PGDN}
PGSU {PGUP}
TAB {TAB}
inoltre possibile specificare dei tasti in combinazione con MAIUSC e/o CTRL e/o ALT. Per specificare un
tasto in combinazione con uno o pi tasti, utilizzare la seguente tabella
Per specificare la Il codice del tasto deve essere
combinazione con preceduto da
MAIUSC + (segno pi)
CTRL ^ (accento circonflesso)
ALT % (simbolo di percentuale)

http://ennius.interfree.it/ Pagina 206


MANUALE VBA X EXCEL
esempio: tasto Control + Freccia destra
Application.OnKey "^{RIGHT}", "pippo"

Esiste anche un altro metodo per "lavorare" con i tasti, ed il metodo SendKeys. Per questo metodo
presenta degli "inconvenienti", che anche altre persone ben pi qualificate di me riconoscono
imperfetto e fonte di incavolature da parte dell'utente. Inoltre anche la guida presenta un esempio
che definirei "curioso" nel risultato. Provate per esempio questa istruzione, posizionata nell'evento
WorkSheet_SelectionChange per comodit di verifica, ma potreste metterlo anche nel
WorkBook_Open, il risultato non cambia. La guida riporta questo esempio, cos scritto, per terminare
Microsoft Excel:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Application.SendKeys ("%fx")
End Sub
e quando cambierete selezione sul foglio di lavoro... si aprir il sottomenu del menu File.
Buon lavoro.

prelevato sul sito http://ennius.interfree.it

http://ennius.interfree.it/ Pagina 207


MANUALE VBA X EXCEL
Controllare se abbiamo il PesoForma. (01/05/03)
Un simpatico esercizio che ci aiuta a lavorare col VBA. Usiamo una UserForm, che faremo aprire
sfruttando l'evento WorkBook_Open, dove inseriamo anche l'istruzione per ridurre ad icona Excel, in
modo da vedere la nostra userform in primo piano.
Private Sub Workbook_Open()
Application.WindowState = xlMinimized 'per rendere a icona
UserForm1.Show 'per aprire la userform
End Sub

Sulla UserForm inseriremo alcune Label (etichette), due TextBox ed un pulsante (CommandButton) che
ci servir per attivare le istruzioni sfruttando il suo evento Click. Inseriamo anche due OptionButton che
selezioneremo a seconda dei casi (Maschio o Femmina), e che influenzano il tipo di risposta. Nelle
istruzioni ci avvaliamo del construtto Select Case ... End Select per determinare cosa fare a secondo
dell'OptionButton selezionata. Il funzionamento semplice: inserendo nelle due TextBox il peso e
l'altezza, otterremo col click sul pulsante lo sviluppo di questa formula che fornisce dei valori per
valutare il rapporto peso/forma :
peso diviso il quadrato dell'altezza
In funzione del valore ottenuto si determina se tutto Ok, o se siamo magri o grassi oppure obesi.

Cliccando sulla Label la cui Caption : "Fattore di conversione", appare una MessageBox che mostra i
rapporti, e sfrutteremo quindi l'evento Label_Click
Private Sub Label5_Click()
Dim Mytt As String
Mytt = Mytt & "Fattori di Rapporto " & vbLf & vbLf
Mytt = Mytt & "Da 20 a 24.9 = Peso Forma" & vbLf
Mytt = Mytt & "Da 25 a 29.9 = Sovrappeso" & vbLf
Mytt = Mytt & "Da 30 a 35 = Obesit" & vbLf
MsgBox Mytt
End Sub
In chiusura della Userform, cliccando sulla X di chiusura, sfruttiamo l'evento QueryClose e inseriremo le
istruzioni per ripristinare Excel a schermo intero e contemporaneamente a chiuderlo:
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
Application.WindowState = xlMaximized
Application.Quit
End Sub
E queste sono le istruzioni inserite nel Click del CommandButton; non le commento perch sono
semplici, sono presenti due controlli per verificare che non ci si dimentichi le textbox vuote, e una serie
di If..Then.., ElseIf...Then che verificano il valore restituito dalla formula (variabile X) e in funzione di
questo valore restituiscono nella Label3 una stringa che potr essere variata a piacere, ovviamente
controllate dal Select Case Options delle due OptionButton :
Private Sub CommandButton1_Click()
If TextBox1 = "" Then
http://ennius.interfree.it/ Pagina 208
MANUALE VBA X EXCEL
Label3.Caption = "DEVI INSERIRE IL TUO PESO"
TextBox1.SetFocus
Exit Sub
End If
If TextBox2 = "" Then
Label3.Caption = "DEVI INSERIRE LA TUA ALTEZZA"
TextBox2.SetFocus
Exit Sub
End If
X = (Val(TextBox1) / (Val(TextBox2) * Val(TextBox2)))
Label4.Caption = Format(X, "###.00")

Select Case Options


Case OptionButton2
If X < 20 Then
Label3.Caption = "SEI UN FILUSSINO. STAI ATTENTO AI COLPI DI VENTO."
Label3.FontBold = True
Label3.ForeColor = vbRed
ElseIf X >= 20 And X <= 24.9 Then
Label3.Caption = "SEI IN PESO FORMA. COMPLIMENTI"
Label3.FontBold = True
Label3.ForeColor = vbMagenta
ElseIf X >= 25 And X <= 30 Then
Label3.Caption = "SEI SOVRAPPESO. COMINCIA A METTERTI A DIETA."
Label3.FontBold = True
Label3.ForeColor = vbBlue
ElseIf X >= 30.1 Then
Label3.Caption = "SEI OBESO. BUHHH!!!. AI BISOGNO DI INTERVENIRE DRASTICAMENTE.
TI PISCI SULLE SCARPE ?"
Label3.FontBold = True
Label3.ForeColor = vbRed
End If
Case OptionButton1
If X < 20 Then
Label3.Caption = "SEI TROPPO MAGRA, STAI RISCHIANDO L'ANORESSIA"
Label3.FontBold = True
Label3.ForeColor = vbRed
ElseIf X >= 20 And X <= 24.9 Then
Label3.Caption = "SEI IN PESO FORMA. COMPLIMENTI"
Label3.FontBold = True
Label3.ForeColor = vbMagenta
ElseIf X >= 25 And X <= 30 Then
Label3.Caption = "SEI SOVRAPPESO. COMINCIA A METTERTI A DIETA."
Label3.FontBold = True
Label3.ForeColor = vbBlue
ElseIf X >= 30.1 Then
Label3.Caption = "SEI OBESA. BUHHH!!!. AI BISOGNO DI INTERVENIRE DRASTICAMENTE.
TE LA VEDI SEMPRE ?"
Label3.FontBold = True
Label3.ForeColor = vbRed
End If
End Select
End Sub

File consultabile e scaricabile : Peso Forma.zip 12 Kb Versione per XP

http://ennius.interfree.it/ Pagina 209


MANUALE VBA X EXCEL
Caricare un elenco (lista) con dati da selezionare. (05/07/03)
Tra le tante necessit quotidiane, ci troviamo spesso a dover aggiungere dei dati in un elenco. Un
operazione che possiamo prendere ad esempio e che si presta per spiegare i concetti, riguarda
l'inserimento degli articoli venduti, in una fattura. Infatti nella emissione di una fattura, useremo dati che
verranno scritti (nelle celle appositamente designate) una sola volta, come il nome del Cliente,
indirizzo, pagamento, p.iva, ecc. ecc., mentre avremo dati che dovremo o potremo scrivere pi volte,
come i prodotti da fatturare, con la loro descrizione, il codice articolo, unit di misura, quantit, prezzo
unitario, ecc. ecc. In questi casi normalmente viene destinata una zona dove poter aggiungere, riga
dopo riga, i vari prodotti e loro caratteristiche. Le procedure che presento riguardano appunto:
come reperire i prodotti da inserire tramite combobox su userform
come inserire i prodotti nell'area assegnata, disponendo i dati correlati all'articolo nelle celle di
pertinenza.
svolgere una parte dei conteggi (quantit x prezzo - ev sconto) direttamente con l'inserimento
dell'articolo.
Premetto che questo articolo molto dettagliato e un p lunghetto, consiglio a chi ne sia interessato di
stamparsi le pagine (verranno stampate anche le immagini) e leggerselo TUTTO con calma a casa.
Come esercizio user un file che un caro amico, Domenico Svolacchia, mi ha gentilmente messo a
disposizione, e su cui ho sviluppato le procedure relative all'"inserimento articoli". Vediamo intanto la
"struttura" di impostazione della fattura relativa alla zona inserimento articoli:

Come vediamo, a partire dalla riga 18, potremo inserire gli articoli, che andranno nel campo
"descrizione", e dovremo inserire nei campi tutti i dati riguardanti l'articolo scelto. Gli articoli che
inseriremo sono in una tabella del foglio "Magazzino", che avremo cura di strutturare sulla falsariga
dell'ordine campi riportati in fattura, in modo da "allineare" i campi in entrambi i fogli. Logicamente sul
foglio "Magazzino" non saranno presenti i campi che riguardano i conteggi (totale, sconti, imponibile)
inutili in questo foglio. Vediamo il foglio Magazzino con l'impostazione della tabella articoli:

All'area del foglio Magazzino predisposta a contenere dati, assegniamo un nome : "maga" che
corrisponde a =Magazzino!$A$2:$B$1000, per facilitare il riferimento alla zona quando lo useremo nel
codice vba per assegnare il RowSource alla combobox posta sulla userform.
Bene, abbiamo visto la zona di destinazione, e la zona di origine dei dati, ora vediamo come reperirli
(primo punto nelle descrizione delle procedure:
la prima procedura, chiamare la userform dal foglio di emissione fattura, che useremo come
"maschera" per la selezione dell'articolo, e lo faremo tramite il commandbutton "Inserisci Articolo", nel
cui evento Click, inseriamo questa istruzione:
Private Sub CommandButton3_Click() 'pulsante "Inserisci Articolo"
UserForm1.Show
End Sub
e questo sar l'aspetto della userform:, in cui vediamo una combobox che ci servir per selezionare
un'articolo tra quelli presenti sul foglio "Magazzino", una textbox per inserire la quantit da fatturare, e

http://ennius.interfree.it/ Pagina 210


MANUALE VBA X EXCEL
due textbox per inserire eventuali sconti concessi sull'articolo. Completa l'userform il commandbutton
"In Fattura" , che nell'evento Click, ha inserito tutte le istruzioni (che vedremo) per l'inserimento
dell'articolo e dei dati correlati nell'area della fattura predisposta:

Sfrutteremo quindi l'apertura della userform per assegnare l'area dati del foglio magazzino al
RowSource della combobox, con questa istruzione:
Private Sub UserForm_Activate()
ComboBox1.RowSource = "Magazzino!maga"
End Sub
Come abbiamo notato dalle spiegazioni sopra, stiamo "caricando" nella combobox due colonne di
dati : la colonna A con il codice articolo e la colonna B con la descrizione dell'articolo (A2:B1000). Un
piccolo accorgimento che ci permetter di identificare meglio l'articolo da fatturare, vedremo infatti
sia il codice sia la descrizione ( possibile infatti che esistano pi articoli con la stessa descrizione, e sar
quindi possibile identificare quello giusto tramite il codice articolo che dovr necessariamente essere
univoco). Vediamo un immagine della combobox col men aperto:

Come facciamo ad avere visibili due colonne nella combobox ? Utilizzando alcune propriet che
troveremo nella "Finestra delle propriet" della combobox, nell'editor del visual basic :
propriet ColumnCount : la imposteremo a 2 in quanto vorremo vedere appunto due colonne.
propriet ColumnWidths : con questa propriet possibile determinare la larghezza di ogni singola
colonna, indicando un valore espresso in punti seguito da pt , separando con un punto e virgola i valori
decisi; in questo esempio i valori assegnati sono : 48 pt;72 pt .Regolando questi valori assegneremo
larghezze diverse alle colonne.
Vediamo poi come gestire via codice, altre due propriet della combobox che determinano il modo
di assegnazione del valore di ogni campo (ne abbiamo 2 nella combobox) a due celle distinte del
foglio di lavoro
propriet Text : con ComboBox1.Text identifichiamo il valore che si trova nella prima colonna a sinistra
della riga selezionata (in questo caso il codice articolo).
propriet BoundColumn : con questa propriet determiniamo, assegnandoli un numero, a quale
colonna ci riferiremo perch ci venga restituito il valore corrispondente nella riga selezionata. il numero
che indicheremo, sar sempre un indice che parte da 1 (e non da zero come in genere fanno i valori
indice in vb). Poich a noi interessa a questo punto la "descrizione articolo" che vediamo nella
seconda colonna, abbiamo bisogno di due istruzioni; la prima assegna il valore indice alla propriet
BoundColumn, cos : ComboBox1.BoundColumn = 2
la seconda dovr fare riferimento non pi al Text, bens al Value (valore indice, cio 2) della
ComboBox, cos : ComboBox1.Value .Questo ci restituir la descrizione articolo.
Ci siamo fino a questo punto? Bene, ora proseguiamo con l'esame della routine che dovr provvedere
a trovare, nel foglio fattura, la prima riga libera dove inserire i dati selezionati nella combobox. Ci
affidiamo per questo ad un ciclo While...Wend, ciclo che controlla una condizione, e continua
fintantoch si verifica la condizione richiesta. Poich vorremo controllare, posta una riga di partenza (la
riga 18. inizio inserimento articoli nella fattura) se una riga vuota, abbiamo bisogno di un "contatore"
http://ennius.interfree.it/ Pagina 211
MANUALE VBA X EXCEL
che incrementi di uno il controllo per garantire l'avanzamento verso il basso di una riga, e queste sono
le istruzioni del ciclo:
Dim iRow As Integer
iRow = 18 'si imposta il numero riga dal quale iniziare il controllo, quindi iRow ora uguale a 18
While Cells(iRow, 2).Value <> "" 'Fino a che la cella (ora la18, colonna 2) diversa da vuoto (cio
iRow = iRow + 1 'contiene dati) si incrementa il numero riga di uno e con Wend si richiama While
Wend 'continuando la verifica, e quando si trover una cella vuota, si esce dal ciclo
va da se che se la prima riga vuota (la 18) si esce dal ciclo e si eseguiranno le istruzioni che
seguiranno, altrimenti verr controllata la condizione richiesta per la riga 19, poi la 20, ecc. ecc.
Ricordo che quando si usa la propriet Cells (dell'Insieme Range) il primo numero indica la riga, il
secondo dopo la virgola indica la colonna. Questo ci dice due cose :
la prima che stiamo controllando le righe della colonna due, cio la colonna B, dove si trover la
descrizione articolo.
la seconda che quando verr trovata una cella vuota, quella sar la cella identificata con (iRow, 2);
se vorremo riferirci ad altre celle della stessa riga sar sufficiente modificare il numero colonna; per
esempio con (iRow, 4) identificheremo la cella della 4 colonna, cio la D; il numero di riga dipender
dal valore che in quel momento avr iRow.
Fatte tutte queste premesse, passiamo ora ad esaminare la routine inserita nell'evento Click del
CommandButton "In Fattura". Ultime considerazioni:
per automatizzare al massimo il lavoro, stato previsto che l'inserimento della Quantit da fatturare
avvenga dalla userform, attraverso l'immissione di un valore, che potr essere anche decimale, nella
casella di testo oppurtuna. Sempre dall'userform si disporr per un eventuale sconto semplice o
doppio, visto che si presume che gli sconti non sempre siano concessi, e comunque potranno variare
in funzione del cliente e/o delle quantit. Predisporre dei campi sconti preimpostati nel foglio
magazzino non lo ritengo utile ma limitante.
Saranno commentate in verde le istruzioni non ancora viste.
Private Sub CommandButton1_Click()
'sotto: si controlla solo se nella textbox1 stata inserito un valore, in caso contrario si
'avvisa e si esce dalla routine
If TextBox1 = "" Then
MsgBox "Manca la quantit"
TextBox1.SetFocus
Exit Sub
End If
'sotto: inizia il ciclo While..Wend
Dim iRow As Integer
iRow = 18
While Cells(iRow, 2).Value <> ""
iRow = iRow + 1
Wend
'trovata la riga con la cella vuota, scrivo la selezione fatta nella combobox
Cells(iRow, 1) = ComboBox1.Text 'prendo il codice art. e lo inserisco nella colonna 1
X = Cells(iRow, 1).Address ' con la variabile X prendo il riferimento alla
'cella che user poi come primo argomento nella funzione vLookUp pi sotto
ComboBox1.BoundColumn = 2
Cells(iRow, 2) = ComboBox1.Value 'ora assegno alla riga, 2 colonna
'il valore trovato con BoundColumn, cio la descrizione articolo
Cells(iRow, 4) = CDbl(TextBox1) 'assegno alla cella della colonna 4 (la D) la quantit
'dichiarandola come "tipo di dati" Double cio numero con decimali
TextBox1 = "" 'pulisco la textbox1

'faccio cercare con vlookup i valori correlati al codice art. cio unita misura, prezzo,
al. 'iva. e li assegno alle rispettive colonne, stessa riga di iRow
Cells(iRow, 3).Formula = "=vlookup(" & X & ",Magazzino!A2:E500,3,0)"
Cells(iRow, 5).Formula = "=vlookup(" & X & ",Magazzino!A2:E500,4,0)"
Cells(iRow, 10).Formula = "=vlookup(" & X & ",Magazzino!A2:E500,5,0)"

'ora facciamo da codice tutte le operazioni per i conteggi:


http://ennius.interfree.it/ Pagina 212
MANUALE VBA X EXCEL
'otteniamo il parziale: prezzo x quantit, usandoli come tipo di dati Double
Cells(iRow, 6) = CDbl(Cells(iRow, 4) * CDbl(Cells(iRow, 5)))

'ora conteggiamo l'imponibile considerando gli sconti:


'assegniamo a due variabili gli importi presenti nelle textbox per gli sconti.
'se lo sconto non esiste bisogna assegnare comunque un valore, altrimenti si genera
un 'errore se il valore vuoto, e quindi in mancanza di un valore impostiamo lo zero:
If TextBox2 = "" Then TextBox2 = 0
sc1 = CDbl(TextBox2) 'la variabile sc1 uguale al primo valore di sconto

If TextBox3 = "" Then TextBox3 = 0


sc2 = CDbl(TextBox3) ' come sopra per sc2 uguale al secondo valore di sconto

'ora scontiamo il parziale per il primo sconto e lo memoriziamo


'in una variabile nps (netto primo sconto)
nps = CDbl(Cells(iRow, 6) - CDbl(Cells(iRow, 6) * CDbl(sc1) / 100))

'ora se il primo valore di sconto maggiore di zero lo scriviamo in fattura


If sc1 > 0 Then Cells(iRow, 7) = sc1

'poi anche se il secondo valore di sconto maggiore di zero lo scriviamo in fattura


ed 'eseguiamo il calcolo
If sc2 > 0 Then
Cells(iRow, 8) = sc2
'ora scontiamo il nps per il secondo sconto e lo memoriziamo in una variabile nss
(netto 'secondo sconto)
nss = CDbl(nps) - CDbl((nps * sc2) / 100)

Cells(iRow, 9) = nss 'ora l'imponbile uguale a netto secondo sconto


Else ' altrimenti (se il secondo sconto zero)
Cells(iRow, 9) = nps 'l'imponibile uguale al netto primo sconto
End If
TextBox2 = "" 'pulisco la textbox2
TextBox3 = "" 'pulisco la textbox3
'sotto, reinizializzo la combobox per una successiva selezione articolo
ComboBox1.Text = "Seleziona un'articolo"
End Sub
Abbiamo scritto un bel p di codice, ma i risultati sono eccellenti : ci troveremo gi con tutti i calcoli
fatti, ed in pi se non avremo assegnato sconti, i relativi campi in fattura non porteranno neanche lo
zero, cosa che se ci fosse comunque un valore in fattura, potrebbe far pensare al cliente che gli sconti
sono previsti e quindi gestibili, mentre cos si potr dire che le colonne sconti le ha inserite il compilatore
del modulo fattura ma che in realt non esiste sconto (infatti i campi sono vuoti). L'ultima colonna,
quella dell'aliquota iva, servir perche i conteggi dei totali useranno la funzione SOMMA.SE reperendo
il totale dei parziali collegati alle varie aliquote, ed applicando quindi l'iva di pertinenza sul relativo
imponibile. Un immagine della zona totali:

Ho indicato la Formula per la somma degli importi relativi all'aliquota iva 4%, nelle celle sottostanti ci
saranno le formule per iva 10% e iva 20%. Gli importi iva si ottengono con una semplice moltiplicazione,
e i totli portaranno la somma degli imponibili, la somma degli importi iva e quindi il totale fattura. Allego
il file per consultazione premettendo che le procedure andranno ultimate a cura dei "pellegrini" che
http://ennius.interfree.it/ Pagina 213
MANUALE VBA X EXCEL
vorranno scaricarsi il file: manca la registrazione dei dati fattura, il salvataggio del solo foglio fattura
come copia, ed altre amenit lasciate ai bisogni di ogni singolo utente. Mi interessava illustrare le
procedure per l'inserimento dei dati, e questo credo di averlo espletato.

File consultabile e scaricabile : Fattura2000.zip 38 Kb

http://ennius.interfree.it/ Pagina 214


MANUALE VBA X EXCEL
Inserimento righe o colonne in automatico.
L'inserimento di una nuova riga o colonna in un foglio di excel cosa estremamente semplice:
sufficiente selezionare l'intestazione di riga (o di colonna) (che la zona del foglio dove sono riportati i
Numeri per le righe, o le Lettere per le colonne) e, cliccando poi con destro del mouse sulla selezione,
scegliere dal men che appare, la voce "Inserisci". Immediatamente SOPRA alla riga selezionata si
inserir la nuova riga, mentre per le colonne, la nuova colonna si inserir immediatamente PRIMA della
colonna selezionata. Tutte le lettere o i numeri di riga verranno immediatamente aggiornati, ed
eventuali formule o funzioni saranno aggiornate in automatico. Esiste a volte la necessit, specie su
cartelle complesse, di inserire una nuova riga non solo sul foglio su cui si sta lavorando, ma anche su
altri fogli, collegati, e ovviamente nello stesso punto in cui abbiamo inserito la riga del primo foglio.
Potrebbe essere il caso di aggiunte su pi fogli che portino lo stesso elenco di dati, ed aggiungendo
una riga sul primo foglio vogliamo che nella stessa posizione vengano aggiunte righe anche su tutti i
fogli collegati. Quella che propongo una macro, da inserire in un modulo, ed associare ad un
pulsante da tenere sul primo foglio. La macro aggiunger una riga sopra una qualsiasi riga selezionata,
passer al foglio successivo, inserir una riga nelle stesso punto e ritorner al foglio di partenza, sulla
riga appena inserita.
Sub InserimentoRiga()

Dim X, Y As Variant
X = ActiveCell.Address
Y = Mid(X, 4, 5)
Worksheets("foglio1").Select
Rows(Y).Select
Selection.Insert Shift:=xlDown

Worksheets("foglio2").Select
Rows(Y).Select
Selection.Insert Shift:=xlDown
Worksheets("foglio1").Select
Rows(Y).Select

Set X = Nothing
Set Y = Nothing
End Sub
La macro potr essere modificata, per adattarla alle proprie esigenze, non solo cambiando il numero
del foglio, ma inserendo ex novo una nuova istruzione per ogni foglio su cui volessimo inserire righe. Per
esempio, volendo inserire una riga anche sul foglio3, inserire la seguente istruzione (va inserita in macro
prima del "ritorno"):
Worksheets("foglio3").Select
Rows(Y).Select
Selection.Insert Shift:=xlDown
Se invece avremo deciso di inserire una stessa riga in ogni foglio della cartella di lavoro, dovremo
impostare un ciclo che "spazzoli" tutti i fogli inserendo la riga, quindi la routine Sub InserimentoRiga(),
sempre basandoci sul reperimento del numero riga attraverso la cella attiva in quel momento, diventa:
Sub InserimentoRiga2()

Dim X, Y As Variant
X = ActiveCell.Address
Y = Mid(X, 4, 5)
For Each ws In Worksheets 'per ogni foglio (ws) dell'insieme Fogli
ws.Rows(Y).Insert Shift:=xlDown 'inseriamo "a distanza" (senza bisogno si selezionare i fogli) la riga
Next
Set X = Nothing
Set Y = Nothing
End Sub
Ovviamente se vorremo legare l'inserimento riga non ad una variabile (Y) che ne indichi il numero, ma
deciderlo fornendo noi il numero, sar sufficente un istruzione semplificata:
Sub InserimentoRiga3()
http://ennius.interfree.it/ Pagina 215
MANUALE VBA X EXCEL
For Each ws In Worksheets 'per ogni foglio (ws) dell'insieme Fogli
ws.Rows(15).Insert Shift:=xlDown 'inseriamo "a distanza" (senza bisogno si selezionare i fogli) la riga
Next
End Sub
dove 15 il numero che identifica la riga.
Per quanto riguarda l'inserimento di colonne valgono gli stessi concetti, tenendo presente che le
colonne si possono identificare sia con lettere, e in questo caso dovremo indicare l'intera colonna
usando i riferimenti, oppure con i numeri, esempi:
con lettera di colonna:
Sub InserimentoColonna1()
For Each ws In Worksheets 'per ogni foglio (ws) dell'insieme Fogli
ws.Columns("E:E").Insert Shift:=xlDown 'inseriamo "a distanza" (senza bisogno si selezionare i fogli) la
colonna
Next
End Sub
Con il numero di colonna:
Sub InserimentoColonna2()
For Each ws In Worksheets 'per ogni foglio (ws) dell'insieme Fogli
ws.Columns(5).Insert Shift:=xlDown 'inseriamo "a distanza" (senza bisogno si selezionare i fogli) la
colonna
Next
End Sub
Le due istruzioni forniscono il medesimo risultato.
Va da s che sar possibile inserire in contemporanea righe e colonne inserendo le due istruzioni, una
per la riga ed una per la colonna:
Sub InserimentoRigaColonna()
For Each ws In Worksheets 'per ogni foglio (ws) dell'insieme Fogli
ws.Rows(15).Insert Shift:=xlDown 'inseriamo "a distanza" (senza bisogno si selezionare i fogli) la riga
ws.Columns(5).Insert Shift:=xlDown 'inseriamo "a distanza" (senza bisogno si selezionare i fogli) la
colonna
Next
End Sub
Buon lavoro.

http://ennius.interfree.it/ Pagina 216


MANUALE VBA X EXCEL
L'istruzione WITH. (02/06/03)
Nella compilazione di codice VB sappiamo che possiamo usare "oggetti" per impartire istruzioni su
come gestirli. Sono "oggetti" le celle del foglio di lavoro, gli stessi fogli di lavoro, i commandbutton, le
userform, le caselle di testo, le label (etichette), Excel stesso visto come "Application", ecc. ecc.
Gli "oggetti" possiedono delle "propriet" che possibile modificare nelle "impostazioni" relative ad ogni
"propriet". All'oggetto "Range" per esempio, possibile assegnare un colore di fondo (oggetto :
Interior e propriet : ColorIndex), possibile impostare un carattere specifico (oggetto : Font
propriet : Name), possibile impostare il carattere grassetto (oggetto : Font e propriet : Bold),
possibile impostare i bordi (oggetto : Border), ecc. ecc. (attenzione: alcuni dei nomi citati possono
essere sia "oggetti" che "propriet", ma non in questo articolo che dobbiamo valutare le differenze).
Facciamo un esempio impostando delle istruzioni in codice su una cella, la A1:
Range("A1").Interior.ColorIndex = 6 'imposta in giallo il colore di fondo della cella
Range("A1").Font.Name = "Courier" 'imposta il carattere come Courier
Range("A1").Font.Bold = True 'imposta il grassetto al carattere
Range("A1").Font.Size= 12 'imposta la dimensione del carattere
ecc.ecc.
Come si vede, ripetiamo ad ogni riga su quale "oggetto" (Range("A1")) applicare le relative
impostazioni. Esiste un modo per riferirsi una sola volta "all'oggetto" , risparmiando codice scritto e
velocizzando l'esecuzione stessa delle istruzioni, usando l'istruzione WITH (con).
L'istruzione With consente di eseguire una serie di istruzioni su un oggetto specificato senza riqualificare
il nome dell'oggetto. Se, ad esempio, si desidera modificare una serie di propriet diverse per un
singolo oggetto, risulta pi agevole inserire le istruzioni di assegnazione di propriet all'interno della
struttura di controllo With facendo riferimento all'oggetto una sola volta, invece di dover includere il
riferimento per ogni assegnazione di propriet. La sintassi dell'istruzione :
With "oggetto" 'inizio istruzione
.istruzione (IMPORTANTE: ogni riga di istruzione deve iniziare con il punto ( . ), il punto che indica al
codice che l'istruzione ' relativa all'oggetto identificato con With)
End With 'fine istruzione; necessario scriverla

per cui il nostro esempio sopra diventer:


With Range("A1")
.Interior.ColorIndex = 6
.Font.Name = "Courier"
.Font.Bold = True
.Font.Size= 12
End With
Se ci dimentichiamo il punto ad inizio di ogni istruzione relativa al Range, il debugger si scatena e ci
segnala subito l'errore: "Necessario oggetto" in quanto senza il punto il codice non sa a chi assegnare
l'istruzione.
Nell'esempio sopra, vediamo che possibile "mescolare" istruzioni (colore cella e impostazioni sul
carattere) in quanto ci riferiamo all'oggetto Range, usando come istruzioni altri "oggetti" facenti parte
dell'oggetto Range, (Interior, Font) ai quali assegniamo delle propriet (ColorIndex, Name, Bold, Size).
Diverso sarebbe se al posto di usare istruzioni con "oggetti" e loro propriet, avessimo voluto usare
direttamente le sole propriet. In questo caso avremmo avuto bisogno di definire su quale oggetto
usare le propriet, e visto che Name, Bold e Size NON sono propriet dell oggetto Range ma
dell'oggetto Font, dovremo modificare cos la nostra istruzione:
With Range("A1").Font
.Name = "Courier"
.Bold = True
.Size = 12
End With
In questo caso le propriet Name, Bold e Size usate da sole (col punto) vengono accettate perch
riferite all'oggetto Font dichiarato con With.
E l'oggetto Interior con la sua propriet ColorIndex ? In questo caso non pu essere usato perch non
rappresenta n un oggetto n una propriet dell'oggetto Font, andr impostata un'altra istruzione.

Buon lavoro.

http://ennius.interfree.it/ Pagina 217


MANUALE VBA X EXCEL
Stampare con Excel (vba). (17/06/03)
L'utilizzo di Excel come programma per stampare si rivela facile e molto versatile, e attraverso istruzioni
in codice possiamo pilotare tutto il processo di stampa, dall'impaginazione, alla regolazione dei
margini, dal formato di stampa all'orientamento (verticale oppure orizzontale), e molti altri parametri;
compreso la possibilit di inserire intestazioni di pagina o pi di pagina; basta dare un occhiata alla
guida in linea a tutti gli argomenti legati alla stampa (nella guida digitate la parola Print e poi
selezionate uno ad uno tutti gli argomenti correlati). Sembra per che molti "pellegrini" si trovino un "p"
in difficolt quando debbano accedere alla guida in linea, ed allora provo ad illustrare per sommi capi
alcune procedure da affrontare. Indicazioni le trovate comunque anche in questa sezione, articolo
"Estrarre i dati e stampare".
L'istruzione pi veloce e semplice da capire, (questo esempio stampa il foglio attivo) :
ActiveSheet.PrintOut
L'istruzione sfrutta il metodo PrintOut, che ricco di argomenti che diversificano molte opzioni di
stampa, ma che non presento in questo esercizio (rimando gli interessati alla guida in linea cercando
l'argomento "Metodo PrintOut").
Imposter una routine che copra diverse esigenze, prendendo come spunto la necessit di stampare
elenchi anche lunghi (su pi pagine) con l'utilizzo di una "intestazione di pagina", che verr stampata in
automatico su ogni foglio successivo e fino alla fine dell'elenco.
La prima cosa che ci serve, definire l'"Area di stampa", cio la zona che vogliamo vada in stampa.
Operazione secondo me necessaria visto che l'istruzione vista sopra stamperebbe tutto ci che il foglio
di lavoro contiene, anche dati che si trovassero in celle o zone che invece non interessano la stampa.
Premesso che la zona che Excel prevede come pagina in formato A4 copre dalla colonna A alla I
compresa, e gi fino alla riga 54 (con le impostazioni standard di larghezza colonne e altezza righe),
potremo usare diversi metodi per identificare l'area:
Usare i riferimenti alle celle (es.: Range("A1:I54") )
Se il foglio di lavoro contiene solo un elenco dati, anche lungo e su pi colonne (fino alla I), senza altre
celle occupate al di fuori dell'area che andr in stampa, potremo avvalerci dell' "UsedRange" che
comprender tutta l'area coperta da dati e quindi tutto l'elenco. (es.: ActiveSheet.UsedRange ).
O ancora fare ricorso alla propriet End applicata all'oggetto Range, che posta una cella iniziale,
trova l'ultima cella occupata, seguendo la direzione impostata dalla costante assegnata ad End
(xlDown, xlUp, xlToRight, xlToLeft). Dovremo solo avere l'accortezza di usare End con la colonna di cui
siamo certi esistano dati fino alla fine, senza celle vuote, altrimenti la selezione si fermerebbe alla prima
cella vuota. Es. con End impostata sulla colonna A :
ActiveSheet.Range(Cells(1, 1).End(xlDown), Cells(1, 9))
Ma vediamo la routine da usare per stampare, con in verde i commenti e le spiegazioni. Ricordo che le
righe precedute dall'apice (apostrofo) NON vengono lette, ma considerate "commenti" e potranno
essere tolte:
Sub miastampa()
'le tre istruzioni sotto per mostrare i tre tipi di selezione di area, la seconda (con
'UsedRange) quella attiva in quest'esempio
'Set zona = ActiveSheet.Range("$A$1:$I$54")
Set zona = ActiveSheet.UsedRange 'impostiamo con la variabile "zona" tutta l'area
dati
'Set zona = ActiveSheet.Range(Cells(1, 1), Cells(1, 9).End(xlDown))
'poich come PrintArea dobbiamo fornire i riferimenti alle celle che comprendono
l'area 'di "zona", e quindi gli indirizzi (Address), non i valori, usiamo "zona.Address")
ActiveSheet.PageSetup.PrintArea = zona.Address
With ActiveSheet.PageSetup 'adesso si impostano le propriet di PageSetup
'le tre righe con Header (Left, Center, Right) si riferiscono alle tre zone
dell'intestazione di 'pagina, in cui potremo scrivere ci che vorremo, il nome e
indirizzo di una ditta, una 'frase, o altro; nell'esempio uso solo la parte centrale
(CenterHeader), e tra doppi apici, 'ci che apparir in alto sul foglio stampato:
.LeftHeader = ""
.CenterHeader = "PIPPO DAMMI LA MELA"
.RightHeader = ""
'le tre righe sotto riguardano il "pi di pagina". Se non vogliamo usarlo, baster non
'scrivere niente tra i doppi apici
.LeftFooter = ""
http://ennius.interfree.it/ Pagina 218
MANUALE VBA X EXCEL
.CenterFooter = "DAMMI LA MELA PIPPO"
.RightFooter = ""
.PrintHeadings = False 'intestazioni di riga e colonna: con False non vengono
stampate
.PrintGridlines = False 'griglia: con false non viene stampata
.PrintComments = xlPrintNoComments 'commenti: non vengono stampati
.PrintQuality = 360 'il valore 360 imposta la qualit di stampa
.CenterHorizontally = False 'centraggio orizzontale: con False viene lasciato
l'allineamento 'tradizionale a sinistra nella pagina
.CenterVertically = False 'centraggio verticale.idem come sopra
.Orientation = xlPortrait 'cos stampa in verticale e con xlLandScape = orizzontale
.Draft = False 'per stampare anche i grafici: con false non li stampa
.PaperSize = xlPaperA4 'si imposta formato foglio A4
.FirstPageNumber = xlAutomatic 'numerazione automatica delle pagine
.Order = xlDownThenOver 'imposta l'ordine automatico utilizzato per numerare le
pagine
.BlackAndWhite = False 'impostata a False per consentire la stampa di event. font
'colorati. Impostata a True stamperebbe tutto in bianco e nero.
.Zoom = 100 'lo zoom consente di variare il fattore di ingrandimento o di riduzione di
'tutta l'area che andr in stampa. Riducendo il valore (100 di default) si pu far
'comprendere come PrintArea, una zona pi ampia (es.: una colonna che
diversamente 'non rientrando nel foglio A4, richiederebbe 2 fogli in stampa.
Ricordarsi di ripristinare il 'valore al default se si modifica, perch Excel lo memorizza
anche per stampe successive.
.PrintErrors = xlPrintErrorsDisplayed 'consente la visualizzazione di errori di stampa
End With
'ed ora si va in stampa: una copia, con l'opzione "fascicola" impostata a SI (true)
zona.PrintOut Copies:=1, Collate:=True
End Sub
Suggerisco ancora di imparare a leggere la guida in linea, che a volte ostica, ma con la stampa
offre veramente un valido aiuto.

http://ennius.interfree.it/ Pagina 219


MANUALE VBA X EXCEL
Realizzare la Tombola in Excel. (29/03/03)
Ogni tanto ci possiamo anche divertire, e coloro che dicono che il computer "isola" potranno rivedere
le proprie idee. Cosa c' di meglio che riunire la famiglia o degli amici per giocare alla vecchia, cara,
Tombola ? Con il computer verr gestito il "Tabellone" e curata l'estrazione dei numeri, cos nessuno
potr dire che "i numeri vengono scelti", sar infatti il vba di Excel a provvedere ad un'estrazione
completamente casuale.
Presento quindi una routine basata sulla randomizzazione ( ROUND() ) i cui concetti li ho presentati nel
paragrafo precedente in questa stessa sezione ("Estrarre dati casuali"). In questo esercizio era
necessario creare due gruppi di istruzioni : una routine che si occupasse di generare un numero
casuale compreso tra 1 e 90, ed un'altra che si occupasse di controllare, ed interrompere, uscendo,
quando tutti i 90 numeri fossero stati estratti. Ho pensato di semplificare le cose, preparando il tabellone
con gi inseriti tutti i 90 numeri, e di evidenziare il numero estratto in questo modo:
Colorare il numero in rosso
Rendere il Font in grassetto
Colorare la cella contenente il numero, evidenziandola in giallo.
Avvisare con un messaggio il numero estratto.
Avvisare con un messaggio quando il tabellone completo.
un immagine del Tabellone durante un'estrazione:

L'idea della realizzazione quindi si basa non sull'inserimento dei numeri estratti in una tabella, che ci
avrebbe costretto a memorizzare la posizione di ogni numero nella sua cella di competenza, e
successivo controllo della sua esistenza (del numero ) per casualizzare un nuovo numero nel caso fosse
gi "uscito" e successiva identificazione della relativa cella di appartenenza, ma, secondo me pi
semplice, al controllo se un numero sia gi evidenziato in rosso; in caso sia nero, leggo il valore (il
numero) presente nella cella, avviso col messaggio del numero cos estratto, e quindi lo coloro di
rosso, grassetto, fondo giallo alla cella; mentre per il ciclo di controllo dei numeri estratti, faccio
controllare se le celle sono evidenziate in giallo e faccio memorizzare il numero di queste celle se
presenti. Se il numero delle celle gialle uguale a 90 (tutti estratti), esco dalla routine e avviso. Per
meglio identificare l'area dove risiede la tabella, uso il classico riferimento ai Range di celle che
interessano.(A1:J9). Le istruzioni si commentano da sole, sono quelle gi ampliamente usate in tanti
esempi su questo sito. L'unica cosa che segnalo e che evidenzio, sono i posizionamenti dei cicli di
istruzioni e dei rimandi. Questa la macro:
Sub tombola()
Set zona = Range("A1:J9")
x = zona.Rows.Count
z = zona.Columns.Count

Dim CL As Object
Dim H As Integer
H=0
'indice riga 10
10:
'qui si controlla, memorizzando con H, quante celle sono di colore giallo; se H sar
uguale 'a 90 si avvisa con un messaggio che il tabellone completo e si esce dalla
routine, se 'invece H inferiore a 90, si salta all'indice riga 20 per ripetere il ciclo di
randomizzazione.
For Each CL In Range("A1:J9")

http://ennius.interfree.it/ Pagina 220


MANUALE VBA X EXCEL
If CL.Interior.ColorIndex = 6 Then
H=H+1
End If
If H = 90 Then
MsgBox "Tabellone Completo"
Exit Sub
Else
GoTo 20
End If
Next
'indice riga 20
20:
Randomize
quale = Int((x * Rnd) + 1)
dove = Int((z * Rnd) + 1)
Y = Cells(quale, dove).Value
miacella = Cells(quale, dove).Address
'sotto: si controlla il colore del font di "miacella"; se diverso da 3 (rosso) vuol dire che
non ' ancora uscito
If Range(miacella).Font.ColorIndex <> 3 Then
'si avvisa col numero (Y) estratto
MsgBox "Numero estratto il : " & Y & ""
' lo si colora di rosso, si rende grassetto, e si fa la cella gialla
With Range(miacella)
.Font.ColorIndex = 3
.Font.Bold = True
.Interior.ColorIndex = 6
End With

'se invece il colore font gi rosso, si ritorna al ciclo di randomizzazione per generare
un 'nuovo numero, recandosi all'indice riga 10
Else
GoTo 10

Exit Sub
End If

End Sub

Sar poi opportuno predisporre un'altra macro per ristabilire il colore dei numeri in nero, togliere il fondo
giallo alle celle, e togliere il grassetto ai font. Predisporremo un'altro pulsante con associata questa
routine:
Sub pulisci()
With Range("A1:J9")
.Interior.ColorIndex = xlNone
.Font.ColorIndex = 1
.Font.Bold = False
End With
End Sub

File scaricabile e consultabile : La Tombola.zip 10 Kb

http://ennius.interfree.it/ Pagina 221


MANUALE VBA X EXCEL
Le ComboBox e le proprier LinkedCell e ListFillRange
Quando si usano le ComboBox (casella combinata) (prese da Casella degli strumenti o Strumenti di
controllo), inevitabile avere a che fare con le "propriet" riportate nel titolo. Ricordo che per
"LinkedCell" si intende il riferimento alla cella del foglio di lavoro, nella quale far corrispondere il valore
selezionato nel men a discesa della combobox stessa, per "ListFillRange" invece si intende il riferimento
al range di celle della colonna che conterr i dati da visualizzare nella combobox. Questi riferimenti
possono venir scritti direttamente nella finestra delle propriet della combobox, oppure inserirli in
eventi, come ad esempio l'apertura del foglio di lavoro nel quale risiede la combobox, tipo :
Private Sub Worksheet_Activate()
ComboBox1.LinkedCell = ("A1")
ComboBox1.ListFillRange = ("C1:C50")
End Sub
In questo modo possibile pilotare, su una stessa combobox, sia la cella di destinazione, sia il range di
provenienza dati, come potrebbe accadere se avessimo vari elenchi da caricare a secondo il tipo di
dati da gestire. Sempre per fare un esempio, potremmo avere sul foglio di lavoro dove c' la
combobox, un elenco di nomi in C1:C50, e sul foglio2 un elenco di citt, o numeri, o colori, o codici, o
quel che vi pare, e che si voglia alternativamente, selezionare i dati presi dai due diversi elenchi.
Procederemo cos.
lasceremo la routine all'apertura del foglio.
inseriremo un CommandButton (sempre da casella degli strumenti) e nella propriet Caption
scriveremo l'identificativo, del tipo: Elenco A, indi nell'evento Click del CmdButton scriveremo:
PrivateSub CommandButton1_Click()
ComboBox1.LinkedCell = ("A1")
ComboBox1.ListFillRange = ("C1:C50")
End Sub
inseriremo un secondo CommandButton (sempre da casella degli strumenti) e nella propriet Caption
scriveremo l'identificativo, del tipo: Elenco B, indi nell'evento Click del CmdButton scriveremo:
PrivateSub CommandButton2_Click()
ComboBox1.LinkedCell = ("A1")
ComboBox1.ListFillRange = ("Foglio2!D1:D50")
End Sub
In questo modo avremo: all'apertura del foglio1, il caricamento dei dati presenti su foglio1 da C1 a
C50, premendo il pulsante 2 il caricamento dei dati provenienti dal foglio 2 da D1 a D50. Il Pulsante 1
servir a ripristinare l'elenco originario (altrimenti avremmo dovuto provocare l'"Activate" del foglio1,
selezionando un altro foglio per poi ritornare al foglio 1). Avremmo anche potuto indicare una diversa
cella di destinazione (linkedCell) se fosse stato necessario. Ma per ci che descrivo di seguito, lasciamo
la LinkedCell invariata.
Il motivo di queste note, scaturito da una domanda rivoltami, che chiedeva come si poteva fare ad
avere la LinkedCell, non fissa, ma variabile, collegata ad una cella, in quel momento attiva
(ActiveCell). Ora, questo non possibile perch anche se selezioniamo una cella qualsiasi ( diventa
ActiveCell), nel momento che andiamo a selezionare la combobox per scegliere il dato che ci
interessa, TOGLIAMO il focus dalla cella in quel momento attiva per spostarlo sulla combobox, e quindi
"addio" alla cella attiva. Un'istruzione del tipo : ComboBox1.LinkedCell = ActiveCell non avrebbe quindi
senso.
Tra le varie soluzioni possibili, la pi indicata, mi sembra questa: definire quindi una LinkedCell fissa, e
modificare invece la destinazione del valore presente in questa cella, usando il copia/incolla con
destinazione su una cella attiva; risolviamo cos il quesito postomi, con una semplice macro associata
ad un pulsante. Selezioneremo PRIMA il dato voluto nella combobox, selezioniamo poi la cella di
destinazione, e clicchiamo sul pulsante attivando questa macro
Sub Scopiazza()
Range("E1").Copy 'copia il contenuto di E1, la LinkedCell
With ActiveCell 'con la cella in quel momemto attiva, incolla
Selection.PasteSpecial Paste:=xlValues, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=False
End With
Application.CutCopyMode = False
End Sub

http://ennius.interfree.it/ Pagina 222


MANUALE VBA X EXCEL
E nella cella precedentemente selezionata otterremo il dato voluto.
Su alcune versioni precedenti, per non mi ricordo, pu essere necessario variare l'istruzione relativa
all'identificazione della cella attiva; queste sotto sono tutte equivalenti, eventualmente trovate la
vostra.
ActiveCell
Application.ActiveCell
ActiveWindow.ActiveCell
Application.ActiveWindow.ActiveCell

http://ennius.interfree.it/ Pagina 223


MANUALE VBA X EXCEL
Lo Scrolling. (15/06/03)
Con il termine Scroll si identifica un metodo che genera l'evento di spostare un oggetto a video.
Parliamo del Foglio di lavoro con le sue righe e colonne, e dell'azione che compiamo quando agiamo
sulle barre di scorrimento verticale e/o orizzontale. Operazione frequentissima che tutti noi eseguiamo
per raggiungere determinate zone dati del nostro foglio di lavoro. L'argomento Scroll piuttosto ampio,
ma ci occuperemo solo di alcuni comandi che tramite vba, ci consentono scorrimenti sul foglio di
lavoro. L'oggetto predefinito di cui lo Scroll fa parte, l'oggetto Window (finestra). Ricordo solo che i
nostri fogli possiedono un indice riga (il numero che vediamo all'estrema sinistra, da 1 a 65536) ed un
indice colonna (da 1 a 256) e che di default viene visualizzato con lettere dell'alfabeto: la A la
colonna numero 1, la B la numero 2, ecc.ecc.
SmallScroll - Esegue uno scorrimento per righe o per colonne. Nell'istruzione basta indicare il numero
di righe di cui vogliamo spostarci ogni volta. Questo esempio fa scorrere il contenuto della finestra
attiva di Foglio1 di tre righe verso il basso (down). Gi altri argomenti per la direzione in cui spostarsi sono:
Up (verso l'alto), ToRight (verso destra), ToLeft (verso sinistra). Nessuno di questi argomenti pu essere
rappresentato da un numero negativo.

Worksheets("Foglio1").Activate
ActiveWindow.SmallScroll down:=3
LargeScroll - Esegue uno scorrimento per pagine. Le direzioni per spostarsi sono uguali a SmallScroll.
(per pagina si intende il formato di una pagina A4, corrispondente in visualizzazione standard 800x600 e
con altezza righe di default, a circa 63 rige). Anche in questo caso un numero identificher di quante
pagine ci vorremo spostare. Questo esempio fa scorrere il contenuto della finestra attiva di Foglio1 di
tre pagine verso il basso.

Worksheets("Foglio1").Activate
ActiveWindow.LargeScroll down:=3
Ma i metodi su cui voglio puntare l'attenzione sono due: ScrollColumn e ScrollRow - entrambi eseguono
uno scorrimento per colonna o per riga, indicando il relativo numero, e posizionando la colonna o la
riga chiamata nell'angolo superiore sinistro del foglio di lavoro, cio all'inizio foglio. Questo ci consente
di portare in primo piano una zona del foglio di lavoro, per poterci lavorare o consultarla. Questa
pratica ci consente di disporre sullo stesso foglio, pi tabelle oppure pi zone di calcolo, con il
vantaggio di non ricorrere ad altri fogli per i riferimenti alle varie celle o zone, con il beneficio che
eviteremo malintesi nelle istruzioni oltre a scrivere di meno, in quanto lavorando sullo stesso foglio,
baster il semplice riferimento alla cella o ad una zona (identificate anche tramite l'assegnazione di un
nome) perch Excel capisca che si sta parlando di cella o zona dello stesso foglio, ed esegua. Ma
vediamo le due propriet :
ScrollColumn - Restituisce o imposta il numero della colonna pi a sinistra nel riquadro o nella finestra..
Cio il numero (indice) della cella chiamata verr posizionato in alto a sinistra (dove di solito vediamo
la cella A1). Se la finestra divisa, la propriet ScrollColumn dell'oggetto Window si riferisce al riquadro
superiore sinistro. Se i riquadri sono bloccati, la propriet ScrollColumn dell'oggetto Window esclude le
aree bloccate. Questo esempio sposta la colonna 3 ( la C ) in modo da essere quella pi a sinistra
nella finestra.

Worksheets("Foglio1").Activate
ActiveWindow.ScrollColumn = 3
ScrollRow - Restituisce o imposta il numero della riga che viene visualizzata nella parte superiore del
riquadro o della finestra. Cio il numero (indice) della riga chiamata verr posizionato al limite
superiore del foglio (dove di solito sta la riga 1). Se la finestra divisa, la propriet ScrollRow
dell'oggetto Window si riferisce al riquadro superiore sinistro. Se i riquadri sono bloccati, la propriet
ScrollRow dell'oggetto Window esclude le aree bloccate. Questo esempio sposta la riga 10 nella parte
superiore della finestra.

Worksheets("Foglio1").Activate
ActiveWindow.ScrollRow = 10
Appare evidente, almeno lo spero, che usando entrambe queste due ultime propriet nella stessa
istruzione, potremo portare in primo piano tabelle poste in aree del foglio che di solito non usiamo. In
questo esempio sotto, posizioniamo nell'angolo superiore sinistro (al posto della A1) la cella Q115 che
sar la cella di inizio di una tabella (per esempio) di dati:
http://ennius.interfree.it/ Pagina 224
MANUALE VBA X EXCEL
Worksheets("Foglio1").Activate
ActiveWindow.ScrollRow = 115
ActiveWindow.ScrollColumn = 17
In realt, trovandoci sullo stesso foglio (per i pi attenti le istruzioni viste ci consentono di "mirare" a
qualunque zona di qualunque foglio nella nostra cartella, basta cambiare il numero del foglio), non
sar necessario scrivere la prima riga dell'istruzione, e come scritta sotto andr bene lo stesso:
ActiveWindow.ScrollRow = 115
ActiveWindow.ScrollColumn = 17
Come usare queste istruzioni ? Suggerisco di usare "Blocca riquadri" (dal men Finestra/Bocca riquadri)
e di bloccare le prime 2 o tre righe; in questa zona che rester fissa a schermo, inseriremo tanti pulsanti
collegati ad altrettante macro, ognuna destinata ad una determinata zona, pi una, importante, per
ritornare all'ovile, cio alla cella di inizio foglio.
Se riterrete utile, potrete scaricare questo file, che ho iniziato, ma non completato, per la gestione di
Corsi Nuoto. L'unico foglio semi completo riguarda i turni del "Nuoto Ragazzi". Chi vorr potr portarlo
avanti o modificarlo, sono presenti comunque numerose routine che aiuteranno a capire, compreso
un ciclo che evidenzia gli "scaduti" se la data odierna del giorno superiore alla data di fine corso e la
cella "prezzo" non contiene valori.(pulsante "check"). Sotto due immagini:

file consultabile e scaricabile : Generale corsi.zip 83 Kb

http://ennius.interfree.it/ Pagina 225


MANUALE VBA X EXCEL
Rendere Maiuscola la prima lettera di una parola. (30/05/03)
Un semplice esercizio per impostare maiuscola la prima lettera di una parola inserita in una cella. Al di
l di focalizzare a quale evento associare le istruzioni (che ognuno potr decidere per le proprie
esigenze), mi limito alla creazione di una macro da associare ad un pulsante. Sar possibile intervenire
su celle specifiche, o su un'intero range di celle. Seguiamo questo esempio: per prima cosa
identificheremo la zona su cui intervenire (con UsedRange), poi controlleremo che ogni cella della
zona non sia vuota o non contenga numeri, se conterr del testo, estraiamo la prima lettera della
parola nella cella (con Mid) e gli applichiamo la maiuscola (con UCase), a questa prima lettera
aggiungiamo il resto della parola (seconda istruzione Mid) che verr resa tutta minuscola (con LCase).
Queste le istruzioni:
Sub Maiuscola()
Dim C As Object
Set zona = ActiveSheet.UsedRange
For Each C In zona
If C <> "" And IsNumeric(C) = False Then
C = UCase(Mid(C, 1, 1)) + LCase(Mid(C, 2))
End If
Next
End Sub
Per l'attivazione in automatico, potremo scegliere per esempio, l'evento Worksheet_Change anzich
affidarci ad un pulsante, cos che ad ogni cambiamento in una cella, o aggiunta, scatti la routine.
Se invece vorremo lavorare su una cella specifica, questa sar un'istruzione (A1 come esempio):
Range("A1") = UCase(Mid(Range("A1"), 1, 1)) + LCase(Mid(Range("A1"), 2))

Buon lavoro.

http://ennius.interfree.it/ Pagina 226


MANUALE VBA X EXCEL
Le Funzioni /Istruzioni MID, RIGHT, LEFT
Quando si lavora con il vba, e si ha bisogno di identificare o selezionare una parte di un dato numerico
o alfanumerico o testo, esistono delle procedure che utilizzando comandi appropriati ci consentono di
ottenere ci che vogliamo. Le tre funzioni/istruzioni argomento di questa pagina, appartengono a
questo tipo di comandi. Cerchiamo di capire meglio cosa si intende per "identificare o selezionare",
con un esempio: supponiamo di volere controllare ci che scriveremo in una casella di testo (TextBox)
in modo da non registrare dati non pertinenti, come un numero negativo se non vogliamo numeri
negativi o una data scritta non nel formato desiderato se decidiamo di adottare il formato classico
rappresentato da gg/mm/aa (giorno a due cifre, barra,mese a due cifre, barra, anno a due cifre);
bene, potremo adoperare la funzione MID. Sono esempi in cui appare evidente la posizione dei
caratteri all'interno della "stringa" che dovremo controllare: nel caso di un numero negativo, il numero
appare con il segno meno (-) davanti, cio il primo carattere che compone la stringa di numeri (-
10234). Nel caso del controllo del formato data avremo nella stringa che forma la data stessa, la prima
e seconda posizione occupate da numeri, la prima barra sar nella terza posizione, poi quarta e
quinta posizione ancora due numeri, sesta posizione una barra, e infine in settima e ottava posizione
altri due numeri (01/10/02) . Perch parliamo di posizione? perch la funzione MID lavora appunto
intercettando la posizione che gli chiederemo di controllare all'interno della stringa dati. Vediamo
intanto la sintassi:
Sintassi

Mid(varstringa, inizio[, lunghezza]) = stringa

La sintassi dell'istruzione Mid composta dalle seguenti parti:


Parte Descrizione

varstringa Obbligatoria. Nome della variabile stringa da modificare o


controllare.

inizio Obbligatoria. Variant (Long). Posizione di un carattere in varstringa


dalla quale inizia la sostituzione del testo.

lunghezza Facoltativa. Variant (Long). Numero di caratteri da sostituire. Se


omesso, viene utilizzata l'intera espressione stringa.

stringa Obbligatoria. Espressione stringa che sostituisce parte di varstringa


Per evitare confusioni, visto la tabella sopra, preciso che l'esempio di cui ci occupiamo
l'intercettazione di un determinato carattere, e NON la sua sostituzione con un altro, cosa peraltro
possibile dato che la funzione lavora anche in questo senso. Vediamo quindi di trasformare la sintassi in
un esempio, e relativa spiegazione, questa l'istruzione compilata:
If Mid(TextBox1, 1, 1) = "-" Then.......
questa l'impostazione sintattica : Se Mid(varstringa il contenuto di TextBox1, a partire dal primo
carattere 1, e per la lunghezza di 1 carattere, cio lo stesso primo carattere) uguale al segno meno,
allora........ Infatti un numero negativo che porta in prima posizione il segno meno verrebbe riconosciuto
e verrebbe eseguita l'istruzione seguente a Then.
ora l'esempio con la data, in questo caso dovremo adoperare la concatenazione di due istruzioni Mid
per eseguire il controllo di tutta una stringa, perch andremo a controllare la presenza delle due barre :
if Mid(TextBox1, 3, 1) + Mid(TextBox1, 6, 1) <> "/" Then.....
questa l'impostazione sintattica : Se Mid(varstringa il contenuto di TextBox1, a partire dal terzo
carattere, e per la lunghezza di 1 carattere, cio lo stesso terzo carattere) e (+) Mid(varstringa il
contenuto di TextBox1, a partire dal sesto carattere, e per la lunghezza di 1 carattere, cio lo stesso
sesto carattere) sono diversi (<>)dalla barra ( / ), allora...... Se la data quindi sar scritta nel giusto
formato scelto 09/08/01, le barre si troveranno al posto giusto (terza e sesta posizione) e non succeder
niente, in caso contrario, il codice eseguir l'istruzione prevista dopo Then. Da notare che il controllo
sulle barre, controlla incidentalmente tutta la data se infatti avessimo scritto 9/08/01 oppure 09/ago/01
oppure 09-08-01 sarebbe scattato il controllo perch le barre non sarebbero state intercettate nelle
posizioni previste delle istruzioni Mid (ma al secondo e quinto posto per 9/08/01, e al terzo ma al settimo
posto per 09/ago/01, e i trattini al posto delle barre). In realt questo controllo non completo,
perch una data scritta 09/08/2001 verrebbe ritenuta valida in quanto le barre si trovano al posto
http://ennius.interfree.it/ Pagina 227
MANUALE VBA X EXCEL
giusto, ma l'anno stato scritto a 4 cifre anzich due. Ma vediamo dopo, quando si parler delle
Funzioni Left e Right, come completare questo controllo.
Un altro esempio, potrebbe essere quello di estrarre da una data, solo il giorno, o il mese, o l'anno;
vediamo le tre istruzioni in sequenza
X = Mid(TextBox1, 1 , 2) (X sarebbe quindi uguale a 09, cio il contenuto della textbox1, a partire dalla
prima posizione e lungo 2 valori)
X = Mid(TextBox1, 4 , 2) (X sarebbe quindi uguale a 08, cio il contenuto della textbox1, a partire dalla
quarta posizione e lungo 2 valori)
X = Mid(TextBox1, 7 , 2) (X sarebbe quindi uguale a 01, cio il contenuto della textbox1, a partire dalla
settima posizione e lungo 2 valori)
Ancora un esempio, relativo questa volta all'estrazione di un nome da una stringa nella quale almeno
un dato sia di lunghezza costante, per esempio la parola totale seguita da un altro nome totale Gino,
totale dollari, totale euro, totale mensile, ecc. In un caso del genere sarebbe utile usare anche
l'istruzione TRIM, ma ne parliamo un altra volta, diamo per scontato che dopo la parola totale
inseriremo uno spazio, il che porta la nostra istruzione MID a intercettare tutto ci che sar dalla settima
posizione in poi (6 lettere totale pi una dello spazio fanno sette, e noi vogliamo ci che sta dopo,
quindi a partire dalla ottava posizione; siccome non sappiamo quanto sar lunga la parola che segue,
useremo l'istruzione MID senza fornire il parametro della lunghezza (non obbligatorio) e in questo caso
verr rilevato tutto ci che sar dalla ottava posizione in poi senza tenere conto di quanto lungo.
Queste le istruzioni (se nella TextBox1 avremo "totale Gino"):
X = Mid(TextBox1, 8) e X sar uguale a Gino, oppure
X = Mid ("totale dollaro", 8) e X sar uguale a dollaro
Anche se non pertinente all'argomento visto con l'ottica di questi esempi, necessario conoscere
l'utilizzo dell'istruzione MID come funzione per SOSTITUIRE una parola in una stringa di dati. In questi
esempi l'istruzione MID viene utilizzata per sostituire un numero specificato di caratteri in una variabile
stringa con i caratteri di un'altra stringa.

Dim MiaStringa
MiaStringa = "Il gatto salta" ' Inizializza la stringa.. Per capire meglio, assegniamo sotto le posizioni dei
caratteri nella stringa
1 2 3 4 5 6 7 8 9 10 11 12 13 14
I L G A T T O S A L T A
nell'esempio sotto diciamo di sostituire nella stringa, a partire dalla quarta posizione e per la lunghezza
di 5 caratteri, il contenuto con le stesse coordinate della stringa, con la parola pesce
Mid(MiaStringa, 4, 5) = "pesce" ' il risultato sar MiaStringa = "Il pesce salta".
sotto invece diciamo di sostituire nella stringa, a partire dalla quarta posizione e senza indicare la
lunghezza, il contenuto della stringa a partire dalla quarta posizione con la parola tonno
Mid(MiaStringa, 4) = "tonno" ' il risultato sar MiaStringa = "Il tonno salta".
sotto ancora sostituiremo praticamente tutta la stringa in quanto le lunghezze delle parole da sostituire
sono identiche
Mid(MiaStringa, 4) = "leone dorme" ' il risultato sar MiaStringa = "Il leone dorme".
sarebbe diversa se la sostituzione fosse con parole di lunghezza diversa
Mid(MiaStringa, 4) = "leone dor" ' il risultato sar MiaStringa = "Il leone dorta". (dor di dorme e ta di salta)
------------------------------------------------
Le Funzioni LEFT e RIGHT
Anche queste due funzioni possono essere usate per controllare se in una determinata stringa esistono
dei valori che dovranno corrispondere alle nostre bisogne. Entrambe le funzioni lavorano intercettando
a SINISTRA (LEFT) o a DESTRA (RIGHT) della nostra stringa, un certo numero di caratteri rappresentati dal
numero che inseriamo nell'istruzione. Vediamo intanto la sintassi che simile per tutte e due:
Sintassi
Left(string, length)
La sintassi della funzione Left composta dai seguenti argomenti predefiniti:
Parte Descrizione

string Obbligatoria. Espressione stringa dalla quale vengono restituiti i


caratteri situati all'estrema sinistra. Se string contiene Null verr
restituito Null.

http://ennius.interfree.it/ Pagina 228


MANUALE VBA X EXCEL
length Obbligatoria. Variant (Long). Espressione numerica che indica
quanti caratteri devono essere restituiti. Se 0, verr restituita una
stringa di lunghezza zero (""). Se maggiore o uguale al numero
di caratteri presenti in string, verr restituita l'intera stringa.
Esemplificando: mettiamo la parola "ciccione" nella textbox1
X = Left(TextBox1, 2) 'ci restituisce le prime due lettere della parola "ciccione" a partire da sinistra, X sar
uguale a "ci"
X = Right(TextBox1, 2) 'ci restituisce le prime due lettere della parola "ciccione" a partire da destra, X
sar uguale a "ne"
Riprendendo quindi l'esempio pi sopra, dove volevamo controllare il formato data, sar ora possibile
controllare non solo la presenza delle barre, ma anche che l'anno sia inserito con 2 cifre e non quattro.
Vediamo le istruzioni sulla data 05/10/02:
Dim X
X = Right(TextBox1, 2) 'impostiamo a due valori la variabile X (saranno le ultime due cifre nella textbox1,
o se preferite, le prime due cifre partendo da destra)
ora controlliamo se la prima barra della data (05/ - terza posizione, un carattere solo, quindi la / ) con
la funzione MID, giusta, indi inseriamo il controllo per verificare che la seconda barra si trovi nella
terza posizione a partire da destra ( /02 ) con la funzione RIGHT, inserendo l'operatore OR tra le due
funzioni
If Mid(TextBox1, 3, 1) <> "/" Or Right(TextBox1, 3) <> "/" & X Then.....
Se il terzo carattere della stringa (MID) diverso da una barra "/" oppure il terzo carattere da destra
(RIGHT) diverso da una barra "/" allora....(per ottenere che il terzo carattere da destra sia una barra
abbiamo concatenato il simbolo della barra alla X che ora contiene due caratteri : in totale 3 e quindi
terza posizione, non importa quali saranno i due caratteri contenuti nella X. Se avessimo scritto /2002, il
terzo carattere da destra sarebbe stato 0 e quindi diverso da /, e l'istruzione avrebbe intercettato
l'errore avviando l'istruzione seguente a Then).
Variando le posizioni nelle istruzioni, sar possibile ottenere il formato data che preferiamo: se per
esempio vogliamo una data scritta 05-10-02, oppure 05-ott-02 sar sufficiente cambiare il simbolo
nell'istruzione:
If Mid(TextBox1, 3, 1) <> "-" Or Right(TextBox1, 3) <> "-" & X Then.....
se invece vorremo come sopra ma con l'anno a quattro cifre 05-ott-2002, questa l'istruzione:
Dim X
X = Right(TextBox1, 4)
If Mid(TextBox1, 3, 1) <> "-" Or Right(TextBox1, 5) <> "-" & X Then.....

http://ennius.interfree.it/ Pagina 229


MANUALE VBA X EXCEL
Misurare il tempo di esecuzione di una routine (o macro).
Autore: Michele email : mic1947@libero.it
Spesso, quando si eseguono cicli di ricerche su elenchi piuttosto lunghi, pu incuriosire sapere quanto
tempo impiega la nostra routine ad eseguire il ciclo, ma potremmo anche voler sapere quanto tempo
abbiamo lavorato sul nostro foglio di lavoro.
Ecco un'idea interessante sviluppata da Michele: misurare il tempo di esecuzione di una macro
sfruttando due variabili , ma, leggermene modificata, pu essere usata anche per misurare il tempo
che si lavorato sui fogli di lavoro. Il concetto semplice: assegnare il tempo ad una variabile, in
apertura macro o applicazione, e poi assegnare ad una seconda variabile il tempo in cui termina la
macro o l'applicazione: la differenza tra i due orari dar il tempo totale di esecuzione. Vediamo il primo
esempio, controllare il tempo di esecuzione di una macro, ottenendo un messaggio che riporta il
tempo trascorso:
le istruzioni andranno poste ad inizio routine, subito dopo il nome della macro, e alla fine,
immediatamente prima di End Sub, es.:
Sub tuaroutine()
Dim D1, D2 As Date 'dichiarazione variabili come tipo di Date/Time per D1 e D2
Dim tempoimpiegato As String ' tempoimpiegato una stringa
D1 = Time ' assegnazione a D1 del tempo in apertura (avvio) macro
....seguono le istruzioni della macro, e alla fine:
D2 = Time 'assegnazione a D2 del tempo in chiusura (termine) macro
tempoimpiegato = Format(D2 - D1, "hh:mm:ss") ' Assegnazione a tempoimpiegato della differenza tra
D2 e 'D1 e formattazione nel formato ora-minuti-secondi
MsgBox "Tempo impiegato: " & tempoimpiegato ' messaggio finale del tempo trascorso
End Sub
E ci divertiremo o preoccuperemo nel sapere quanto tempo occorso per eseguire il nostro controllo.
A parte le battute, pu essere invece un sistema valido per il programmatore affinch verifichi i tempi
di esecuzione delle istruzioni.
Un p diverso risulta l'utilizzo delle due istruzioni per controllare quanto tempo si lavorato sulla cartella.
Avremo bisogno che le variabili impiegate (B1, B2, tempototale) siano e restino "visibili" su tutto
"l'oggetto" (WorkBook) da noi scelto, e quindi dovremo adoperare la zona "Generale" e "Dichiarazioni"
per avvisare con Option Explicit la visibilit a livello globale di "oggetto" delle variabili che
dimensioneremo in questa zona. (le Variabili usate all'interno di una routine/macro o evento, restano
attive solo all'interno della routine/macro o evento stesso e non disponibili in altre macro o eventi).
Ma vediamo un esempio per il controllo del tempo passato su una cartella di lavoro; sfrutteremo oltre a
" Generale -Dichiarazioni del WorkBook, anche il WorkBook_Open per inizializzare il tempo in apertura
del foglio, e il WorkBook_BeforeClose che avviene quando si chiude la cartella di lavoro, per stoppare il
tempo ed avere il totale del tempo impiegato;

Se invece vogliamo controllare quanto tempo abbiamo lavorato su un solo foglio di lavoro, dovremo
usare la stessa tecnica della "visibilit", ma utilizzando l'oggetto WorkSheet sfruttando, oltre a Generale
- Dichiarazioni del WorkSheet, l'evento Activate per attivare il tempo di apertura foglio, e l'evento
Deactivate per stoppare il tempo ed avere il tempo di lavoro. Tenete presente che l'evento Activate
NON si genera quando si apre la cartella di lavoro che si apre sul Foglio1, ma solo se da un'altro foglio
si va sul Foglio1. Un sistema : salvare la cartella dopo aver selezionato il foglio2 in modo che quando
la si riapre ci troveremo sul foglio2, selezionando il foglio1 per iniziare a lavorare, attiveremo l'evento
Activate. Questo l'esempio per il foglio di lavoro:
http://ennius.interfree.it/ Pagina 230
MANUALE VBA X EXCEL
Option Explicit '( in "Generale - Dichiarazioni" del WorkSheet )
Dim C1, C2 As Date
Dim tempototalefoglio As String
____________________________________________
Private Sub Worksheet_Deactivate()
C2 = Time
tempototalefoglio = Format(C2 - C1, "hh:mm:ss")
MsgBox "Tempo impiegato: " & tempototalefoglio
End Sub
____________________________________________
Private Sub Worksheet_Activate()
C1 = Time
End Sub

http://ennius.interfree.it/ Pagina 231


MANUALE VBA X EXCEL
Gli spazi vuoti tra i nomi visti dal VisualBasic. (04/04/03)

Presento una soluzione non documentata (non ho ancora mai trovato spiegazioni sull'argomento) di
come affrontare il problema di nomi con spazi vuoti in vba in istruzioni per la ricerca o apertura di file
e/o cartelle.
Sappiamo, quando siamo su un foglio di lavoro, che se vogliamo indicare che se una cella vuota
(non contiene dati) in una formula possiamo usare due doppi apici : "". Lo stesso facciamo in vba
quando in una routine vogliamo indicare, per esempio per una casella di testo di una UserForm, che se
la casella di testo vuota....ed usiamo tranquillamente l'istruzione If TextBox1 = "".....ed il vba riconosce
l'istruzione e non si lamenta. Sappiamo anche che se vogliamo indicare il "vuoto" (come assenza di
dati) relativo ad una cella, ma in una formula o funzione usata in una macro ( e quindi vba ) il codice
pretende che nella formula al posto dei due doppi apici indicanti il "vuoto", se ne inseriscano quattro:
"""", uno di seguito all'altro. Questo significa che il codice riconosce anche i quattro apici come "vuoto".
Si portati quindi a ritenere che i quattro apici siano una regola. Ma non sempre cos. Infatti, usando
istruzioni in vba, in cui si voglia aprire una cartella o un file i cui nomi sono rappresentati da parole con
spazi tra una parola ed un'altra, come ad esempio una cartella che sia sul C:\ e che si chiami Cosa
Vuoi ed un file ivi contenuto che si chiama Pippo 1999.doc, oppure caso pi frequente, rintracciare un
file all'interno della cartella di sistema di Windows XP, Documents and Settings , diventa impossibile
raggiungere il file sia che si scriva "C:\Cosa Vuoi\Pippo 1999.doc" (o anche "C:\Documents and
Settings\NomeUtente\Pippo 1999.doc") oppure si scriva usando i quattro doppi apici, presunti risolutori,
cos: "C:\Cosa""""Vuoi\Pippo""""1999.doc" ( o anche
"C:\Documents""""and""""Settings\NomeUtente\Pippo""""1999.doc" ). Non approderemo a niente se non
ricorriamo ad una sottigliezza : l'inserimento di uno spazio vuoto, nell'istruzione, tra i due doppi apici
centrali dei quattro, cos : "" "" (due doppi apici - spazio - altri due doppi apici)
In questo modo il nome verr riconosciuto e l'istruzione eseguita. Se quindi avessimo voluto leggere il
contenuto del file Pippo 1999.doc, avremmo potuto usare la Shell per aprire Word e il relativo
documento, e l'istruzione sarebbe quindi:
Shell("WinWord.exe "C:\Cosa"" ""Vuoi\Pippo"" ""1999.doc"), 1

Buon lavoro.

http://ennius.interfree.it/ Pagina 232


MANUALE VBA X EXCEL
Numerazione automatica di un documento. (28/05/03)
Ovvero: come generare un numeratore automatico (altrimenti chiamato : contatore)
Anche se abbiamo gi visto come ottenere un contatore in procedure presenti in questa sezione,
continuano a pervenirmi richieste sullo specifico, per cui provo a dedicare una pagina a questo
argomento.
Diciamo subito che un'operazione semplice e che comunque si basa su un "serbatoio" dove esiste un
numero (una cella), che a seguito di un "evento" facciamo incrementare di una unit. Per questa
operazione useremo istruzioni in codice vba, non volendoci affidare a uguaglianze o formule tipiche
del foglio di lavoro, che genererebbero "Riferimenti circolari" e quindi errori.
Molti sono i modi di operare, dipendono da noi e da come impostiamo il nostro lavoro, e quindi
prenderemo in esame alcuni esempi, che potranno servire per chiarire i concetti di base. Gli esempi
prendono tutti in esame la compilazione di una fattura nella quale, ad ogni nuova fattura, dovremo
assegnare un numero successivo all'ultimo usato. Useremo quindi una cella che conterr il numero
fattura, esempio la F10.
La F10 sar quindi il nostro "serbatoio", che potr essere utilizzato anche se all'inizio sar vuoto, o se
proprio vogliamo, inseriremo il valore zero (0).
L'incremento lo otteniamo con questa semplice istruzione:
Range("F10") = Range("F10").Value + 1
cio : il valore che si trova il F10 sar uguale allo stesso valore pi uno. Ed Excel esegue docile, se F10
era vuoto, dopo questa istruzione sar 1, se era 22, diventer 23, e cos via.
Stabilita l'istruzione, dobbiamo decidere quale evento scegliere per lanciarla. Vediamone alcuni:
Creare una macro da associare ad un pulsante che nomineremo ad esempio :"Numero Fattura". In
questo caso ad ogni pressione sul pulsante, incrementiamo il numero. In questo modo per possiamo
dimenticarci di premere il pulsante, e quando registreremo la fattura, la registriamo con un numero
che esister gi. Conviene affidarci ad un sistema che automatizzi l'istruzione sopra citata, evitandoci
errori dovuti a dimenticanze. Potremmo sfruttare eventi collegati all'apertura o all'attivazione del foglio
di lavoro dedicato alla compilazione del documento, ma non va bene perch se apriamo il foglio per
sola consultazione, facciamo scattare il contatore incrementando il numero quando invece non lo
vogliamo. Potremmo sfruttare l'evento Worksheet_Change, nel quale potremmo inserire una
condizione, cio se la cella che porter il nome del cliente sar diverso da vuoto, allora
incrementiamo il contatore. Ma non va bene neanche questa soluzione perch se avremo sbagliato
cliente, cancelliamo il nome e ne scriviamo un'altro, si incrementa di nuovo il contatore. Allora?
Sicuramente, in ogni progetto degno di tale nome, avremo previsto un pulsante associato ad una
macro con le istruzioni per la registrazione, in un foglio chiamato "Archivio", dei dati riguardanti la
fattura compilata: bene, inseriremo l'istruzione sopra citata ad inizio macro, prima delle istruzioni di
registrazione. In questo modo, prima che inizino le registrazioni avremo il nostro contatore incrementato
col giusto valore, che verr registrato insieme agli altri dati.
In genere, nei progetti ben congegnati, solo dopo che avvenuta la registrazione, che passeremo
alla stampa del documento. Anche in questo caso la stampa che otterremo riporter il giusto numero
di fattura.
Potremo a questo punto avere previsto un pulsante per il salvataggio di una copia della fattura
(sfruttando le istruzioni contenute nel paragrafo precedente "Salvare una Fattura").
Un accorgimento poi sar quello di NON cancellare il dato nella cella numeratore quando a fine
registrazione e successiva stampa e/o salvataggio copia, faremo pulire le celle (con ClearContents)
con l'apposita macro che avremo creato, per predisporre il foglio ad una nuova fattura. Poco importa
se nella cella del numero fattura vediamo il numero della fattura precedente, sappiamo che si
incrementer quando premeremo il pulsante "Registra fattura".
A fine lavoro, non ci dovremo mai scordare di salvare la cartella, oppure predisporre le istruzioni per il
salvataggio in automatico della cartella.
Esistono, come gi detto, parecchi sistemi per creare un incremento nel numero fattura, compreso
quello di andarsi a leggere nel foglio "Archivio" l'ultimo numero registrato, ed incrementarlo di 1, ma
dovremo comunque scegliere l'evento giusto perch questo avvenga. Credo di avere un p chiarito
questi semplici concetti. Queste informazioni sono sfruttabili su schemi fattura autocostruiti e non sui
"Modelli" che peraltro non uso e non ho mai usato.

http://ennius.interfree.it/ Pagina 233


MANUALE VBA X EXCEL
Conversione di Numeri in Lettere (senza decimali)
Conversione di Numeri in Lettere (con decimali)
Conversione di Numeri in Lettere (senza decimali):
Questa routine, perfettamente funzionante, stata realizzata da Marco Nocciolini (basta copiare la/le
routine ed incollare in un modulo o in un evento dl foglio di lavoro)
marco.nocciolini@tin.it
E' possibile modificare le celle usate nell'esempio (B6 per la cella che contiene il numero e B7 per la
cella che ospita la conversione in lettere) sostituendo i relativi riferimenti alle celle che vi necessitano
Sub NumeriLettere()
Dim N$(100), M$(100)
Range("B6").Select 'cella col numero da convertire
Num = ActiveCell.Value

N$(0) = ""
N$(1) = "uno"
N$(2) = "due"
N$(3) = "tre"
N$(4) = "quattro"
N$(5) = "cinque"
N$(6) = "sei"
N$(7) = "sette"
N$(8) = "otto"
N$(9) = "nove"
N$(10) = "dieci"
N$(11) = "undici"
N$(12) = "dodoci"
N$(13) = "tredici"
N$(14) = "quattordici"
N$(15) = "quindici"
N$(16) = "sedici"
N$(17) = "diciassette"
N$(18) = "diciotto"
N$(19) = "diciannove"
M$(0) = ""
M$(2) = "venti"
M$(3) = "trenta"
M$(4) = "quaranta"
M$(5) = "cinquanta"
M$(6) = "sessanta"
M$(7) = "settanta"
M$(8) = "ottanta"
M$(9) = "novanta"
M$(10) = "Cento"
NN$ = LTrim$(Str$(Num))

If Len(NN$) > 6 Then


Milioni$ = Left$(NN$, Len(NN$) - 6)
NN$ = Right$(NN$, 6)
End If
If Len(NN$) > 3 Then
Migliaia$ = Left$(NN$, Len(NN$) - 3)
NN$ = Right$(NN$, 3)
End If

GoSub Ciclo
LLL$ = LL$
NN$ = Migliaia$
If Migliaia$ = "1" Then
http://ennius.interfree.it/ Pagina 234
MANUALE VBA X EXCEL
LLL$ = "mille" + LLL$
Else
GoSub Ciclo
If Len(LL$) > o Then LLL$ = LL$ + "mila" + LLL$
End If

NN$ = Milioni$
If Milioni$ = "1" Then
LLL$ = "unmilione" + LLL$
Else
GoSub Ciclo
If Len(LL$) > o Then LLL$ = LL$ + "milioni" + LLL$
End If

Range("B7").Select 'cella che riporta la conversione il lettere


ActiveCell.Value = LLL$

GoTo Fine

Ciclo:
LL$ = ""
Num0 = Val(NN$)
If Len(NN$) = 2 Then NN$ = "0" + NN$
If Len(NN$) = 1 Then NN$ = "00" + NN$
Num3 = Val(Right$(NN$, 1))
Num2 = Val(Mid$(NN$, 2, 1))
Num1 = Val(Left$(NN$, 1))
If Num0 > 99 Then
If Num0 > 199 Then LL$ = N$(Num1)
LL$ = LL$ + "cento"
End If

If Num2 > 1 Then


LL$ = LL$ + M$(Num2)
If Num3 > 0 Then
If Num3 = 1 Or Num3 = 8 Then LL$ = Left$(LL$, Len(LL$) - 1)
LL$ = LL$ + N$(Num3)
End If
End If
If Num2 < 2 Then
LL$ = LL$ + N$(Num3 + Num2 * 10)
End If
Return

Fine:
End Sub
Un plauso al bravo Marco; ora aspettiamo la versione per i decimali.
La versione per gli Euro con i decimali arrivata:
La routine inserita nell'evento Change del Foglio di lavoro, ma pu essere inserita anche in un modulo
e attivabile tramite l'associazione ad un pulsante. (Dovr essere assegnato un nome alla macro, per
esempio Sub NumeriLettere() )
Private Sub Worksheet_Change(ByVal Target As Range)
' Converte un numero da cifre a lettere (con decimali)

Application.ScreenUpdating = False

Dim N$(100), M$(100)


http://ennius.interfree.it/ Pagina 235
MANUALE VBA X EXCEL
Range("B6").Select 'cella col numero da convertire
NumTot = ActiveCell.Value

Num = Int(NumTot)
Dec = NumTot - Num
Decim$ = Format(Dec, ".00")
Decim$ = " / " + Right$(Decim$, Len(Decim$) - 1)

N$(0) = ""
N$(1) = "uno"
N$(2) = "due"
N$(3) = "tre"
N$(4) = "quattro"
N$(5) = "cinque"
N$(6) = "sei"
N$(7) = "sette"
N$(8) = "otto"
N$(9) = "nove"
N$(10) = "dieci"
N$(11) = "undici"
N$(12) = "dodoci"
N$(13) = "tredici"
N$(14) = "quattordici"
N$(15) = "quindici"
N$(16) = "sedici"
N$(17) = "diciassette"
N$(18) = "diciotto"
N$(19) = "diciannove"
M$(0) = ""
M$(2) = "venti"
M$(3) = "trenta"
M$(4) = "quaranta"
M$(5) = "cinquanta"
M$(6) = "sessanta"
M$(7) = "settanta"
M$(8) = "ottanta"
M$(9) = "novanta"
M$(10) = "Cento"
NN$ = LTrim$(Str$(Num))

If Len(NN$) > 6 Then


Milioni$ = Left$(NN$, Len(NN$) - 6)
NN$ = Right$(NN$, 6)
End If
If Len(NN$) > 3 Then
Migliaia$ = Left$(NN$, Len(NN$) - 3)
NN$ = Right$(NN$, 3)
End If

GoSub Ciclo
LLL$ = LL$
NN$ = Migliaia$
If Migliaia$ = "1" Then
LLL$ = "mille" + LLL$
Else
GoSub Ciclo
If Len(LL$) > o Then LLL$ = LL$ + "mila" + LLL$
End If
http://ennius.interfree.it/ Pagina 236
MANUALE VBA X EXCEL
NN$ = Milioni$
If Milioni$ = "1" Then
LLL$ = "unmilione" + LLL$
Else
GoSub Ciclo
If Len(LL$) > o Then LLL$ = LL$ + "milioni" + LLL$
End If

'ActiveCell.Offset(0, 1).Range("A1").Select
LLL$ = LLL$ + Decim$
Range("B7").Select 'cella che riporta la conversione il lettere
ActiveCell.Value = LLL$
'ActiveCell.Offset(1, -1).Range("A1").Select
Exit Sub
'GoTo Fine

Ciclo:
LL$ = ""
Num0 = Val(NN$)
If Len(NN$) = 2 Then NN$ = "0" + NN$
If Len(NN$) = 1 Then NN$ = "00" + NN$
Num3 = Val(Right$(NN$, 1))
Num2 = Val(Mid$(NN$, 2, 1))
Num1 = Val(Left$(NN$, 1))
If Num0 > 99 Then
If Num0 > 199 Then LL$ = N$(Num1)
LL$ = LL$ + "cento"
End If

If Num2 > 1 Then


LL$ = LL$ + M$(Num2)
If Num3 > 0 Then
If Num3 = 1 Or Num3 = 8 Then LL$ = Left$(LL$, Len(LL$) - 1)
LL$ = LL$ + N$(Num3)
End If
End If
If Num2 < 2 Then
LL$ = LL$ + N$(Num3 + Num2 * 10)
End If
Return

Fine:

End Sub
Ancora grazie a Marco.

http://ennius.interfree.it/ Pagina 237


MANUALE VBA X EXCEL
Numeri Romani (in automatico.)
A volte abbiamo la necessit di ottenere, in una cella, numeri in formato romano (con le lettere). Oltre
alla funzione specifica =ROMANO(rif_Cella) da inserire in una cella del foglio di lavoro, possibile
ovviamente ottenere anche via codice lo stesso risultato. Ricordo che un istruzione via codice rimane,
non pu essere cancellata come invece pu accadere con una formula inserita in una cella.
Ecco qu una routine veloce, magari da inserire nell'evento SelectionChange del foglio di lavoro
anzich associata ad un pulsante, per averla attivata ad ogni cambio di selezione cella, sul foglio di
lavoro. Esemplificando, porremo in A1 la cella contenente il numero da convertire, ed in C1 vorremo il
numero romano; se in A1 avremo il numero "24", in C1 avremo "XXIV" . Questo il codice:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
'per avere numeri romani
Range("C1").Formula = "=ROMAN(A1)"
End Sub

http://ennius.interfree.it/ Pagina 238


MANUALE VBA X EXCEL
La routine converti numeri in lettere trasformata in FUNZIONE: NUMINEURO().
Utilizzo: Conversione numeri in lettere, quando la conversione interessa pi celle . Aggiornata al
30/06/03 con l'aggiunta dell'argomento Arrotonda.
Questa procedura utile nel caso si voglia utilizzare la conversione su pi celle, e magari con
riferimenti a celle distanti. A differenza delle routine del precedente paragrafo, dove necessario
inserire nel codice i riferimenti alle celle, sia quella che porta il numero, sia quella dove deve apparire
la conversione in lettere del numero, questa funzione, una volta inserita la funzione in un modulo,
consente di essere richiamata in qualunque cella, semplicemente dichiarando il nome della funzione
ed il riferimento alla cella da convertire. Se per esempio, vogliamo che in F2 appaia il numero in lettere
che nella cella A1, in F2 scriveremo
=Numineuro(A1;2) 'arrotondata a due decimali
ed avremo in F2 la conversione. La conversione converte numeri interi o decimali e restituisce sempre il
numero scritto in lettere con due decimali. (es: centoventisette/00). Ora previsto l'arrotondamento a
due decimali secondo il concetto: se il terzo decimale 5 o maggiore, il secondo decimale viene
arrotondato al decimale superiore (per eccesso), da 0 a 4, arrotondamento per difetto. Esempio:
in A1 abbiamo 127,5478 con la funzione =Numineuro(A1;2) in un'altra cella, otteniamo:
Centoventisette/55 (il secondo decimale arrotondato per eccesso)
Questo il codice, da copiare e incollare in un modulo:
Function NumInEuro(NumTot As Currency, Arrotonda As Integer)

Application.ScreenUpdating = False

Dim N$(100), M$(100)


NumTot = Round(NumTot, Arrotonda)
Num = Int(NumTot)
Dec = NumTot - Num
Decim$ = Format(Dec, "." + String(Arrotonda, "0"))
Decim$ = " / " + Right$(Decim$, Len(Decim$) - 1)
If Arrotonda = 0 Then Decim$ = " / 00"

N$(0) = ""
N$(1) = "uno"
N$(2) = "due"
N$(3) = "tre"
N$(4) = "quattro"
N$(5) = "cinque"
N$(6) = "sei"
N$(7) = "sette"
N$(8) = "otto"
N$(9) = "nove"
N$(10) = "dieci"
N$(11) = "undici"
N$(12) = "dodoci"
N$(13) = "tredici"
N$(14) = "quattordici"
N$(15) = "quindici"
N$(16) = "sedici"
N$(17) = "diciassette"
N$(18) = "diciotto"
N$(19) = "diciannove"
M$(0) = ""
M$(2) = "venti"
M$(3) = "trenta"
M$(4) = "quaranta"
M$(5) = "cinquanta"
M$(6) = "sessanta"
M$(7) = "settanta"
M$(8) = "ottanta"
http://ennius.interfree.it/ Pagina 239
MANUALE VBA X EXCEL
M$(9) = "novanta"
M$(10) = "Cento"
NN$ = LTrim$(Str$(Num))

If Len(NN$) > 6 Then


Milioni$ = Left$(NN$, Len(NN$) - 6)
NN$ = Right$(NN$, 6)
Else
Milioni$ = ""
End If
If Len(NN$) > 3 Then
Migliaia$ = Left$(NN$, Len(NN$) - 3)
NN$ = Right$(NN$, 3)
Else
Migliaia$ = ""
End If

GoSub Ciclo
LLL$ = LL$
NN$ = Migliaia$
If Migliaia$ = "1" Then
LLL$ = "mille" + LLL$
Else
GoSub Ciclo
If Len(LL$) > o Then LLL$ = LL$ + "mila" + LLL$
End If

NN$ = Milioni$
If Milioni$ = "1" Then
LLL$ = "unmilione" + LLL$
Else
GoSub Ciclo
If Len(LL$) > o Then LLL$ = LL$ + "milioni" + LLL$
End If

NumInEuro = LLL$ + Decim$

Exit Function

Ciclo:
LL$ = ""
Num0 = Val(NN$)
If Len(NN$) = 2 Then NN$ = "0" + NN$
If Len(NN$) = 1 Then NN$ = "00" + NN$
Num3 = Val(Right$(NN$, 1))
Num2 = Val(Mid$(NN$, 2, 1))
Num1 = Val(Left$(NN$, 1))
If Num0 > 99 Then
If Num0 > 199 Then LL$ = N$(Num1)
LL$ = LL$ + "cento"
End If

If Num2 > 1 Then


LL$ = LL$ + M$(Num2)
If Num3 > 0 Then
If Num3 = 1 Or Num3 = 8 Then LL$ = Left$(LL$, Len(LL$) - 1)
LL$ = LL$ + N$(Num3)
http://ennius.interfree.it/ Pagina 240
MANUALE VBA X EXCEL
End If
End If
If Num2 < 2 Then
LL$ = LL$ + N$(Num3 + Num2 * 10)
End If
Return
End Function
Procedura realizzata da Marco Nocciolini.

http://ennius.interfree.it/ Pagina 241


MANUALE VBA X EXCEL
Cicli su "Controlli". (ovvero sugli "Oggetti" posti su Userform)
Quando lavoriamo sulle UserForm, possiamo inserirvi degli "Oggetti" presi dalla finestrina degli strumenti
che appare quando, nell'editor di visual basic, inseriamo o selezioniamo una UserForm. Questi oggetti:
una TextBox, un CommandButton, una ComboBox, ecc. ecc., non sono altro che "Controlli" ActiveX.
Ogni Controllo viene identificato dal vba in funzione della Classe di appartenenza. Pi Oggetti
appartenenti alla stessa Classe vengono visti come "insiemi" omogenei, per esempio le TextBox ; tant
che se inseriamo pi TextBox sulla nostra UserForm, per identificare l'oggetto, il vba provvede ad
assegnare un numero progressivo ad ogni oggetto della stessa Classe inserito (avremo quindi: TextBox1,
TextBox2, ecc.ecc.).
La numerazione progressiva dovrebbe semplificare la programmazione quando si debbano trattare
pi oggetti omogenei, per esempio con cicli For Each...Next oppure For I = 1 To X ..Next, in riferimento a
ci che vorremmo fosse compiuto su ogni oggetto dell'insieme.
A differenza di quanto avviene in Visual Basic, dove possibile costruire una "Matrice di Controlli", che
ci consentirebbe di assegnare un indice progressivo ad uno stesso "controllo" ripetuto (Text1(0),
Text1(1), Text1(2), ecc.), favorendo quindi il riconoscimento di quale indice interessato
progressivamente dal ciclo For ...Next, in vba necessario ricorrere all'insieme CONTROLS (Controlli)
tramite un indice, un numero o un nome.
Visto che tutte le TextBox hanno in comune almeno la parola Text, possibile impostare una routine per
intervenire sulle loro propriet, per esempio per renderle visibili o invisibili:
For Each cnt In Controls
If Left(cnt.Name, 4) = "Text" Then
cnt.Visible = False '(oppure True)
End If
Next
Cio : per ogni controllo (cnt) in Controlli (cio gli "oggetti" presenti sull'UserForm), se le prime 4 lettere
del nome del controllo sono uguali a Text, allora rendiamo invisibile il controllo.
Vediamo ora un esempio su come riempire, sfruttando l'insieme Controls, una serie di TextBox con i
valori prelevati da celle del foglio di lavoro. Supponiamo di avere dieci TextBox, nelle quali vogliamo
che vengano riportati i dati presenti in altrettante dieci celle, sulla stessa riga, e di cui sia resa attiva la
prima cella a sinistra, dovremmo scrivere le istruzioni, una per ogni textbox, in questa maniera:
TextBox1 = ActiveCell.Offset(0, 1).Value
TextBox2 = ActiveCell.Offset(0, 2).Value
TextBox3 = ActiveCell.Offset(0, 3).Value
TextBox4 = ActiveCell.Offset(0, 4).Value
TextBox5 = ActiveCell.Offset(0, 5).Value
ecc.ecc. fino alla 10.
Sfruttando invece i Controls dell'oggetto UserForm, possibile ridurre le istruzioni a poche righe, con un
ciclo For ..Next, vediamo come:
For n = 1 To 10 '(n sar incrementato di 1 da 1 a 10 ad ogni ciclo (10 sono sia le textbox, sia le celle))
UserForm1.Controls("TextBox" & n).Text = ActiveCell.Offset(0, n).Value
Next
ed avremo ottenuto il nostro risultato con solo tre righe di istruzioni. La variabile n cambia ad ogni ciclo,
sia per indicare in progressione il nome del controllo TextBox, sia per identificare la colonna della cella.

Buon lavoro.

http://ennius.interfree.it/ Pagina 242


MANUALE VBA X EXCEL
Usare l'Operatore LIKE (19/07/03)
Sappiamo tutti, almeno spero, cosa sono gli "Operatori di confronto", eventualmente date un occhiata
all'articolo "operatori numerici" nella sezione "primi passi". Comunque servono a confrontare due valori
(testi, numeri o date). In genere i confronti si fanno per valutare la corrispondenza esatta tra due o pi
valori, oppure se un valore pu essere maggiore o minore rispetto ad un altro; ma quando abbiamo
bisogno di confrontare "approssimativamente" due valori, gli operatori normalmente usati non bastano
pi. Un esempio potrebbe essere quello di cercare, in un elenco, tutti valori la cui lettera iniziale
corrisponde ad "a". Sappiamo che una parola come "atlante", che pure comincia con "a", non
verrebbe trovata in quanto in quanto i metodi di ricerca si basano su un valore preciso fornito come
chiave di ricerca, e la stringa "a" ovviamente diversa dalla stringa "atlante". In questi casi ci viene in
aiuto l'operatore LIKE, che vuol dire appunto "simile a...", "come" o " che "assomiglia a..". Perch Like ci
possa aiutare in una ricerca, va a sua volta aiutato, (indicando di seguito ad un valore chiave per
esempio la lettera "c"), un carattere speciale definito sintatticamente "criterio", e che pu essere
rappresentato da uno dei seguenti caratteri Jolly :
? - (punto di domanda) che fa corrispondere qualsiasi carattere singolo.
* - (asterisco) che fa corrispondere zero o pi caratteri.
# - (cancelletto) che fa corrispondere qualsiasi cifra singola (0-9).
I caratteri Jolly ci consentono quindi di sostituirsi ad elenchi di caratteri o intervalli di caratteri in qualsiasi
combinazione. Un'istruzione quindi che ci consentirebbe di trovare "atlante" digitando solo la lettera
"a", diventerebbe:
If CL.Value Like "a*" Then
dove l'asterisco posto dopo la lettera "a" consentirebbe di riconoscere "a tlante" perch l'asterisco
sostituisce l'intervallo di caratteri "tlante". In parole povere, l'istruzione sopra dice:
se il valore della variabile CL comincia con "a" con tutto quello che ci sia dopo, Then ecc. ecc.
Ma come e dove usare Like ? Essenzialmente per eseguire ricerche di dati, di cui si voglia inserire una
sola lettera iniziale, o un numero come chiave di ricerca, e si vogliano trovare tutti i valori che iniziano
con quella lettera (o gruppo di lettere), e quel numero (o gruppi di numeri). Avremo quindi che con la
stringa di ricerca
c* - verranno trovati tutti i valori che iniziano per "c" : catullo, circo, caramba, cucurnia, ceffo, ecc.
ca* - verranno trovati tutti i valori che iniziano per "ca" : catullo, caramba
car* - verranno trovati tutti i valori che iniziano per "car" : caramba
lo stesso dicasi per i numeri, o per le date (pi avanti troverete una precisazione a questo proposito)
1* - verranno trovati tutti i valori che iniziano per "1" : 10, 125, 1543, 10/07/03 ecc.
10* - verranno trovati tutti i valori che iniziano per "10" : 10, 10/07/03
154* -verranno trovati tutti i valori che iniziano per "154" : 1543
Abbiamo quindi imparato un metodo flessibile che ci consente un'ampia possibilit di variare le
ricerche. Vediamo ora qualche esempio di applicazione, con relative istruzioni e commenti (in verde).
Iniziamo con chiarire come impostare la chiave di ricerca:
inserendo la chiave di ricerca direttamente nelle istruzioni: es. Like "a*" ; sistema poco flessibile perch
ci costringerebbe alla modifica dell'istruzione nel codice se volessimo trovare altri valori che inizino con
altre lettere.
usare una cella del foglio di lavoro, nella quale di volta in volta scrivere il valore che serva come
chiave di ricerca; es. usando la cella C1, la nostra istruzione diventerebbe Like Range("C1") & "*". Come
si nota usiamo un concatenatore di stringa (la &) per restituire, uniti, il valore che scriveremo in C1
seguito dall'asterisco (carattere Jolly)
usare una textbox se usiamo una userform, nella quale scriveremo il valore chiave di ricerca (come
sopra) e in questo caso l'istruzione sar : Like TextBox1 & "*"
usare una InputBox. in questo caso dovremo assegnare ad una variabile il valore restituito dalla
InputBox, e richiamare questa variabile+asterisco dopo Like. Sar sufficiente compilare:
Myvar = InputBox("Inserisci il valore da cercare")
......Like CStr(Myvar) & "*"
Ora passiamo a vedere in quale contesto usare queste istruzioni. Molte sono le situazioni in cui si pu
presentare la necessit di svolgere una ricerca, qui sceglieremo l'esempio di cercare tutti i valori la cui
iniziale corrisponder ad una determinata lettera, e con i dati cos trovati, riempire una ListBox. Sotto
vediamo l'immagine dell'esercizio: la colonna A la zona dove risiedono i dati, la cella C1 la cella
che usiamo come vettore per l'iniziale che serve a trovare nella colonna A tutti i valori che cominciano
con una lettera, in questo caso la lettera "c", e la ListBox1 con i nomi trovati

http://ennius.interfree.it/ Pagina 243


MANUALE VBA X EXCEL

e questa la routine usata:


Sub carica1()
Dim CL As Object
ActiveSheet.ListBox1.Clear 'predisponiamo la pulizia della listbox per la nuova ricerca
For Each CL In Range("A1:A20") 'inizia il ciclo di ricerca: per ogni CL (cella presente
'nel Range A1:A20 (tanto per fare l'esempio mi fermo alla riga 20)
'sotto: se il valore che presente nella cella in quel momento scorsa, uguale al
valore che ' in C1*, cio basta che inizi con "c" (in questo caso), allora
If CL.Value Like Range("C1") & "*" Then
'carichiamo con AddItem quel valore nella ListBox1
ActiveSheet.ListBox1.AddItem CL.Value
End If
Next
End Sub
Baster quindi variare la lettera in C1 per ottenere, se presenti nell'elenco, i nomi che iniziano per quella
lettera, nella ListBox. Un'altro aspetto interessante di questo metodo di estrazione dati, perch di questo
si tratta, che se nell'elenco dati esistono celle vuote, queste non figureranno mai nella ListBox.
Qualcuno potrebbe obiettare: ma come fare per ottenere i nomi trovati, messi in ordine alfabetico
nella ListBox? E ancora: come fare perch eventuali dati doppi vengano riportati una sola volta? A
quest'ultima domanda rispondo: leggete l'articolo "ComboBox . ordinare la lista", dove si parla della
routine per l'eliminazione dei doppioni. Alla prima domanda rispondo.
applicare un'ordinamento all'elenco a cui si attingono i dati da ricercare: i dati trovati saranno gi in
ordine alfabetico.
creare in una colonna fuori vista, un riepilogo dei dati estratti, applicare a questo secondo elenco
un'ordinamento ascendente, reperire quindi il riferimento alla cella iniziale e con End il riferimento alla
cella finale, e fornire questi riferimenti alla propriet ListFillRange della ListBox (anzich usare AddItem)
in modo che la ListBox ci mostri l'elenco in ordine alfabetico.
Vediamo un'immagine basata su quest'ultima ipotesi, dove, per comodit visive, il secondo elenco lo
ospito nella colonna D, a partire dalla cella D4. A questo elenco stato gi applicato l'ordinamento, a
destra la Listbox caricata usando la sua propriet ListFillRange :

http://ennius.interfree.it/ Pagina 244


MANUALE VBA X EXCEL

E questa la routine, le istruzioni sono un p pi complesse rispetto alla routine carica1, ma viene svolto
un lavoro diverso :
Sub carica2()
'iniziamo pulendo la ListBox1 predisponendo alla nuova ricerca, e NON usiamo
Clear, 'ma impostiamo il ListFillRange a vuoto ("")
ActiveSheet.ListBox1.ListFillRange = ""
Dim CL As Object 'dichiariamo CL come "oggetto" (usato nel ciclo For Each..Next)
Dim iRow As Integer 'dichiariamo la variabile iRow come Integer ( la variabile con
la 'quale impostiamo da quale riga iniziare il riepilogo dei dati trovati (il secondo
elenco)
iRow = 3 'rendiamo iRow uguale a 3, cio il riepilogo inizier dalla riga 3
Range("D:D").ClearContents 'Puliamo tutta la colonna destinata al riepilogo, e la
puliamo 'tutta in quanto non sappiamo quanto lungo era il riepilogo precedente.
'sotto: ATTENZIONE : istruzione necessaria per ripristinare tutta la colonna destinata al
'riepilogo, impostando il formato celle a "Generale". Operazione necessaria nel caso
in cui 'si cerchino occasionalmente anche valori tipo data (es. 10/07/03), quando il
dato 'cercato viene trovato, se una data, Excel nel copiare la data nel riepilogo,
modifica 'anche il formato della cella che ospiter la data a formato cella data.
Questa 'impostazione rimane anche per le nuove ricerche, e se nella nuova ricerca
venissero 'cercati numeri anzich date, il numero che finisse dove prima era stata
ospitata una data, 'sarebbe errato e inservibile.
Range("D:D").NumberFormat = "General"
'sotto: si imposta il valore della cella, ora riga 3, 4 colonna, cio la D, a "riepilogo"
come 'se fosse un'intestazione di campo
Cells(iRow, 4).Value = "riepilogo"
'sotto: si inizia il ciclo di ricerca nel Range A1:A20, ognuno metter i suoi riferimenti
For Each CL In Range("A1:A20")
'sotto: se il valore che presente nella cella in quel momento scorsa, uguale al
valore 'che in C1*, cio basta che inizi con "a" (in questo caso), allora
If CL.Value Like Range("C1") & "*" Then
'inizia il ciclo interno per cercare una cella libera, colonna D (4) dove scrivere il
valore 'trovato sopra (CL.Value)
Do While Cells(iRow, 4).Value <> "" 'fino a che la cella occupata
iRow = iRow + 1 'si passa a controllare la cella sottostante (+1) e si continua con Loop
Cells(iRow, 4) = CL.Value 'quando si verifica che una cella vuota, gli si passa il
valore 'rappresentato da Cl.Value
Exit Do 'e si esce dal ciclo Do While..Loop
Loop 'altrimenti si continua a cercare una cella vuota ritornando a Do While
http://ennius.interfree.it/ Pagina 245
MANUALE VBA X EXCEL
End If
Next ' con Next si scorrono, una ad una le celle del Range A1:A20
'a questo punto, finita la ricerca e caricato il "riepilogo", abbiamo bisogno di reperire
gli 'Address, cio gli indirizzi delle celle che delimitano il "riepilogo"
lista = Cells(4, 4).Address 'con "lista" prendiamo l'indirizzo della cella riga 4, colonna 4
'(D4)
nera = Cells(4, 4).End(xlDown).Address 'con "nera" reperiamo l'ultima cella occupata
'della colonna D.
'sotto: applichiamo l'ordinamento ai range i cui estremi sono stati trovati con le due
'variabili
Range(lista & ":" & nera).Sort Key1:=Range("D4"), Order1:=xlAscending, Header:= _
xlGuess, OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom
'e alla fine carichiamo la ListFillRange della ListBox1 con l'assegnazione dei range di
'pertinenza
ActiveSheet.ListBox1.ListFillRange = (lista & ":" & nera)

End Sub
Sotto riporto, senza spiegazioni (sono uguali), la routine che si avvale di una InputBox per reperire il
valore da cercare:
Sub caricainput()
ActiveSheet.ListBox1.ListFillRange = ""
Dim CL As Object
Dim iRow As Integer
iRow = 3
cosa = InputBox("Scrivi cosa cerchi") 'con "cosa" prendiamo il valore da cercare
Range("D:D").ClearContents
Range("D:D").NumberFormat = "General"
Cells(iRow, 4).Value = "riepilogo"
For Each CL In Range("A1:A20")

If CL.Value Like CStr(cosa) & "*" Then 'e usiamo la variabile stringa "cosa" al posto
'dell'indicazione di una cella
Do While Cells(iRow, 4).Value <> ""
iRow = iRow + 1
Cells(iRow, 4) = CL.Value
Exit Do
Loop
End If
Next
lista = Cells(4, 4).Address
nera = Cells(4, 4).End(xlDown).Address
Range(lista & ":" & nera).Sort Key1:=Range("D4"), Order1:=xlAscending, Header:= _
xlGuess, OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom
ActiveSheet.ListBox1.ListFillRange = (lista & ":" & nera)

End Sub
Unica precisazione: il carattere Jolly * (asterisco), pu essere usato come valore iniziale da cercare,
seguito da una o pi lettere, e quindi ancora un asterisco. In questo modo possiamo trovare valori al
cui interno compaia la lettera o le lettere digitate tra gli asterischi. Esempio: se in C1 o nella InputBox
scriviamo *lo*, verranno trovati tutti i nomi al cui interno compare la coppia "lo", cio : bellotti, cellosi,
luppolo .

Buon lavoro.

http://ennius.interfree.it/ Pagina 246


MANUALE VBA X EXCEL
Ordinamento di un elenco dati in automatico.
Oltre all'ordinamento di un elenco dati ottenibile dai due pulsantini A-Z o Z-A posti su una barra dei
men, pu essere utile usare il codice Vba per ottenerlo in automatico. La tenuta di dati ordinati per
ordine alfabetico (ad esempio dei nominativi o un elenco articoli), oppure per ordine di grandezza (in
un elenco numerico), o ancora un elenco di date. Con la seguente procedura, baster infatti
aggiungere un nuovo dato per vederlo subito dopo ordinato al posto giusto in elenco. La procedura la
inseriremo nell'evento WorkSheet_SelectionChange del foglio che contiene l'elenco:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
With Range("A:A")
.Sort Key1:=Range("A1"), Order1:=xlAscending, Header:=xlGuess, _
OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom, _
DataOption1:=xlSortNormal
End With
End Sub
L'esempio stato fatto presupponendo un elenco contenuto nella colonna A, e che i dati iniziassero
nella cella A1. Baster sostituire i riferimenti per adattarlo al proprio elenco. Se anzich volere un
ordinamento crescente volessimo un ordinamento decrescente, baster sostituire il comando "
Order1:=xlAscending " con " Order1:=xlDescending " . Volendo, invece, disporre manualmente il nostro
elenco, potremo utilizzare questa routine , associata ad un pulsante posizionato sul foglio di lavoro:
Sub OrdineCrescente()
With Range("A:A")
.Sort Key1:=Range("A1"), Order1:=xlAscending, Header:=xlGuess, _
OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom, _
DataOption1:=xlSortNormal
End With
End Sub

e l'altra, decrescente:
Sub OrdineDecrescente()
With Range("A:A")
.Sort Key1:=Range("A1"), Order1:=xlDescending, Header:=xlGuess, _
OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom, _
DataOption1:=xlSortNormal
End With
End Sub

Quando invece vogliamo ordinare un elenco formato da pi colonne, per esempio un indirizzario dove
oltre al nome registriamo, nelle colonne adiacenti, l'indirizzo, la citt, ed altri dati, avremo bisogno, se
scegliamo di avere i dati in ordine alfabetico del nominativo, che anche i dati associati al nominativo si
spostino insieme al nome. Volendo usare ancora l'ordinamento automatico, dovremo allora modificare
le istruzioni. Sfrutteremo sempre l'evento SelectionChange del foglio di lavoro, ma dovremo inserire
delle coordinate precise per indicare TUTTA l' area interessata all'ordinamento, compreso quindi non
solo la colonna che contiene i nomi che vogliamo in ordine alfabetico, ma anche le colonne dove
sono i dati correlati (indirizzo, citt, telefono, ecc.). Potremo comprendere anche delle righe vuote che
serviranno poi per l'aggiunta di nuovi dati. Supponiamo quindi di usare la zona che va dalla prima cella
(A1) e. per quattro colonne (A,B,C,D) fino alla riga 200, l'istruzione sar:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)

With Range("A1:D200") 'Area che comprende tutti i dati


.Sort Key1:=Range("A1"), Order1:=xlAscending, Header:=xlGuess, _
OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom, _
DataOption1:=xlSortNormal
End With
'la spiegazione di questa parte di codice la d sotto
Dim CL As Object
For Each CL In Range("A1:A200")
If CL.Value <> "" And CL.Offset(0, 1).Value = "" Then
CL.Offset(0, 1).Select
http://ennius.interfree.it/ Pagina 247
MANUALE VBA X EXCEL
End If
Next

End Sub
Poich l'inserimento di un nominativo, nella colonna A, ha bisogno di essere confermato premendo il
tasto INVIO o con la pressione su una delle frecce per spostarsi, e questo genera l'evento
SelectionChange, avremo che il nome appena immesso verr immediatamente ordinato, con
conseguente spostamento nell'elenco stesso: per non correre a cercare dove finito (specie con
lunghi elenchi), ho aggiunto la seconda istruzione che cercher (nella colonna dei nominativi, la A) il
primo valore con la cella adiacente vuota, e la selezioner, cos che si possano inserire gli altri dati
mancanti.

http://ennius.interfree.it/ Pagina 248


MANUALE VBA X EXCEL
Ordinamento scadenzario con raggruppamento clienti e somma degli importi delle loro fatture.
Fra i diversi metodi che Excel ci offre per ottenere da un elenco, per esempio uno scadenzario, il
raggruppamento dei dati relativi ad una chiave prestabilita (per esempio il Codice Cliente o il
nominativo Cliente), ottenibili con un filtro, e relativi sub totali del campo "Importo fattura", sempre
attraverso le risorse di Excel (men Dati/Subtotali), presento una soluzione realizzata in vba che non
richiede l'uso del filtro. Vediamo un esempio, nella foto sotto vediamo una tipica tabella, che potrebbe
essere anche un "Riepilogo Fatture emesse" anzich uno scadenzario, il concetto non cambia:

Come si nota nell'elenco, i dati non sono raggruppati per Cliente, ma mescolati. Avremo bisogno
quindi di eseguire un "ordinamento" in modo da riunire tutti i clienti con lo stesso nome oppure con lo
stesso codice cliente, noi scegliamo la chiave "codice cliente". poich sappiamo da quanti campi
(colonne) formato il nostro elenco, ma non possiamo sapere quante righe occuper, useremo la
funzione End per reperire i "riferimenti" delle ultime celle: sia quella verso il basso (End(xlDown) a partire
dalla cella di inizio elenco (la A2), sia quella verso destra (End(xlToRight)) sempre a partire dalla stessa
A2. In questo modo selezioneremo tutta l'area dati che ci interessa, e su quell'area applicheremo
l'ordinamento usando come chiave di ricerca il codice cliente (SortKey1:= Range("A2")), e queste sono
le istruzioni, che assoceremo ad un pulsante:
Sub Ordinadati()

giu = Range("A2").End(xlDown).Address
dx = Range("A2").End(xlToRight).Address

Range(giu & ":" & dx).Select

Selection.Sort Key1:=Range("A2"), Order1:=xlAscending, Header:=xlGuess, _


OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom, _
DataOption1:=xlSortNormal
End Sub
e questo sar l'effetto dopo l'ordinamento; come di vede, sono stati riuniti tutti i clienti che hanno lo
stesso codice uguale:

A questo punto cosa dovremo ottenere:


la separazione tra un cliente e l'altro con l'aggiunta di due righe, nella prima delle quali inseriremo la
parola "totale" nella colonna B
l'inserimento nella colonna E, sempre nella prima delle due righe aggiunte, di una formula che cerchi,
a salire, tutti gli importi relativi alle fatture di quel cliente, e sommi gli importi in modo da ottenere un
totale cliente.
Per ottenere questo risultato:
http://ennius.interfree.it/ Pagina 249
MANUALE VBA X EXCEL
useremo una InputBox nella quale inseriremo il codice cliente di cui vogliamo il totale.
useremo in ciclo di ricerca di questo valore in modo che venga selezionata l'ultima cella che sia
uguale al codice indicato.
trovata questa cella, selezioniamo la riga immediatamente sotto, e con la cella in quel momento
attiva, diciamo di inserire 2 nuove righe. Operazione necessaria visto che l'inserimento riga in Excel
avviene sopra la cella (meglio riga) in quel momento selezionata, non sotto.
inseriamo nella prima delle due righe (colonna A) un trattino, nella colonna B la parola "totale" e nella
colonna E la funzione SOMMA.
questo il codice impiegato:
Sub cerca()
With Worksheets(1).Range("a1:a20") 'range sui cui si opera
'istruzioni per l'imputbox che ti chiede il
'codice cliente
Dim code, mess, titolo
mess = "Inserisci il Codice Cliente :"
titolo = "Inserimento Codice"
code = InputBox(mess, titolo) '"code" ora uguale al codice digitato

'inizio il ciclo di ricerca nel range scelto (A1:A20), del valore che
' stato assegnato a "code"
Set c = .Find(code, LookIn:=xlValues)
If Not c Is Nothing Then
firstAddress = c.Address
Do
'viene individuato l'ultimo "code" trovato e seleziono
'la cella sotto per poter aggiungere due righe
c.Offset(1, 0).Select
Set c = .FindNext(c)
Loop While Not c Is Nothing And c.Address <> firstAddress
End If
End With
'aggiungo due righe
ActiveCell.EntireRow.Insert Shift:=xlDown
ActiveCell.EntireRow.Insert Shift:=xlDown
'inizia l'inserimento nella prima cella di una lineetta (colonna A)
'poi inserisce "totale" nella cella accanto,
ActiveCell = "-"
ActiveCell.Offset(0, 1) = "totale"
'poi controlla la colonna importi, (la E) e ne prende i riferimenti a salire: X sar uguale
al 'riferimento cella attiva + 4, cio la colonna E, ma la cella nella riga
immediatamente 'sopra (-1). Poich si pu verificare il caso che esista un cliente con
una sola fattura, 'sarebbe inutile sommare, ed allora eseguiamo un controllo sulla
seconda riga a salire, colonna E, Se questa cella conterr dati (diversa da vuota),
allora si ricercano tutte le 'righe a salire con End, per prendere l'ultimo riferimento
If ActiveCell.Offset(-2, 4) <> "" Then
X = ActiveCell.Offset(-1, 4).Address
'poi preso il riferimento dell'ultima cella con End(xlUp) contenete valori Y sar uguale
al riferimento cella attiva + 4, cio la colonna E ma alla prima (la pi in alto) cella
iniziale.
'Ricordo che l'istruzione End cerca l'ultima cella occupata nella direzione indicata
dalla 'costante, a partire dalla cella iniziale indicata (in questo caso: ActiveCell) e si
ferma 'appena trova una cella vuota.
Y = ActiveCell.Offset(-1, 4).End(xlUp).Address
'indi applica la funzione somma
ActiveCell.Offset(0, 4).Formula = "=SUM(" & X & ":" & Y & ")"
'nel caso previsto che il cliente sia presente con una sola fattura, invece rendiamo il
totale 'uguale all'importo della fattura
Else
http://ennius.interfree.it/ Pagina 250
MANUALE VBA X EXCEL
ActiveCell.Offset(0, 4).Value = ActiveCell.Offset(-1, 4).Value
End If
End Sub
Una nota: perch la somma si applichi in maniera corretta, sar necessario procedere rispettando il
codice progressivo: se per esempio, si cercasse di ottenere il totale del codice 3402 senza prima avere
ottenuto i totali e quindi la separazione con due righe vuote del codice 3401, il codice 3402 verrebbe
separato si da quello successivo, ma la somma coinvolgerebbe anche i valori relativi al codice 3401
non essendo separati.
Questa comunque l'immagine del risultato dell'istruzione sopra:

Buon Lavoro.

http://ennius.interfree.it/ Pagina 251


MANUALE VBA X EXCEL
ProgressBar. (23/07/03 - Aggiornamento 10/02/04)
Alcune richieste, anche passate, avevano come argomento, la realizzazione di una "barra di
avanzamento" (ProgressBar) che avvisasse l'utente che una macro era in esecuzione. Infatti a volte si
pu lamentare una lentezza nell'esecuzione di procedure, tale da far pensare che il computer non stia
lavorando, Una barra di avanzamento consentirebbe, con la sua progressione, di "visualizzare" che in
effetti "qualcosa" sta succedendo. Premesso che alcune routine sono mal costruite, ed impiegano pi
tempo del dovuto a terminare, premesso che alcuni computer sono dotati di scarse risorse Hardware
(poca RAM, dischi lenti, processori obsoleti) esistono tuttavia lentezze causate dalla gran quantit di
dati che devono essere elaborati, da qui l'esigenza di avere un "segnale" che tutto sta procedendo.
Bisogna capire come prima cosa, che qualsiasi ProgressBar per funzionare, deve poter essere
collegata ad una variabile che sia un vettore del numero di iterazioni che si stanno eseguendo. Solo
con questa impostazione sar possibile verificare in tempo reale (o quasi ) l'avanzamento
dell'esecuzione di una macro, e le istruzioni per l'avvio della ProgressBar, andranno posizionate
opportunamente per evitare che lo scorrimento della barra di avanzamento non parta, o parta dopo,
o addirittura interferisca con l'esecuzione stessa (della procedura) rallentandola ulteriormente.
La ProgressBar pi semplice e veloce da ottenere (ATTENZIONE: questa soluzione NON vale per la
versione 97 di Excel), quella di usare la "BARRA DI STATO". Vediamo come ottenerla:
dal men Visualizza, selezionare la voce "Barra di stato", vedi foto:

e in fondo alla pagina, comparir una barra in pi, con all'estrema sinistra, la parola "Pronto" :

Questa operazione pu comunque essere evitata, perch la "Barra di stato" pu venire chiamata da
un'istruzione che integreremo nella nostra macro, e che imposter anche il testo che apparir al posto
di "Pronto", indicando peraltro il valore che indica lo "stato di avanzamento", ottenendo l'effetto di
tranquillizzare chi aspetta che la macro termini. Nella foto sotto vediamo un'istantanea dei numeri che
scorrono, indicando l'avanzamento:

Vediamo quindi come sfruttare le istruzioni, presentando un esempio nel quale, riempiremo tutte le
celle che vanno dalla cella A1 alla J500, con numeri casuali. Questa la macro, che potrete copiare e
provare sul vostro computer :
Sub Test()
http://ennius.interfree.it/ Pagina 252
MANUALE VBA X EXCEL
[A1:J500].ClearContents 'nel range previsto come esempio, puliamo le celle
Dim r 'dimensioniamo la variabile "r" per indicare le righe
Dim c 'dimensioniamo la variabile "c" per indicare le colonne
For r = 1 To 500 'indi si inizializza il ciclo che conter le righe da 1 fino a 500
For c = 1 To 10 ' e le colonne fino alla colonna 10 (la J)
Randomize 'Randomize serve a reinizializzare il numero iniziale casuale, diverso dal
'primo ottenuto con Rnd, successivo

Cells(r, c) = Int(Rnd * 150) 'poi assegniamo un numero casuale compreso tra zero e
150 'alla cella, riga r, colonna c, in quel momento reperita con i cicli For..Next sopra
Cells(r, c).Select 'selezioniamo la cella in quel momento "spazzolata" solo per creare
un 'effetto visivo delle celle che vengono di volta in volta individuata. In questo
modo si pu 'controllare l'efficacia dell'avanzamento routine
Counter = r * c 'con la variabile "counter" (riga per colonna) otteniamo il numero di
celle 'in ogni momento "contate" dai cicli For..Next e rappresenta il valore che verr
mostrato 'nella "StatusBar", indicando quindi la progressione delle operazioni.
DoEvents 'istruzione necessaria perch lascia l'esecuzione delle istruzioni "libere" di
'proseguire, senza "bloccarne" l'esecuzione.
'sotto: si attiva la "barra di stato" e si imposta il testo che vedremo, seguito dal valore
'rappresentato da "COUNTER".
Application.StatusBar = "Procedura in esecuzione : " & Counter
'indi si procede con Next a scorrere prima le righe, e a seguire le colonne
Next c
Next r
[A1].Select 'a fine ciclo si seleziona la cella A1 per ritornare a inizio foglio
Application.StatusBar = False 'questa istruzione cancella il testo dalla barra di stato
End Sub
se non si fosse utilizzata l'ultima istruzione (Application.StatusBar = False), ma questa:
Application.StatusBar = "Procedura completata : " & Counter
questo sarebbe ci che vedremo nella barra di stato:

il tutto crea un buon effetto di macro in esecuzione e termine.


Bisogna fare attenzione al posizionamento delle istruzioni per l'avvio della StatusBar, si corre il rischio che
per vedere una progressione di avanzamento, si rallenti in maniera notevole l'esecuzione della macro
peggiorando il risultato finale in termini di tempo impiegato. Ognuno dovr valutare le proprie
necessit in funzione delle proprie istruzioni. Non chiedetemi aiuto in questo caso, ognuno dovr capire
come usare l'esempio proposto, e risolvere da solo.
Un modo meno problematico e comunque di effetto, quello di usare una UserForm con una Label,
dove sfrutteremo la Caption della Label per gestire due messaggi: Inizio Procedura, e Fine Procedura.
Se avviamo l'UserForm ad inizio macro, usando DoEvents, lasceremo la prosecuzione delle istruzioni fino
alla fine, e indipendentemente dal tempo impiegato, otterremo di avvisare l'utente che la procedura
in esecuzione, e alla fine che terminata, senza interferire con i tempi gi lunghi richiesti dalle vostre
procedure. Vediamo come lavorare:
Impostare la propriet ShowModal della UserForm a False. Questo consente di spostare il focus sul
foglio lasciandolo libero di aggiornarsi. Condizione necessaria per l'aggiornamento o lo scorrimento del
foglio, dipende ovviamente dalle istruzioni contenute nelle vostre procedure. Questa impostazione
crea un problema su Excel 97 che si rifiuta, dando errore, di mostrare una UserForm con ShowModal
impostato a False.
Usiamo l'esempio dei numeri casuali usato sopra, ma con le istruzioni per inizializzare la UserForm:
Sub Test3()
[A1:J500].ClearContents
'sotto: attiviamo la userform e nella Label facciamo apparire la scritta "PROCEDURA
IN 'CORSO", usando la propriet Caption della Label (etichetta)
UserForm1.Show

http://ennius.interfree.it/ Pagina 253


MANUALE VBA X EXCEL
UserForm1.Label1.Caption = "PROCEDURA IN CORSO"
DoEvents ' Non ci scordiamo di trasferire il controllo ad altri processi, quelli sotto:
Dim r
Dim c
For r = 1 To 500
For c = 1 To 10
Randomize

Cells(r, c) = Int(Rnd * 150)


Cells(r, c).Select
Counter = r * c
'DoEvents

Next c
Next r
[A1].Select
'alla fine della procedura, modifichiamo il testo nella Label sull'userform
UserForm1.Label1.Caption = "FINE PROCEDURA"
End Sub
L'efficacia garantita, questa l'immagine iniziale all'avvio della macro:

e questa l'immagine a fine procedura.

Un'altra ProgressBar molto pi efficace come effetto visivo, che comporta un p pi di lavoro per
ottenerla, la propongo nell'esempio sotto. Premetto che l'idea non mia, ma trovata in Internet, e
adattata da me per l'occasione. Viene sfruttata anche in questo caso una UserForm, ma l'effetto visivo
dello stato di avanzamento simula il funzionamento di una reale ProgressBar. Anche questa procedura
non attuabile con la versione 97 di Excel o precedenti. Ma vediamo cosa serve:
una UserForm la cui propriet ShowModal va impostata a False.
una Cornice (Frame) (da inserire nella Userform), la cui propriet SpecialEffect va impostata a 2-
fmSpecialEffectSunken per creare l'effetto incavato.
un'etichetta (Label) (da inserire all'interno del Frame) la cui propriet SpecialEffect va impostata a 1-
fmSpecialEffectRaised per creare l'effetto rilievo.
ed ora vediamo la routine presentata sopra per generare numeri casuali, modificata con le istruzioni
necessarie:
Sub TestBar()
[A1:J500].ClearContents
Dim r
Dim c
RowMax = 500 'assegniamo il valore 500 al numero massimo di righe(con RowMax)
ColMax = 10 'assegniamo il valore 10 al numero massimo di colonne (con ColMax)

For r = 1 To 500 'inizializziamo i cicli come spiegato nella Sub Test


For c = 1 To 10

Randomize
Cells(r, c) = Int(Rnd * 150)
Cells(r, c).Select
Dim Counter As Integer 'dichiariamo la variabile Counter come Integer
http://ennius.interfree.it/ Pagina 254
MANUALE VBA X EXCEL
Counter = Counter + 1 'incrementiamo di 1 il counter ad ogni cella scorsa

Next c 'si passa alla cella della colonna successiva


Percent = Counter / (RowMax * ColMax) 'con Percent prendiamo il valore della
'percentuale delle celle scorse, dividendo il valore di counter per 5000
UserForm1.Show 'chiamiamo la Userform

With UserForm1 ' con la Userform impostiamo il formato (0%) della propriet Caption
del 'Frame del valore rappresentato da Percent
.Frame1.Caption = Format(Percent, "0%")
.Label1.Width = Percent * (.Frame1.Width - 10) ' questa l'istruzione che imposta la
'lunghezza della Label, data appunto dal valore Percent moltiplicato la Lunghezza
del 'Frame meno 10 pt. E' questo che provoca l'effetto avanzamento nella label, il
cui fondo 'stato impostato a rosso
End With 'fine con

DoEvents 'istruzione importante che passa il controllo ad altri processi, passando con
'Next r alla riga successiva per ripetere tutto il ciclo
Next r

[A1].Select

End Sub
Due immagini relative alla Sub TestBar

Chiaramente la velocit dell'avanzamento proporzionale al tempo di esecuzione delle istruzioni.

10/02/04 - Aggiornamento.
Quando invece non sia possibile stabilire il numero di iterazioni legate all'esecuzione di una procedura,
per cui risulta problematico determinare il vettore del valore di incremento di una ProgressBar, ma si
voglia comunque avvisare l'utente che una procedura, a volte molto lunga, in corso, possiamo usare
una cella del foglio di lavoro (magari determinandola a priori, o meglio lasciando una cella libera per
questo scopo), dove far apparire la scritta : "Procedura in esecuzione". Evitiamo in questo modo di
"trafficare" con UserForm, e saremo comunque avvisati che il computer sta lavorando.

http://ennius.interfree.it/ Pagina 255


MANUALE VBA X EXCEL
L'idea, presentata dall'amico Falini Eliano ( falinieliano@virgilio.it ), semplice, facilmente attuabile, e di
sicura efficacia. Si pongono ad inizio e fine della procedura di cui vorremo avvisare, due semplici
blocchi di istruzioni, il primo attiver la cella che avremo destinato allo scopo, scrivendo una frase che
ci avvisi, e magari evidenziamo di giallo la cella stessa, e ne evidenziamo i bordi; il secondo blocco
invece ripristina la cella, eliminando la scritta, il colore e togliendo i bordi. Quando attiveremo la nostra
procedura, verremo avvisati che la procedura in esecuzione, e quando sar terminata sparir
l'avviso e la formattazione della cella ritorner normale.
Simuliamo la Cella B1 come quella da noi destinata, e vediamo i due blocchi di istruzioni:
Sub TuaMacro()
With [B1] 'blocco iniziale nuove istruzioni
.Value = "Procedura in esecuzione :" 'messaggio che appare in B1
.Interior.ColorIndex = 6 'si colora la cella di giallo
.Borders.LineStyle = xlContinuous 'si impostano i bordi alla cella
End With
.....seguono le istruzioni da eseguire

With [b1] 'blocco finale nuove istruzioni


.Value = "" 'si pulisce la cella B1
.Interior.ColorIndex = xlNone 'si toglie il colore giallo
.Borders.LineStyle = xlNone 'si tolgono i bordi
End With
End Sub
Ovviamente potrete decidere se usare il grassetto per la cella, ed eventualmete un colore per il font.
Un grazie ad Eliano.

http://ennius.interfree.it/ Pagina 256


MANUALE VBA X EXCEL
La propriet End. (01/07/03)
Ovvero : come reperire l'ultima cella occupata in una colonna (o in una riga).
Continuano a pervenire domande su come individuare la fine di un elenco di dati, quando si lavora
con elenchi la cui lunghezza variabile, e quindi non si conosce il riferimento alla cella finale. Su sito
esistono moltissime routine che usano End per reperire i range su cui agire, ma probabilmente
opportuno evidenziare l'argomento con una pagina dedicata. Vediamo cosa dice la guida in linea:
Propriet End (da non confondere con l'Istruzione End, che tutta un'altra cosa)
Restituisce un oggetto Range che rappresenta la cella alla fine dell'area contenente l'intervallo di
origine.
la sintassi:
espressione.End(Direction)
dove:
espressione Argomento necessario. Un'espressione che restituisce un oggetto nell'elenco.

Direction Argomento necessario di tipo XlDirection. Specifica la direzione dello spostamento.


XlDirection una delle seguenti costanti:
xlDown - verso il basso
xlToRight - verso destra
xlToLeft - verso sinistra
xlUp - verso l'alto

Ora vediamo di tradurre in "pellegrinese" queste istruzioni, aiutandoci con esempi. Supponiamo di
avere nella colonna B dalla cella B1 fino alla cella B10 un elenco di dati: un'istruzione cos compilata:
Range("B1").End(xlDown).Select
identificherebbe la cella finale dell'elenco, la B10, e la selezionerebbe. Come si nota, noi abbiamo
quindi indicato nell'istruzione la cella iniziale dell'elenco (la B1), e l'istruzione, grazie all'uso di End con la
direzione verso il basso (xlDown), trova la fine dell'ultima cella occupata dell'elenco. Che cosa vuol dire
questo:
che quando non sappiamo quanto sar lungo un elenco, ma vogliamo identificare l'ultima cella
occupata, sufficiente indicare la cella iniziale pi End per trovare senza fallo la cella finale. Come
condizione determinante per il corretto reperimento della cella finale occupata, dovremo disporre di
un elenco SENZA celle vuote nel mezzo. Se nell'elenco ipotizzato prima (B1:B10) avessimo avuto la cella
B8 vuota, senza dati, l'esecuzione dell'istruzione avrebbe identificato la B7 come ultima cella occupata,
trascurando di proseguire nonostante la B9 e la B10 contengano dati. Chiaro?
Uno degli utilizzi classici della propriet End (dell'oggetto Range) la identificazione di un'area dati
quando non sappiamo quanto ampia l'area stessa, quando aggiungendo o togliendo righe di dati
(o colonne), non possiamo determinarne a priori i riferimenti. Parlo dei riferimenti alle celle che
contengono tutta l'area dati, di cui abitualmente usiamo indicare la cella iniziale e la cella finale che
comprendono l'area. Se abbiamo un'area che va dalla prima cella della colonna A alla 22esima cella
della colonna G noi usiamo questa sintassi:
Range("A1:G22").Select - indichiamo appunto gli estremi dell'area per selezionarla.
Ma quando non conosciamo quale sar la cella finale e vorremo usare End per reperirla, dovremo
usare una sintassi diversa, legata a Range non come "oggetto" del foglio di lavoro, ma come "Insieme
Range" (cio un insieme di celle). In quest'ottica, "l'Insieme Range" possiede delle propriet, due delle
quali sono lo stesso Range (come propriet dell'Insieme Range), e la propriet Cells. Servono entrambi
per definire le celle, e possiamo usare indifferentemente l'uno o l'altro purch non mescolati insieme.
Vediamo prima l'utilizzo della proriet Range:
Range("A1", Range("G1").End(xlDown)).Select
intanto vediamo che la differenza maggiore rispetto alla precedente istruzione che non usiamo i due
punti (:) come separatori tra le celle che delimitano l'area, ma una virgola; questo perch la propriet
Range necessita di argomenti (per definire le celle), e come tali devono essere separati dalla virgola.
Comunque vediamo che per identificare il secondo argomento (la cella finale), abbiamo usato End
riferito alla cella iniziale della colonna G, la G1: in questo modo verr cercata l'ultima cella occupata
nella colonna G, e sar questa cella a fornire il secondo riferimento.
Se invece volessimo usare Cells, di cui ricordo brevemente i concetti:
Propriet Cells
Utilizzare Cells(row, column) dove row l'indice di riga e column l'indice di colonna, per restituire una
singola cella.
http://ennius.interfree.it/ Pagina 257
MANUALE VBA X EXCEL
dovremmo usare questa istruzione:
Range(Cells(1, 1), Cells(1, 7).End(xlDown)).Select
dove il primo argomento va letto come cella riga 1 colonna 1 (quindi A1), e il secondo argomento
come cella riga 1 colonna 7 (e quindi G1). Anche in questo caso gli argomenti sono separati da
virgola, e al secondo argomento stata "affibbiata" End per reperire l'indice riga dell'ultima cella nella
stessa colonna (la 7) che conterr i dati.
Impostando opportunamente le direzioni, potremo cercare sia celle in righe che in colonne, sia verso il
basso sia verso l'alto, che a destra o a sinistra, dipender da come avremo impostato le nostre tabelle
dati. Ci che poi faremo con le aree identificate e selezionate non riguarda questa pagina, ma
propongo un esempio, peraltro riscontrabile scaricando il file "TraduttoreFunzioni2000.zip" (vedi articolo
"Traduttore Funzioni"), dove, dovendo prevedere l'inserimento di dati, nell'ordinamento alfabetico dei
dati, viene usata la Propriet End per reperire tutta l'area da ordinare. In questo caso, dovendo
ordinare secondo una chiave specifica, e volendo che i dati correlati alla chiave, sulle stesse righe, si
muovano insieme, vengono usate delle variabili (x e y) alle quali assegnare gli indirizzi (o riferimenti)
delle celle che comprendono l'area. Alla prima variabile assegniamo il range che va dalla cella A1 alla
C1, prendendo gli indirizzi (Address) ; le tre colonne che comprendono l'area dati:
y = Range("A1:C1").Address

con la seconda variabile reperiamo, tramite End sulla prima colonna, l'indirizzo (Address) dell'ultima
cella occupata:
x = Range("A1").End(xlDown).Address
poi selezioniamo tutta l'area usando i riferimenti (indirizzi o Address) ora "presenti" nelle due variabili :
Range(y, x).Select
Se andiamo a controllare (con "imposta punto di interruzione" e successive pressioni sul tasto F8
possiamo scorrere le istruzioni riga per riga), vediamo infatti che in Range(y, x) , la y corrisponde a
"$A$1:$C$1"

e la x corrisponde a "$A$267"

e quindi l'area selezionata sar:

http://ennius.interfree.it/ Pagina 258


MANUALE VBA X EXCEL

E queste le istruzioni basate come chiave d'ordinamento sulla colonna A:


Sub ordinaitaliano()
Worksheets("Foglio2").Select
Dim x, y
y = Range("A1:C1").Address
x = Range("A1").End(xlDown).Address
Range(y, x).Select
Selection.Sort Key1:=Range("A1"), Order1:=xlAscending, Header:=xlGuess, _
OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom
End Sub
Se invece, anche per le colonne non sapessimo quale sar l'ultima che ci consenta di definire un
riferimento preciso, potremo usare End dando come direzione xlToRight (verso destra) riferito alla cella
iniziale (A1), e baster sostituire questa riga nella routine appena vista, per ottenere la nostra selezione:
y = Range("A1", Range("A1").End(xlToRight)).Address
oppure, usando la propriet Cells
y = Range(Cells(1, 1), Cells(1, 1).End(xlToRight)).Address
cio, in entrambi i casi, stiamo dicendo : y uguale al Range che parte dalla cella A1 fino all'ultima
cella occupata partendo dalla A1, andando verso destra (quindi stessa riga).
Credo di avere fatto un p pi di luce sull'argomento.

http://ennius.interfree.it/ Pagina 259


MANUALE VBA X EXCEL
La propriet Offset (relativa all'oggetto Range).
Scarto, scartamento o spostamento, in Vba si chiama Offset .La sua sintassi :
ActiveCell.Offset(0, 1).Select
oppure
Range("Tuorange").Offset(0, 3).Value
Un foglio di lavoro composto da righe e colonne, e le celle vengono identificate dal loro "riferimento",
cio dalla lettera di colonna e dal numero di riga all'incrocio dei quali si trova una cella. Quindi la cella
che si trova nella terza riga all'incrocio con la seconda colonna avr il riferimento B3. (come in una
"battaglia navale"). Si usa mettere nel riferimento, per prima la lettera che identifica la colonna, seguita
senza spazi dal numero di riga. E' con questo sistema, quello dei riferimenti, che Excel ci consente di
lavorare con i dati che saranno contenuti nelle celle. Usiamo infatti dei riferimenti quando compiliamo
le nostre formule o le nostre macro, in questo modo "miriamo" con precisione alle celle che ci
interessano. Esistono tuttavia situazioni nelle quali, pur "mirando" ad una cella, avremo bisogno di dati
che si trovano non nella cella "mirata", ma in altre celle del foglio di lavoro, in genere contenenti dati
correlati al dato contenuto nella cella "mirata". Possiamo fare un esempio: considerando di avere una
tabella con un elenco di nomi (posti nelle righe della colonna A), per ogni nome: l'indirizzo (nella
colonna B), la citt (nella colonna C) il numero di telefono (nella colonna D). E di volere, dato un
determinato nome, il suo numero di telefono. Cosa faremo? cercheremo con una procedura, il nome
voluto, lo selezioneremo, e con l'uso di Offset andremo a pescare il numero di telefono che si trova
sulla stessa riga, ma tre celle a destra rispetto alla cella in quel momento selezionata, per cui l'istruzione
risulterebbe cos:
ActiveCell.Offset(0, 3).Value
Ci che faremo poi col numero di telefono cos trovato non riguarda questa pagina, ma vediamo
invece di capire l'istruzione Offset sopra esemplificata : abbiamo stabilito una cella di base (ActiveCell)
e abbiamo detto ad Excel di volere il valore contenuto nella cella che si trova sulla stessa riga ma tre
celle a destra rispetto alla cella selezionata. E questo l'abbiamo detto usando dei numeri : in una
istruzione Offset, il primo numero identifica sempre la riga, il secondo numero identifica la colonna,
rispetto ad una cella di riscontro. Abbiamo usato quindi lo Scarto. Le direzioni di Scostamento rispetto
alla cella base, sono : a destra (positivo), a sinistra (negativo), sopra (negativo) o sotto (positivo).
Utilizzando quindi un numero (positivo o negativo) per indicare la riga e un numero (negativo o
positivo) per indicare la colonna, rispetto alla cella base, "pescheremo" il dato nella cella che ci
interessa. Sotto, uno specchietto per capire come usare i riferimenti con Offset. Impostata la cella D7
come cella base, se volessimo "pescare" i dati nella cella F8, useremmo Offset(1, 2) (una riga sotto,
due colonne a destra) rispetto a D7. (per i riferimenti positivi non occorre usare il +, per quelli negativi
necessariamente andr usato il - ) Con lo 0 (zero) si indica : nessun scarto, cio stessa riga op. stessa
colonna.

http://ennius.interfree.it/ Pagina 260


MANUALE VBA X EXCEL
Proteggere e/o Limitare la durata nell'uso di una cartella Excel.
In generale con "protezione" possiamo intervenire per proteggere un foglio di lavoro o tutta la cartella.
Le modalit per l'utilizzo di queste "protezioni" sono note e comunque facilmente leggibili e apprendibili
dai vari men. Abbiamo poi la possibilit di proteggere anche il codice in vba (macro) attraverso
l'editor di visual basic, scegliendo dal men dell'editor, "Strumenti/Propriet di VBA Project... e nella
finestra che appare, scegliere "protezione", spuntando la casella "proteggi progetto dalla
visualizzazione", e assegnando una password. Fatto questo necessario salvare e chiudere la cartella :
alla riapertura, se vorremo accedere al codice, dovremo digitare la password. Tutti questi metodi sono
comunque inservibili se ci vogliono forzare le protezioni : esistono in commercio dei programmi che
hanno il preciso compito di individuare e fornirci le password usate a protezione di fogli, cartelle e
progetto vba, rendendo quindi inutili i nostri sforzi per proteggerci il lavoro. Per fortuna la maggior parte
degli utenti di Excel rientra nell'utenza standard (non fraintendetemi), cio di coloro che, per uso
casareccio o di ufficio, usano excel senza malizia e senza sentirsi degli pseudoHacker. Le protezioni, per
questi "onesti cittadini", servono e funzionano egregiamente.
E' possibile peraltro munire i nostri lavori di "protezioni" personalizzate, oltre a quelle standard fornite da
Excel, protezioni impostate tramite istruzioni in codice vba, che possono essere molto articolate e
prevedere anche "scadenze" o "durate". Sarebbe in questo modo possibile distribuire dei lavori in
versione "Trial" che se, non confermati, scadranno e non sar possibile utilizzarli. Si pu scegliere una
scadenza a data oppure per numero di volte. Vediamo entrambi i casi, facendo prima alcune
considerazioni. Non esiste una protezione inviolabile per gli "smanettoni", esistono solo protezioni valide
per "pellegrini" "non smanettoni" (la maggioranza, per fortuna.)
Excel quando apre un file che contiene macro, mostra sempre una finestra che chiede se vogliamo
"Attivare" o "Disattivare" le macro (questo solo se NON abbiamo scelto in "Protezione/Macro" "Bassa
protezione", in questo caso i file vengono aperti senza nessuna richiesta e con l'attivazione delle
macro).
Disattivare le macro ci consente di poter scorrere i fogli, di scoprire i fogli eventualmente nascosti, di
girare in lungo e in largo, compreso l'accesso al codice, di poter modificare o eliminare istruzioni e/o
dati presenti nei fogli (quei dati che vedremo pi avanti, e che servirebbero a limitare l'uso del nostro
programma). Al tempo stesso per, non sar possibile attivare le istruzioni di nessuna macro e quindi
non potremo gestire il lavoro se impostato con delle macro.
Ci spostiamo tra i fogli perch possiamo selezionare le "linguette" dei fogli (le WorksTab). Se le "linguette"
non fossero visibili non potremo mai usarle e quindi spostarci. Esiste un istruzione, CHE SI ATTIVA anche se
disabilitiamo le macro, e che consente appunto di non far vedere le "linguette", e senza linguette, non
si va da nessuna parte, neanche quindi sul foglio dove avremo inserito le nostre istruzioni "segrete". Per
poterci spostare tra i fogli, useremo dei pulsanti, associati a delle macro. Ma se disabilitiamo le macro,
non ci potremo spostare, giusto? E quindi continuiamo a proteggerci. Sar poi sufficiente NON
prevedere un pulsante che porti al nostro foglio "segreto", e chiunque, anche abilitando le macro, non
potr mai accedervi. A questo punto, sar sconsigliato "nascondere" il foglio "segreto", proprio perch
dal men "Formato/Foglio" sarebbe possibile usare "Scopri foglio" che un'azione che selezionerebbe il
foglio cos scoperto, mettendolo in primo piano, mostrando a tutti ci che vogliamo invece tenere
nascosto.
Ricapitoliamo le operazioni da fare:
munire l'accesso al codice vba di una password
disabilitare le "linguette" dei fogli
predisporre i pulsanti per spostarci sui fogli permessi
(per attivare la protezione del codice e disabilitare le linguette occorre salvare, chiudere e riaprire il
foglio, resteranno poi sempre attivi) vediamo le istruzioni da compilare:
Nell'evento WorkBook_Open(), per disabilitare le linguette su tutti i fogli:
ActiveWindow.DisplayWorkbookTabs = False
In un Modulo nell'editor di vb, creare le macro per spostarsi tra i fogli:
Sub apriuno()
Sheets(1).Select
End Sub
Sub apridue()
Sheets(2).Select
End Sub
preparare tante macro per quanti saranno i fogli su cui navigare, TRANNE quella che porterebbe al
foglio che vorremo come "segreto". In ogni foglio predisporremo tanti pulsanti per quanti saranno i fogli,
http://ennius.interfree.it/ Pagina 261
MANUALE VBA X EXCEL
in modo che da qualunque foglio si possa andare su qualunque altro foglio. Ogni pulsante sar
associato alla macro di pertinenza.
A questo punto ci troveremo in questa condizione: se abilitiamo le macro, andremo solo sui fogli di cui
esistono i pulsanti, se NON abilitiamo le macro, non andremo da nessuna parte e le linguette non
saranno comunque visibili. Per accedere al codice avremo bisogno di una password : la protezione
in atto.
Ed ora vediamo i due sistemi per la "Prova a Scadenza" del nostro lavoro.
Prova a tempo. Si basa sulla registrazione della data di primo accesso, e dopo un periodo stabilito
(normalmente 15 o 30 giorni), non sar pi possibile l'uso del lavoro.
Useremo il nostro foglio "nascosto" per queste registrazioni, e predisporremo le opportune istruzioni,
sempre sfruttando l'evento WorkBook_Open(). Supponiamo di usare il foglio3. Avremo bisogno di un
contatore che abiliti l'attivazione della registrazione della data di prima apertura (A1 e A2), metteremo
in C1 la data che otterremo con la funzione =OGGI(), faremo copiare via codice solo la data e non la
funzione, in D1, e in E1 metteremo la data + il tempo in giorni destinato al periodo di prova. (Abbiamo
bisogno che questa operazione sia fatta una volta sola, per questo usiamo un contatore), avremo poi
bisogno di un'istruzione che controlli se la data odierna (in C1) sar maggiore della data posta in E1
(limite massimo di prova) o minore della data posta in D1 (limite di inizio prova) che faremo invece
aggiornare ad ogni chiusura cartella. Se qualcuno, da pannello di controllo, regolasse la data a un
certo giorno antecedente, provocherebbe la chiusura della cartella cos come avverr se superata la
data di termine prova. Vediamo le istruzioni e le spiegazioni:
Foglio3, cella A1 inserire zero (0) - cella C1 inserire =OGGI()
Private Sub Workbook_Open()
'si disabilitano le linguette
ActiveWindow.DisplayWorkbookTabs = True
'si inizializza il contatore incrementando A2 di 1 rispetto a A1 (che zero)
Sheets(3).Range("A2") = Sheets(3).Range("A1") + 1
'si rende A1 uguale a A2 (ora A1 uguale a 1)
Sheets(3).Range("A1") = Sheets(3).Range("A2")

'si controlla se A1 uguale a 1 (e quindi solo in questo caso si eseguono queste


istruz.)
If Sheets(3).Range("A1").Value = 1 Then
'allora si copia la data di C1 (oggi) in D1
Sheets(3).Range("D1") = Sheets(3).Range("C1")
'e si incrementa la data C1 del valore scelto (15) in E1
Sheets(3).Range("E1") = Sheets(3).Range("C1") + 15
End If

'ora inizia il controllo sulle date: se la data di oggi maggiore di quella scritta in E1
If Sheets(3).Range("C1").Value > Sheets(3).Range("E1") Then
'allora si chiude l'applicazione e quindi anche Excel
Application.Quit
End If
'se la data di oggi inferiore alla data registrata in D1 (che corrisponde alla prima
esecuzione del programma (nel caso che qualche "astuto" retroceda la data in
pannello di controllo)(legata anche all'istruzione posta in WorkBook_BeforeClose)
If Sheets(3).Range("C1").Value < Sheets(3).Range("D1") Then
'allora si chiude l'applicazione e quindi anche Excel
Application.Quit
End If
End Sub

E queste le istruzioni in chiusura della cartella:

Private Sub Workbook_BeforeClose(Cancel As Boolean)


'questo controllo aggiorna la data che si trover in D1, e che serve di controllo alla
routine precedente, riducendo i giorni (all'indietro) di prova: se la data di oggi
superiore alla data presente in D1, D1 viene aggiornato con la data di oggi. Se il
http://ennius.interfree.it/ Pagina 262
MANUALE VBA X EXCEL
solito "astuto" metter indietro la data, scatta la chiusura dell'applicazione.
If Sheets(3).Range("C1") > Sheets(3).Range("D1") Then
Sheets(3).Range("D1") = Sheets(3).Range("C1")
End If
'questa istruzione garantisce che in uscita venga comunque salvata la cartella con
le registrazioni sulle date e sul contatore.
ThisWorkbook.Save

End Sub
Volendo possibile munire l'istruzione di un messaggio che avvisa quanti giorni mancano alla
scadenza. (usando la fuzione DateDiff)

Prova a numero di aperture. Si basa sul conteggio di quante volte viene aperta la cartella del nostro
lavoro. Risulta pi semplice da impostare rispetto alla precedente (questione di opinioni) e anche qui
useremo un contatore che inizializzeremo partendo da zero (A1), e decideremo il numero di aperture
consentite. Come sopra sfruttiamo il foglio3 con le celle A1 e A2, la durata sar di 15 aperture. (non
ripeto le istruzioni gi fornite nella precedente routine)
Private Sub Workbook_Open()
ActiveWindow.DisplayWorkbookTabs = False

Worksheets(3).Range("A2") = Worksheets(3).Range("A1") + 1
Worksheets(3).Range("A1") = Worksheets(3).Range("A2")
'sotto: con X prendiamo il numero di volte rimaste, con una semplice sottrazione
X = 15 - Worksheets(3).Range("A2").Value

If Worksheets(3).Range("A2").Value >= 15 Then


Application.Quit
Else
'avvisiamo con un messaggio che riporta il numero di prove restanti
MsgBox "Hai ancora " & X & " prove da fare"
End If
End Sub

e questa l'istruzione in chiusura cartella :

Private Sub Workbook_BeforeClose(Cancel As Boolean)


ThisWorkbook.Save
End Sub

Alcuni consigli: si possono inserire quanti fogli vorremo, per usare un foglio come "segreto"; non detto
che le celle usate per le protezioni siano necessariamente sul foglio3, potrebbero stare sul dodicesimo
di venti fogli, per esempio. Non scordarsi dei pulsanti per la selezione dei fogli.

http://ennius.interfree.it/ Pagina 263


MANUALE VBA X EXCEL
Calcolare provvigioni a scalare con il Vba. (04/04/03)
Ancora un esercizio con un calcolo provvigionale, con utilizzo di una Funzione Utente oppure di una
routine.
A differenza del paragrafo precedente "Provvigioni differenziate" dove le provvigioni si modificavano in
funzione dell'importo della fattura e dello sconto concesso al cliente, restando computate per intero
con l'aliquota provvigionale prevista (in toto), questa volta ci occupiamo di provvigioni a scalare in
funzione dello scaglione di importo fattura (al di l dello sconto concesso, che considereremo
comunque a parte).
Ma riassumiamo le diversit:
nell'esempio precedente, se variava l'importo fattura (5000=8% - 25000=4% - oltre 25000=2,5%) si
assegnava la provvigione prevista su tutto l'importo fattura. per cui la provvigione spettante su una
fattura di 10000, sarebbe stata del 4% e cio di 400 . (ripeto, senza tenere conto dello sconto cliente
che comunque avrebbe poi contribuito a variare l'aliquota in questo caso del 4%).
In questo esercizio invece useremo il concetto che troviamo anche nella sezione "Formule", paragrafo
"tabella calcolo IRPEF", dove le aliquote vengono applicate secondo il sistema fiscale: fino ad una
certa cifra, una certa aliquota, da questa cifra fino ad un'altra, un'altra aliquota sulla cifra eccedente
la prima cifra, e cos via. Tutti conosciamo il sistema di tassazione attualmente in vigore.
Applicheremo quindi una provvigione dell'8% fino a 5000, del 4% sulla cifra tra 5000 e 25000, e del 2,5%
sulle cifre oltre 25000. Sommeremo poi le tre provvigioni, nel caso presenti, in modo da ottenere un
totale provvigioni da assegnare all'agente. Per rendere il tutto il pi simile all'esercizio precedente,
anche qui valuteremo lo sconto concesso al cliente, in modo da ridurre la provvigione assegnata allo
scaglione di pertinenza. Non ripeto queste condizioni che sono leggibili nel paragrafo su citato.
Per meglio presentare questo esercizio, presento due soluzioni, entrambe portano allo stesso risultato.
La prima una macro, la seconda l'ho impostata come Funzione, in modo da poterla usare
direttamente sul foglio di lavoro. Vediamo la macro: nelle istruzioni esemplifico identificando l'origine
del campo importo fattura e sconto concesso, ipotizzando che i due valori si trovino il primo in A1
(importo) e il secondo in B1(sconto). Uso ancora due variabili per assegnare le due costanti relative agli
scaglioni che determinano l'assegnazione delle aliquote provvigionali, base (per lo scaglione fino a
5000) e basedue (per lo scaglione da 5000 25000) e oltre. L'identificazione degli scaglioni di pertinenza
delle provvigioni le identifico con dei cicli If..Then...Else. Una volta assegnato alle variabili b - c - d gli
importi degli scaglioni, uso Select Case per diversificare le due condizioni degli sconti ( fino a 5% o
maggiore di 5%). All'interno di questi due casi, eseguo i conteggi di assegnazione delle provvigioni. Il
risultato lo riporto in una messagebox, ma pu essere tranquillamente assegnata una cella dove
restituire il risultato.
Sub ProvvScalare()
'assegnazione alle variabili sconto e importo dei valori contenuti nelle due celle
sconto = Range("B1").Value
importo = Range("A1").Value
'assegnazione alle variab. base e basedue delle costanti dei valori degli scaglioni
base = 5000
basedue = 25000
'controllo se base (5000) maggiore o uguale a importo (Range("A1"))
If base >= importo Then
'nel qual caso assegno alla variab. minimo lo stesso valore di importo
minimo = importo
Else
'in caso contrario rendo la variab. minimo uguale a base (5000)
minimo = base
End If
'inizio l'assegnazione alle variab, b - c - d dei valori che corrisponderanno agli importi
'relativi ai vari scaglioni
b = minimo
If basedue >= importo Then
c = importo - b
Else
c = basedue - b
End If
d = importo - (c + b)
http://ennius.interfree.it/ Pagina 264
MANUALE VBA X EXCEL
'si controlla che esistano gli importi relativi ai tre scaglioni, altrimenti si assegna zero
alla 'variabile dello scaglione. Se il valore fosse nullo (non esistesse), si genererebbe
un errore 'nelle istruzioni successive dove si eseguono i calcoli su questi valori.
If b < 0 Then b = 0
If c < 0 Then c = 0
If d < 0 Then d = 0

'inizio il controllo sugli sconti, usando Select Case, il primo caso che lo sconto sia 5
o 'inferiore a 5
Select Case sconto
Case Is <=5
'si assegnano le aliquote provvigionali i % a tre variabili: pp=prima provv -
sp=seconda provv. - tp=terza provvigione
pp = 8 / 100
sp = 4 / 100
tp = 2.5 / 100
'indi si assegnano a tre variabili (F-G-H) i valori che si ottengono dalla moltiplicazione
degli scaglioni di importi per le aliquote provv.
F = b * pp
G = c * sp
H = d * tp
'poi restituisco il totale delle provvigioni cos ottenute attraverso un messaggio, ma il
risultato lo potremmo tranquillamente inviare ad una cella, esempio:
'Range("D1")=F+G+H
MsgBox F + G + H
'ora iniziamo i conteggi nel secondo caso, cio che lo sconto sia maggiore del 5
Case Is > 5
'assegnazione alle variabili delle aliquote derivanti dalla differenza dello sconto
maggiore con lo sconto 5, diviso per 1/3, e sottratto alla provvigione normalmente
prevista
pp = 8 - ((sconto - 5) / 3)
sp = 4 - ((sconto - 5) / 3)
tp = 2.5 - ((sconto - 5) / 3)
'controlliamo che il valore ora assegnato ad ogni provvigione non sia inferiore a 1,5,
nel qual caso lo rendiamo uguale a 1,5
If pp < 1.5 Then pp = 1.5
If sp < 1.5 Then sp = 1.5
If tp < 1.5 Then tp = 1.5
'e poi anche qui otteniamo l'assegnazione alle tre variabili (F-G-H) dei valori scaturiti
dalla moltiplicazione degli importi per le aliquote rese in % ( diviso 100 )
F = b * pp / 100
G = c * sp / 100
H = d * tp / 100
'e si finisce come nel caso precedente
MsgBox F + G + H
'questa istruzione sotto necessaria quando si usa il costrutto della selezione dei casi
(Select Case), alla fine delle istruzioni si deve inserire: fine delle selezioni (End Select)
End Select
'fine della routine
End Sub
Bene, questa routine finita, e potr essere associata ad un pulsante per averla funzionante sul foglio
di lavoro. Va da se che se il conteggio provvigionale dovesse interessare un elenco di dati, sar
necessario inserire nella routine le istruzioni necessarie a reperire gli importi, gli sconti, e restituire le
provvigioni spettanti con, per esempio, un'istruzione come quella presentata alla fine del paragrafo
precedente.
Ora vediamo le stesse istruzioni della macro ProvvScalare() trasformate in Funzione Utente, cio
personalizzata; in questo caso sconto e importo diventeranno argomenti della funzione stessa che
quindi ci permetter o di essere richiamata direttamente sul foglio di lavoro, come una qualsiasi
http://ennius.interfree.it/ Pagina 265
MANUALE VBA X EXCEL
funzione di Excel, oppure di poter essere richiamata in un'altra macro come nell'esempio della pagina
precedente. Ma vediamo la funzione. Non sto ad inserire commenti perch sono gli stessi della macro:
Function ProvvScalare(importo, sconto) As Double
base = 5000
basedue = 25000
If base >= importo Then
minimo = importo
Else
minimo = base
End If
b = minimo
If basedue >= importo Then
c = importo - b
Else
c = basedue - b
End If
d = importo - (c + b)
If b < 0 Then b = 0
If c < 0 Then c = 0
If d < 0 Then d = 0

Select Case sconto

Case Is <= 5
pp = 8 / 100
sp = 4 / 100
tp = 2.5 / 100
F = b * pp
G = c * sp
H = d * tp
ProvvScalare = F + G + H

Case Is > 5
pp = 8 - ((sconto - 5) / 3)
sp = 4 - ((sconto - 5) / 3)
tp = 2.5 - ((sconto - 5) / 3)
If pp < 1.5 Then pp = 1.5
If sp < 1.5 Then sp = 1.5
If tp < 1.5 Then tp = 1.5
F = b * pp / 100
G = c * sp / 100
H = d * tp / 100
ProvvScalare = F + G + H
End Select

End Function
Gli argomenti della funzione: importo e sconto non saranno altro che il riferimento alla cella che
contiene l'importo fattura il primo, e una cella che destineremo a contenere il valore dello sconto
concesso, il secondo. Questa funzione potr essere inserita in una cella, esempio la C1, visto che nel
problema in esempio si citava la A1 e la B1, e sar : =ProvvScalare(A1;B1) ed in C1 avremo il risultato
della formula. Se l'elenco fosse su pi righe, sar sufficiente usare il "trascinamento" per copiare la
formula dalla C1 nelle celle sottostanti, ed il bravo Excel provveder ad aggiornare i riferimenti alle
celle di pertinenza.
Due precisazioni: nel campo "sconto" (colonna B) dovr essere inserito lo sconto in formato numero e
NON percentuale ( 5 e non 5%); i campi importo fattura (colonna A) e provvigioni (colonna C)
dovranno avere il formato celle a numero con 2 decimali.

http://ennius.interfree.it/ Pagina 266


MANUALE VBA X EXCEL
Calcolare provvigioni differenziate con il Vba. (03/04/03)
Utilizzo di una Funzione Utente per il calcolo (vedi in questa sezione: Funzioni Utente in vba).
Rifacendomi al problema esposto nella sezione Formule, articolo: "Condizioni SE a raffica", vorrei
presentare una soluzione a quel problema, che comunque riporto di seguito, realizzata mediante l'uso
di istruzioni in vba. Dovendo realizzare una routine che si presume interessare molteplici celle (visto che
un calcolo provvigionale su importi fattura in genere lo si esegue su un riepilogo fatture generale o per
agente) ho ritenuto pi sfruttabile utilizzare una Funzione personalizzata. In questo modo sar possibile
scegliere le celle destinate a contenere detta funzione che sar usata come si usa una tradizionale
Funzione di un foglio di lavoro, facendo precedere al nome della funzione il segno = e indicando i
riferimenti alle celle che formeranno gli "argomenti" della funzione.
Ma riassumiamo il problema:
"un rappresentante prende delle provvigioni in %
Come dati ho il valore in della fattura (A1) e lo sconto che il rappresentante ha fatto (B1)
se fattura <5000 prende l'8%
5000-25000 prende il 4%
>25000 prende il 2,5%
Se applica fino al 5% di sconto sulla fattura il rappresentante prende la provvigione piena (l'8% o il 4% o
il 2,5% a seconda dell'importo della fattura)
ma se applica sconti >5% la sua provvigione dovr essere decurtata di 1/3 dello sconto oltre il 5%
Ultimissima cosa: minimo provvigionale=1,5% ".
Ci troviamo quindi con
3 aliquote provvigionali che variano al variare dell'importo fatturato.
queste aliquote restano immutate se lo sconto massimo concesso al cliente il 5%.
nel caso sia superiore, dovr essere fatta la differenza tra lo sconto concesso il 5% max previsto; di
questa differenza dovr essere preso 1/3 e sottratto alla provvigione di pertinenza in funzione
dell'importo fattura.
e comunque la provvigione non potr essere inferiore al 1,5%
Abbiamo quindi a che fare con una raffica di SE ( If ). Per sveltire l'esecuzione del codice, che
dovrebbe leggere tutte le condizioni ( If ) immesse, facciamo uso dell'istruzione Select Case che rende
la lettura delle condizioni pi veloce, affidandogli il compito di decidere se lo sconto sar inferiore o
uguale a 5% oppure maggiore, ed annidare le istruzioni If all'interno dei Case. Come gi visto nella
pagina "Funzioni Utente in vba", assegneremo un nome alla funzione, seguito, tra parentesi, dai nomi
che rappresentano gli argomenti della funzione. Per chi ha un minimo di conoscenza in vba, non sar
difficile "leggere" le istruzioni impiegate; si basano su valori assegnati alle provvigioni, e su variabili (uso
lettere dell'alfabeto) che raccolgono le varie condizioni. Non ho previsto argomenti "legati" alle
provvigioni in quanto in genere, una volta stabilite le provvigioni, queste restano tali, e allora tanto vale
inserirle nella funzione ( la funzione con meno argomenti risulta pi "leggera"). Questa la funzione:
Function Provv(cifra, sconto) As Double
Select Case sconto
Case 5
If cifra <= 5000 And sconto = 5 Then X = 8
If cifra >= 5001 And cifra <= 25000 And sconto = 5 Then X = 4
If cifra >= 25001 And sconto = 5 Then X = 2.5
Case Is > 5
y = 8 - ((sconto - 5) / 3)
z = 4 - ((sconto - 5) / 3)
w = 2.5 - ((sconto - 5) / 3)
If y < 1.5 Then y = 1.5
If z < 1.5 Then z = 1.5
If w < 1.5 Then w = 1.5
If cifra <= 5000 Then X = y
If cifra >= 5001 And cifra <= 25000 Then X = z
If cifra >= 25001 Then X = w
End Select
Provv = (X * cifra) / 100
End Function
Gli argomenti cifra e sconto non saranno altro che il riferimento alla cella che contiene l'importo fattura
il primo, e una cella che destineremo a contenere il valore dello sconto concesso, il secondo. Questa
http://ennius.interfree.it/ Pagina 267
MANUALE VBA X EXCEL
funzione potr essere inserita in una cella, esempio la C1, visto che nel problema su esposto si citava la
A1 e la B1, e sar : =Provv(A1;B1) ed in C1 avremo il risultato della formula. Se l'elenco fosse su pi righe,
sar sufficiente usare il "trascinamento" per copiare la formula dalla C1 nelle celle sottostanti, ed il
bravo Excel provveder ad aggiornare i riferimenti alle celle di pertinenza.
Se poi si volesse, nel caso di elenchi lunghi, affidarsi ad una macro per inserire la funzione nelle celle
previste, sar possibile richiamare la funzione assegnandogli gli argomenti, come faremmo con
qualsiasi altra funzione. Questo un esempio: elenco importo fatture nella colonna A, nella B gli sconti
concessi, a partire dalla riga 2. Nella colonna C vorremo il conteggio provvigioni. la macro:
Sub provvigioni()

Dim CL As Object

For Each CL In Range("C2:G200")


'definizione con "importo" dell'importo fattura che si trova stessa riga, 2 colonne a
sinistra '(la A), rispetto a CL, primo argomento della funzione Provv
importo = CL.Offset(0, -2).Value
'definizione con "scon" del valore dello sconto che si trova stessa riga, 1 colonne a
sinistra '(la A), rispetto a CL, secondo argomento della funzione Provv
scon = CL.Offset(0, -1).Value
'se la cella CL vuota, allora
If CL = "" Then
'nella cella CL si mette il risultato della funzione: la provvigione spettante
CL = Provv(importo, scon)
End If
Next
End Sub
non ho inserito un controllo se l'importo fattura o lo sconto non sono presenti, perch in caso manchino
dati il risultato della funzione sar zero.
Due precisazioni: nel campo "sconto" (colonna B) dovr essere inserito lo sconto in formato numero e
NON percentuale ( 5 e non 5%); i campi importo fattura (colonna A) e provvigioni (colonna C)
dovranno avere il formato celle a numero con 2 decimali.

http://ennius.interfree.it/ Pagina 268


MANUALE VBA X EXCEL
Utilizzare dell'istruzione Clear.
Anche se semplice, a fronte di alcune domande rivoltemi, vorrei suggerire come usare l'istruzione
"CLEAR", cio : "pulisci" o se preferite, "vuota". Una prima precisazione v fatta nel distinguo tra "Clear" e
"ClearContents" .
Clear "pulisce" la/le celle da ogni contenuto, numeri, lettere ecc., ma elimina anche formule presenti
nella/e celle, oltre a formato bordi, colore font, colore cella, praticamente tutto.
Sub Cancella()
Range("A2:C23").Clear
End Sub
ClearContents invece "pulisce" la/le celle solo dei valori e delle eventuali formule, lasciando inalterate
le altre eventuali impostazioni.
Sub Cancella()
Range("A2:C23").ClearContents
End Sub
E' possibile usare uno dei due comandi anche per pulire intere righe, o intere colonne, oppure celle
non contigue, "sparse" sul foglio, con le seguenti rispettive istruzioni:
pulire, ad esempio, tutta la riga 8: Rows("8:8").ClearContents
pulire, ad esempio, tutta la colonna C : Columns("C:C").ClearContents
Pulire, ad esempio, le celle B1, F4, A10,G3 Range("B1,F4,A10,G3").ClearContents

http://ennius.interfree.it/ Pagina 269


MANUALE VBA X EXCEL
Registrare dei dati in un archivio dati.
In questa esercitazione ci riallacciamo a quanto contenuto nel paragrafo precedente dove si cercano
dei totali tra due date, in un archivio dati. Questa volta ci occupiamo di come trasferire i dati
provenienti da una zona di registrazione, nell'archivio. In questo esempio, simuliamo di avere un range
di celle dove a fine giornata inseriremo il totale incassato, diviso per prodotto. Che il totale si inserisca
manualmente oppure sia il risultato di una somma, non cambia niente: ci troveremo sempre con una
riga di celle dove avremo dei dati, divisi per colonna, ed questa riga con i totali giornalieri divisi per
prodotto che noi vorremo registrare in un archivio (una tabella) che contenga i totali per data, in
modo da poter successivamente consultare questo archivio, per indagini sul totale incassi relativi a
periodi di date. Il funzionamento delle procedure semplice: un Copia/Incolla con ricerca della
destinazione basata su una chiave di ricerca: la data del giorno. Useremo una cella dove inseriremo la
funzione =OGGI() per aggiornare automaticamente la data del giorno all'apertura del foglio di lavoro
(nell'esempio la D1). Disporremo la zona di raccolta dei dati da registrare (nell'esempio le celle che
vanno da B3 a F3 comprese), alla quale assegneremo un Nome (dal menu Inserisci/Nome/definisci) (in
questo esempio : Importo) cos nelle istruzioni useremo il nome anzich la definizione del range
interessato. Disporremo sullo stesso foglio (ma potremo farlo anche su un'altro foglio) una tabella che
sar l'archivio in cui registrare i totali giornalieri. In questa tabella useremo la prima colonna a sinistra
(nell'esempio la colonna A) per predisporre le date di registrazione. Lo potremo fare agevolmente,
baster scrivere le prime due date con cui inizia il nostro archivio, selezionarle entrambi e, usando il
"trascinamento", scorrere verso il basso: Excel, capendo che intendiamo ottenere una "serie",
provveder a inserire tutte le date in progressione, fino a quando decidiamo di fermarci. Sotto
vediamo l'effetto "trascinamento" dove veniamo avvisati del valore (data) raggiunto alla fine della
selezione (NB: il formato celle dovr essere impostato a Data, con lo stesso formato usato per la cella
D1):

Per le istruzioni useremo una Funzione Utente per la ricerca della riga corrispondente alla data odierna
(nella colonna A dell'archivio) ed una procedura che, una volta trovata la riga, selezioni la cella
immediatamente a destra della cella con la data trovata, e provveda a Copiare (prelevare pi
giusto) i dati dalla zona che abbiamo chiamata Importo (Range B3:F3) e la Incolli (inserisca pi
giusto) nella cella in quel momento attiva. Assegneremo ad un pulsante la macro creata, ed il gioco
fatto: a fine giornata premeremo il pulsante e i dati verranno archiviati alla data corrispondente. Sotto
un'immagine dell'esempio preparato:

E queste le istruzioni, per prima la funzione per la ricerca:


Function cercadata(Intervallo, valore)

http://ennius.interfree.it/ Pagina 270


MANUALE VBA X EXCEL
For Each c In Intervallo
If c.Value = valore Then
Y = c.Row
Exit For
End If
Next c
cercadata = Y
End Function
e quindi la procedura (nell'esempio mi sono fermato alla riga 134) assegnata al pulsante "Registra
Incasso"
Sub registra()
Dim oggi As Date 'dichiarazione del "tipo" di dati della cella D1 assegnato a "oggi"
oggi = Range("D1").Value 'la variabile "oggi" uguale alla data in D1
Set rango = Range("A8:A134") 'si assegna a "rango" la zona in cui avviene la ricerca
cerca = cercadata(rango, oggi) '"cerca" il risultato della Funzione "cercadata",
che 'cerca in "rango" il valore "oggi" e restituisce il numero di riga nell'archivio,
corrispondente 'alla data odierna (rango e oggi sono i due argomenti della funzione
cercadata)
Set Zona = Range("Importo") 'assegniamo a Zona il Range B3:F3
Rows(cerca).Cells(1, 2).Select 'selezioniamo la seconda cella della riga (cerca)
Zona.Copy ActiveCell 'copiamo il contenuto di Zona nella cella attiva
End Sub
Ricordo che che quando si vuole incollare il contenuto di pi celle (anche non contigue, MA presenti
sulla stessa riga) sufficiente selezionare per la destinazione una SOLA cella iniziale, sar Excel a
provvedere che l'incollaggio avvenga in tante celle CONTIGUE per quante sono le celle di
provenienza.

http://ennius.interfree.it/ Pagina 271


MANUALE VBA X EXCEL
Registrare Prenotazioni su un Foglio di lavoro. (04/05/03)
Uno fra i lavori che vorremmo realizzare con Excel, vista la sua naturale impostazione in righe e colonne
che formano tante celle, certamente quello di crearci un "Planning", cio un foglio dove poter
registrare prenotazioni di Camere d'albergo, o anche di appartamenti nei Bed and Breakfast, ma
potrebbe essere anche un Planning per turni di lavoro, per appuntamenti, per.... per.... Tanti sono i
motivi. Normalmente ci si affida ad un planning Mensile, e facendo l'esempio sulle camere, per ogni
camera, ma potrebbe essere per ogni dipendente nel caso dei turni di lavoro, ecc.ecc.
Presento un esempio impostato sulla necessit di controllare visivamente i giorni di prenotazione di una
camera, in un Planning annuale. Come controllo, coloreremo le celle corrispondenti alle prenotazioni,
di un colore in contrasto col resto del foglio. Vediamo l'esempio del Planning:

Come vedete, stata predisposta una griglia, che per quanto riguarda le celle interessate ai giorni e ai
mesi, partono dalla colonna C (quindi la numero 3), e dalla riga 5. Questi riferimenti sono importanti
perch ci serviranno nelle istruzioni, da quale riga e quale colonna iniziare a contare.
Prima di passare ad illustrare le procedure adoperate, premetto un'altra necessit che sorge nel
determinare, quanti giorni possiede ogni mese, visto che non tutti i mesi sono di 31 giorni. Per questo ho
realizzato una Funzione Utente, che verr poi richiamata nelle routine. Questa la funzione, che
restituisce il numero di giorni in funzione del mese espresso come numero (1=gen, 2=feb, ecc):
nella sezione Generale - Dichiarazioni di un Modulo, inseriamo questa istruzione,
per "aiutare" la funzione ad essere visibile anche al di fuori del modulo stesso:
Option Explicit
___________________________________________________________________
Function giorni(mese)
'questa funzione serve a definire quanti giorni ha un mese in modo che nel calcolo
di 'registrazione sul foglio si possa determinare automaticamente il fine mese. Per
'febbraio ho considerato fisso 28 giorni. Nel bisestile lo farete manualmente di
colorare il 'giorno 29.
Select Case mese
Case 1, 3, 5, 7, 8, 10, 12
giorni = 31
Case 4, 6, 9, 11
giorni = 30
Case 2
giorni = 28
End Select
End Function
Ho poi usato una UserForm che richiamo col CommandButton sul foglio, e nella quale inseriremo le due
date: di inizio e di fine prenotazione. Le date le inseriremo in due TextBox, e per comodit visiva ho
usato altre 4 textbox nelle quali svolgeremo delle trasformazioni. Premesso che per queste operazioni si
pu usare delle variabili anzich delle textbox, io ho usato queste perch pi facilmente rintracciabili
nelle istruzioni e rendono, credo, pi comprensibile il tutto. Sulla UserForm ho inserito due altri pulsanti:
quello per lo sviluppo delle routine che coloreranno le celle, ed uno per ripristinare il colore di fondo,
"ripulendo" quindi la tabella.
Vediamo la UserForm:

http://ennius.interfree.it/ Pagina 272


MANUALE VBA X EXCEL

e questo sar il risultato:

Per le Textbox indicate dalle frecce, imposteremo poi la loro propriet "Visible" a False. Nelle due
textbox indicate in blu, estraggo il giorno presente nella textbox a sinistra, e nelle due indicate in rosso,
estraggo il mese (in numero). Le routine sono state inserite nell'evento Exit della textbox (la 2) relativa
alla data di partenza, in modo che, spostandoci col Focus sulla textbox (la 7) della camera N, si attivi
l'evento. Queste le istruzioni:
Private Sub TextBox2_Exit(ByVal Cancel As MSForms.ReturnBoolean)
TextBox3 = Day(CDate(TextBox1)) 'restituisce il giorno della data di arrivo
TextBox5 = Month(TextBox1) 'e il mese espresso in numero

TextBox4 = Day(CDate(TextBox2)) 'restituisce il giorno della data di partenza


TextBox6 = Month(TextBox2) 'e il mese espresso in numero
End Sub
Come gi detto, possibile usare delle varianti anzich delle textbox, esempio:
giornoarrivo = Day(CDate(TextBox1)) 'restituisce il giorno della data di arrivo
mesearrivo = Month(TextBox1) 'e il mese espresso in numero
baster poi usare i nomi delle varianti (giornoarrivo, mesearrivo) nelle istruzioni al
posto del riferimento alle textbox.
Sempre nella Userform vediamo la TextBox7 dove appare il numero della camera. Questo numero
dovr corrispondere anche al nome assegnato al foglio di lavoro che identificher appunto il planning
relativo a quella camera, inoltre il numero camera ci servir anche per controllare se siamo sul foglio
giusto quando premeremo il pulsante "Pulisci Foglio Attivo". Infatti nell'evento Click del commandbutton
facciamo controllare se il nome del foglio corrisponde al numero camera; in caso positivo si ripristina il
colore di tutte le celle (in questo caso in grigio), altrimenti veniamo avvisati con un messaggio. Questa
la routine:
Private Sub CommandButton2_Click()
'queste istruz. controllano se siamo sul foglio che corrisponde al numero scritto nella
'textbox7, e in caso positivo colorano tutte le celle dei giorni in grigio
If ActiveSheet.Name = TextBox7.Value Then
http://ennius.interfree.it/ Pagina 273
MANUALE VBA X EXCEL
With Range("C5:AG16")
.Cells.Interior.ColorIndex = 15
End With
Else
MsgBox "Non siamo sul Foglio giusto"
End If
End Sub
Anzich usare una textbox nella quale digitare il numero ( in lettere ) potremmo usare una ComboBox
che "peschi" con il suo RowSource un elenco con i numeri delle camere, e baster poi selezionare il
numero voluto nella ComboBox. In questo caso va modificata l'istruzione di confronto in questo modo:
If ActiveSheet.Name = ComboBox1.Text Then
Passiamo ora ad esaminare le istruzioni collegate all'evento Click del pulsante "Registra sul foglio".
Private Sub CommandButton3_Click()
'sotto: leggo il nome del foglio che corrisponde alla textbox7 e lo seleziono
Worksheets("" & TextBox7.Value & "").Select

'sotto: inizia il controllo delle date per colorare le celle. Si possono verificare 3
condizioni:
'1) le due date corrispondono allo stesso mese es: 10/03/03 - 25/03/03
'2) le due date accavallano un mese es: 20/03/03 - 05/04/03
'3) le due date accavallano pi di un mese es: 20/04/03 - 05/07/03
'Per stabilire le tre condizioni sopra citate, usiamo un cico If... Then..ElseIf; nella prima
'condizione verifichiamo se i valori (numeri) che rappresentano i mesi, e che si
trovano 'nelle textbox 5 e 6 sono uguali (cio se le date appartengono allo stesso
mese), se la 'condizione vera, allora eseguiamo le istruzioni:
If TextBox5.Value = TextBox6.Value Then
'assegniamo alla variabile r il valore che nella textbox5 e che serve a conoscere
quale 'riga identificare, cio nell'esempio la riga 4 (aprile) AGGIUNGENDO il numero
di 'quante righe ci sono prima che inizi la tabella, che sono 4 (gennaio inizia dalla
riga 5), 'quindi 4+ 4 = 8 (infatti nella tabella il mese Aprile si trova sulla riga 8)
r = TextBox5.Value + 4 'seleziona la riga del mese
'ora assegniamo alla variabile c il valore che si trova nella textbox3 (cio 15, che il
'giorno) e che serve a identificare la colonna del giorno di inizio. Poich anche in
questo 'caso come per le righe, le colonne dei giorni iniziano dalla C cio la
colonna 3, 'aggiungiamo 2 al valore della textbox3 che sar 15+2=17 (infatti nella
tabella il giorno 15 ' nella colonna Q che la diciassettesima da sinistra)
c = Val(TextBox3) + 2
f = Val(TextBox4) + 2
'a questo punto sappiamo con r in quale riga assegnare il colore, e con c ed f
abbiamo i 'giorni, e quindi usiamo queste variabili per identificare il range di celle da
colorare.
Range(Cells(r, c), Cells(r, f)).Interior.ColorIndex = 40

'sotto abbiamo la seconda condizione, cio se le date accavallano un mese,


esempio dal 15/04/03 al 05/05/03 (che l'esempio citato nell'immagine della
userform); quindi 'controlleremo se la textbox6 sar uguale al valore della textbox5
+1, in caso positivo, 'seguono le istruzioni che assomigliano a quelle sopra, solo che
dovremo identificare due 'righe (quelle dei due mesi che appartengono alle due
date), in pi abbiamo bisogno di 'sapere quando finisce il mese appartenente alla
data di ingresso, e per fare questo usiamo 'la funzione vista inizio pagina, che dato il
numero del mese, restituisce di quanti giorni 'formato, e ci servir per determinare
quale colonna usare per colorare il periodo dalla 'data di inizio, alla fine del mese.
Mentre per il mese successivo sapremo che inizia dalla 'colonna 3, mentre i giorni li
prenderemo dalla Data della partenza.
ElseIf TextBox6.Value = Val(TextBox5) + 1 Then
r = TextBox5.Value + 4 'identifica la riga del mese
c = Val(TextBox3) + 2 'identifica colonna del giorno di arrivo
f = giorni(TextBox5) + 2 ' identifica tramite la funzione "giorni" la fine del mese e quindi,
http://ennius.interfree.it/ Pagina 274
MANUALE VBA X EXCEL
'riga sotto, colora le celle del range cosi reperito (data arrivo-fine mese)
Range(Cells(r, c), Cells(r, f)).Interior.ColorIndex = 40
'sotto:ora si reperiscono riga (cio mese), colonna iniziale(la 3) e giorno della Data di
'partenza e si colorano le celle
rr = TextBox6.Value + 4
cc = 3
ff = TextBox4.Value + 2
Range(Cells(rr, cc), Cells(rr, ff)).Interior.ColorIndex = 40

'terza condizione: questa condizione deve prevedere un numero imprecisato di mesi


che 'possano intercorrere tra le due date; infatti possiamo avere due date 02/04/03-
05/06/03 '(tre mesi: aprile,maggio,giugno), ma potrebbero essere 10/04/03-15/08/03
(cinque mesi: 'aprile,maggio,giugno,luglio,agosto). Abbiamo bisogno di inserire un
ciclo che valuti quanti 'mesi sono presenti fr le due date, e ci affideremo ad un ciclo
For..Next.
'quindi controlleremo se la data di partenza maggiore rispetto alla data di arrivo +
1 'mese , in caso positivo il codice eseguir queste istruzioni, che differiscono dalle
'precedenti solo per quanto riguarda il ciclo For Next che assegner a mesi interi la
'colorazione per tutto il mese. In questo caso i giorni saranno reperiti dall'inizio mese,
che 'ripeto, si trova nella colonna 3, e per ogni fine mese alla funzione "giorni"
ElseIf TextBox6.Value > Val(TextBox5) + 1 Then
'con la variabile X prendiamo la differenza in numero tra le textbox dei mesi
X = Val(TextBox6) - Val(TextBox5)
r = TextBox5.Value + 4 'identifica la riga del mese data di arrivo
c = Val(TextBox3) + 2
f = giorni(TextBox5) + 2
Range(Cells(r, c), Cells(r, f)).Interior.ColorIndex = 40
'inizia il ciclo che assegna a N il vettore X meno 1 (il primo mese)
For N = 1 To X - 1
d = 3 'con d reperiamo l'inizio del mese
fff = giorni(r + N + 1) + 2 'con fff usiamo la funzione "giorni" per reperire la fine mese.
'Usiamo r come contatore al quale aggiungiamo N + 1, + 2 (le due colonne che
portano 'alla 3)
'quindi coloriamo tutte le celle del mese
Range(Cells(r + N, d), Cells(r + N, fff)).Interior.ColorIndex = 40
Next
'sotto finiamo di reperire e di colorare la parte dall'inizio al giorno del mese
'corrispondente alla data di partenza
rr = TextBox6.Value + 4
cc = 3
ff = TextBox4.Value + 2
Range(Cells(rr, cc), Cells(rr, ff)).Interior.ColorIndex = 40

End If
End Sub
Sotto, un esempio che mostra l'effetto delle istruzioni sopra, con l'esecuzione della terza condizione,
data di arrivo 14/04/03, data di partenza 10/08/03 (5 mesi) e il rispetto dei relativi fine mese.

http://ennius.interfree.it/ Pagina 275


MANUALE VBA X EXCEL

http://ennius.interfree.it/ Pagina 276


MANUALE VBA X EXCEL
Classifica dei primi 10
Uso delle funzioni MAX e GRANDE abbinate a codice vba per la ricerca dei 10 valori pi alti e relativi
indici.
In quest'esempio, esaminiamo come poter analizzare una tabella dati dove figurano i nomi degli
agenti di un'ipotetica ditta e i relativi punteggi in un periodo determinato di tempo, per ricavare la
Classifica dei primi 10, nell'arco di tutto il periodo. Questo un esempio che si presta per ottenere
numerose varianti nella ricerca di una classifica con evidenzazione degli agenti e relativi punteggi. Le
funzioni usate non sono difficili da capire: la funzione MAX cerca il maggior valore presente in un
elenco di dati numerici, e lo riporta nella cella dove risiede la formula. La funzione GRANDE simile alla
precedente, ma offre la possibilit di reperire la graduatoria di un valore in un insieme di dati, variando
il parametro di ricerca: vediamo la sintassi delle due funzioni:
MAX(num1;num2;...) es.: =MAX(A2:A6) Riporta il numero pi grande tra quelli indicati nel range
Se un argomento costituito da una matrice o da un riferimento, verranno utilizzati soltanto i numeri
presenti nella matrice o nel riferimento, mentre le celle vuote, i valori logici o il testo verranno ignorati.
Se non si desidera che i valori logici e il testo vengano ignorati, utilizzare la funzione MAX.VALORI al
posto di questa funzione
GRANDE(matrice;k)
Matrice la matrice o l'intervallo di dati di cui si desidera determinare il k-esimo valore pi grande.
K la posizione nella matrice o nell'intervallo di celle dei dati da restituire (partendo dal pi grande).
es.: =GRANDE(A2:B6;3) dar il 3 numero pi grande tra i numeri presenti nel range. Se una matrice
non contiene alcun dato, GRANDE restituir il valore di errore #NUM!.Se una matrice contiene pi valori
uguali, verr considerato comunque il valore che si trova nella k esima posizione tra i valori uguali. Es..
=GRANDE(A1:A10;7) ed i valori nel range sono 5,3,6,3,2,1,4,8,9,3 verr considerato il secondo 3 (7
posizione a parit di valore).
Per le altre caratteristiche delle funzioni vi rimando alla guida in linea (da consultare).
Questa l'immagine della tabella:

La cella A22 porta la funzione =MAX(B3:H19) e quindi il valore 1 classificato, le altre celle fino alla J22,
sulla stessa riga, portano la funzione =GRANDE(B3:H19;2) fino a =GRANDE(B3:H19;10) che porter il 10
classificato. La riga 23 porta solo i colori di identificazione classifica, con all'interno il codice del colore,
che serve (ColorIndex) nelle istruzioni Vba per colorare la cella che ospita il valore relativo alla
graduatoria. La riga 24 invece ospita il nome dell'agente che ha realizzato il relativo punteggio
presente due righe sopra. Questo nome viene "pescato" dal codice, che dopo aver colorato la cella
relativa alla classifica punteggio, si sposta a inizio stessa riga, copia il nome, e lo "scarica" nella
rispettiva cella della riga 24. Il pulsante per attivare la routine ha una doppia funzione, serve per
attivare la routine e per azzerare i valori; funziona come interruttore. Vediamo la routine:
Private Sub CommandButton1_Click()
If CommandButton1.Caption = "Mostra" Then
CommandButton1.Caption = "Azzera"

http://ennius.interfree.it/ Pagina 277


MANUALE VBA X EXCEL
Application.ScreenUpdating = False 'evita il saltellamento sul foglio
'dichiarazioni delle variabili
Dim CL As Object
x = Range("A22").Value 'assegnazioni dei valori alle variabili (celle con funzioni)
y = Range("B22").Value
w = Range("C22").Value
z = Range("D22").Value
t = Range("E22").Value
u = Range("F22").Value
m = Range("G22").Value
p = Range("H22").Value
a = Range("I22").Value
j = Range("J22").Value
'per ogni cella (CL) nel range B3:H19, se il valore della cella uguale alla variabile (x) indicata, selezioni
la 'cella, la colori, ti sposti alla cella di inizio riga (colonna A), copi il valore (nome agente), selezioni la
cella di 'destinazione (A24) e incolli il nom. Quindi la routine continua per le rimanenti variabili (ElseIf).

For Each CL In Range("B3:H19")


If CL.Value = x Then
CL.Select
CL.Interior.ColorIndex = 6
With ActiveCell
Cells(ActiveCell.Row, 1).Select
Selection.Copy
Range("A24").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End With

ElseIf CL.Value = y Then


CL.Select
CL.Interior.ColorIndex = 40
With ActiveCell
Cells(ActiveCell.Row, 1).Select
Selection.Copy
Range("B24").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End With

ElseIf CL.Value = w Then


CL.Select
CL.Interior.ColorIndex = 38
With ActiveCell
Cells(ActiveCell.Row, 1).Select
Selection.Copy
Range("C24").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End With

ElseIf CL.Value = z Then


CL.Select
CL.Interior.ColorIndex = 43
With ActiveCell
Cells(ActiveCell.Row, 1).Select
Selection.Copy
http://ennius.interfree.it/ Pagina 278
MANUALE VBA X EXCEL
Range("D24").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End With

ElseIf CL.Value = t Then


CL.Select
CL.Interior.ColorIndex = 4
With ActiveCell
Cells(ActiveCell.Row, 1).Select
Selection.Copy
Range("E24").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End With

ElseIf CL.Value = u Then


CL.Select
CL.Interior.ColorIndex = 35
With ActiveCell
Cells(ActiveCell.Row, 1).Select
Selection.Copy
Range("F24").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End With

ElseIf CL.Value = m Then


CL.Select
CL.Interior.ColorIndex = 15
With ActiveCell
Cells(ActiveCell.Row, 1).Select
Selection.Copy
Range("G24").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End With

ElseIf CL.Value = p Then


CL.Select
CL.Interior.ColorIndex = 34
With ActiveCell
Cells(ActiveCell.Row, 1).Select
Selection.Copy
Range("H24").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End With

ElseIf CL.Value = a Then


CL.Select
CL.Interior.ColorIndex = 8
With ActiveCell
Cells(ActiveCell.Row, 1).Select
Selection.Copy
Range("I24").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
http://ennius.interfree.it/ Pagina 279
MANUALE VBA X EXCEL
End With

ElseIf CL.Value = j Then


CL.Select
CL.Interior.ColorIndex = 3
With ActiveCell
Cells(ActiveCell.Row, 1).Select
Selection.Copy
Range("J24").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End With

End If
Next
Application.CutCopyMode = False
'fine ciclo ricerche

Else
'questa l'istruzione per togliere i colori e pulire le celle riga 24, e rinomina la Caption del
commandbutton per 'reinizzializzare una nuova ricerca
CommandButton1.Caption = "Mostra"
Range("B3:H19").Interior.ColorIndex = xlNone
Range("B24:J24").ClearContents
End If
End Sub

http://ennius.interfree.it/ Pagina 280


MANUALE VBA X EXCEL
Ricerca di dati in un elenco di un foglio di lavoro
Usare il metodo Find
Per dimostrare che sfruttando gli esempi contenuti nella guida in linea dell'Editor di Visual Basic,
possibile, con piccole modifiche, adattare gli esempi alle nostre necessit, presento alcune soluzioni
possibili sfruttando l'esempio collegato al metodo Find. Questo sotto quanto riportato nella "Guida il
linea", ottenibile anche premendo il tasto F1, quando ci si trova nell'editor di visual basic:
(N.B. la seguente routine, presa dalla guida contiene un piccolo bug. Vedi la segnalazione a pagina 5
de "le vs domande", paragrafo "Errori sulla Guida")
Esempio dalla guida in linea (cito:)
Questo esempio trova tutte le celle nell'intervallo A1:A500 sul foglio di lavoro
1 contenenti il valore 2 e modifica il valore in 5.

With Worksheets(1).Range("a1:a500")
Set c = .Find(2, lookin:=xlValues)
If Not c Is Nothing Then
firstAddress = c.Address
Do
c.Value = 5
Set c = .FindNext(c)
Loop While Not c Is Nothing And c.Address <> firstAddress
End If
End With

E queste sono alcune possibili varianti, la prima ipotizza l'utilizzo di una cella per l'introduzione del dato
da cercare (vettore). La cella d'esempio ( Cells(1, 2).Value ) identifica la cella B1, e avremmo potuto
usare indifferentemente la notazione Range("B1").Value, sarebbe stato lo stesso, forse pi semplice da
usare e da riconoscere per colui che compla l'istruzione. A questa cella viene associata la variabile
stringa X in modo che, qualunque testo si scriva in B1, venga identificato con la X. Se il valore da
cercare, anzich testo, fosse un numero, sarebbe necessario definire la X non come String ma come
Variant (Variant accetta sia testo che numero, solo occupa un p pi di spazio in memoria). Sempre
per fare l'esempio, diremo che i dati si trovano sul Foglio1, nel Range A2:H100. Ovviamente ognuno
metter i riferimenti alla zona dove vorr eseguire la ricerca, che potr essere pi ampia, o anche una
sola colonna da una determinata riga ad un altra. Una particolarit legata al tipo di ricerca, questa:
con la seguente istruzione, verranno cercati valori esatti al valore da cercare : Set c = .Find(X,
LookIn:=xlValues, LookAt:=xlWhole), con la seguente istruzione verranno invece trovati valori che sono
una parte del valore cercato: Set c = .Find(X, LookIn:=xlValues), se, per esempio, in B1 digitiamo.
"pape", verranno trovati anche "papero", op. "paperino", ecc.ecc. La seguente routine cerca quindi il
valore dato, e se lo trova, seleziona la cella, altrimenti avvisa con un messaggio "Nome non Trovato".
Sub Cerca1()

With Worksheets(1).Range("A2:H100")
Dim X As String
X = Cells(1, 2).Value
Set c = .Find(X, LookIn:=xlValues, LookAt:=xlWhole)

If Not c Is Nothing Then


firstAddress = c.Address
Do
c.Cells.Select
Set c = .FindNext(c)
Loop While Not c Is Nothing And c.Address <> firstAddress

Else
MsgBox "Nome non Trovato"
End If
End With
End Sub

http://ennius.interfree.it/ Pagina 281


MANUALE VBA X EXCEL
Questo che segue un'altro esempio, in cui l'introduzione del dato da cercare passa attraverso una
InputBox, e quindi viene usata la imputbox come vettore per la ricerca:
Sub Cerca2()

With Worksheets(1).Range("A2:H100")
Dim Message, Title, MyValue

Message = "Inserisci il nominativo da cercare :"


Title = "Ricerca Dati" ' Imposta il titolo.

' Visualizza il messaggio, il titolo


MyValue = InputBox(Message, Title)

Dim X As String
X = MyValue 'viene assegnato alla X il contenuto della Inputbox
Set c = .Find(X, LookIn:=xlValues, LookAt:=xlWhole)

If Not c Is Nothing Then


firstAddress = c.Address
Do
c.Cells.Select
Set c = .FindNext(c)
Loop While Not c Is Nothing And c.Address <> firstAddress

Else
MsgBox "Nome non Trovato"
End If
End With
End Sub
Un altro modo per eseguire una ricerca, e senza il metodo Find, la seguente, per senza messaggio
di avviso, visto che se trova il dato lo seleziona, se non lo trova vuol dire che il dato non presente
Sub Cerca3()

For Each c In Worksheets("Foglio1").Range("A2:H100")


If c.Value = Range("B1").Value Then
c.Select
End If
Next c

End Sub
Volendo, anche per quest'ultima routine, possibile sfruttare l'assegnazione del vettore ad una
variabile, oppure usare una InputBox; sar sufficiente sostituire If c.Value = Range("B1").Value Then con
If c.Value = X Then... oppure If c.Value = MyValue Then...

NUOVO:
Un problema di tutti i cicli di ricerca (ovviamente dipende dalla procedura scelta), che quando in un
elenco ci sono pi dati uguali, il ciclo, o trova il primo (come negli esempi sopra), e li si ferma, e se lo fai
ripartire inizia da capo e si riferma al primo, o li trova tutti ma si ferma all'ultimo. Questo secondo caso
avviene perch nel ciclo in genere si usa l'istruzione "se lo trovi, selezionalo", ed il ciclo lo fa, ma dopo
averlo selezionato prosegue e se trova altri valori uguali, li seleziona fintantoch non trova l'ultimo
valore e si ferma. Allora ho pensato di inserire un'istruzione che blocchi il ciclo se trova il valore cercato,
ma che lo possa riavviare dal punto in cui si fermato; la soluzione pi semplice e quella che riporto
sotto, dove nel caso venga trovato il valore, faccio apparire una msgbox Si/No, che interrompe il ciclo,
con una domanda: " Ti vuoi fermare?" Se premi Si, esci dal ciclo, se premi No, prosegue nel ciclo dal
punto in cui si era fermato, e per ogni valore uguale si riferma e ripone la domanda. Semplice no?
Sub cerca()
Dim CL As Object
For Each CL In Range("A1:A2000") 'colonna in cui esegue la ricerca
http://ennius.interfree.it/ Pagina 282
MANUALE VBA X EXCEL
Dim X
X = Range("D1").Value 'cella che porta il valore da cercare
If CL = X Then 'se la cella (CL) ugule a X
CL.Select 'faccio selezionare (fermo il ciclo) questa cella
Y = Mid(CL.Address, 2, 1) + Mid(CL.Address, 4, 5) 'con Y prendo il 'riferimento
alla cella che poi uso nella domanda
Dim irisposta As Integer 'Imposto la msgbox e relativa domanda
irisposta = MsgBox("Trovato in " & Y & " Vuoi fermarti ?", vbYesNo)
If irisposta = vbYes Then 'se rispondo Si allora
Exit For 'esco dal ciclo
End If
End If
Next CL 'altrimenti proseguo al successivo
End Sub

Come per le altre routine, anche in questa la variabile X pu venir assegnata attraverso una InputBox.
Buon lavoro.

http://ennius.interfree.it/ Pagina 283


MANUALE VBA X EXCEL
Ricerca di un dato in un elenco o tabella. (21/05/03)
Ricercare dati, valori o altre informazioni all'interno dei fogli di lavoro, sembra sia uno tra gli sport
preferiti dagli Excelnauti. Nel paragrafo precedente abbiamo visto delle procedure adatte a questo
scopo, ma il buon Excel col suo vba, ha il gran pregio di consentirci di seguire percorsi diversi per
raggiungere lo stesso scopo. Questa pagina si occuper di mostrare alcune di queste altre procedure,
esemplificando anche gli obiettivi che intendiamo ottenere come risultato di una ricerca..
Per prima cosa, in una ricerca, bisogna indicare in quale zona o area eseguirla. Vediamo alcuni sistemi
di identificazione di un area:
Usare i riferimenti precisi dell'area : Set zona = ActiveSheet.Range("A1:A500")
Usare il riferimento a tutta una colonna: Set zona = ActiveSheet.Range("A:A")
Usare il riferimento alla cella iniziale della Colonna (A nell'esempio) e alla cella finale (con End)
dell'area : Set zona = Range(Cells(1, 1), Cells.End(xlDown))
Usare il riferimento a tutta l'area che contiene dati sfruttando la propriet UsedRange del foglio di
lavoro : Set zona = ActiveSheet.UsedRange
Stabilita l'area, il passo successivo sar quello di definire cosa vogliamo cercare. In questo caso,
esemplificare il "cosa cercare" diventa ardua impresa visto la molteplicit nelle necessit che ogni
utente potr avere. Ci limiteremo ad alcuni esempi che comunque serviranno a capire. Imposteremo
tre classiche ricerche:
ricercare una data
ricercare un valore numerico
ricercare del testo
Precisiamo intanto che le procedure usate, sono tutte impostate in modo che nel caso venga trovata
la chiave di ricerca, si venga avvisati con un messaggio riportante i riferimenti alla cella, e la routine
proseguir poi segnalandoci ogni indirizzo di cella che corrisponder alla chiave cercata. In questo
modo, su lunghi elenchi, potremo annotare tutti i riferimenti per poi visualizzarli , oppure aggiungere
una semplice istruzione perch per ogni chiave trovata, venga selezionata la relativa cella. Per
ognuna delle ricerche su esposte, puntualiziamo spiegazioni e facciamo qualche esempio, vediamo
una prima riga di istruzione:
ricerca su date: l'istruzione significa: se il valore cercato (rng.Value) una data (IsDate) e la prima
lettera a sinistra (Left(rng.Text, 1)) del valore trovato uguale a # (cancelletto), allora... (segue
istruzione di cosa fare). Questa istruzione utile quando si imposta, per necessit visive, una larghezza
di colonna inferiore alla lunghezza del dato presente in una cella; in questo caso Excel, avrete notato,
non cancella i dati, ma mostra una serie di #, tanti quante sono le lettere che compongono il valore.
If IsDate(rng.Value) And Left(rng.Text, 1) = "#" Then
ancora su date, ma nel caso in cui si voglio trovare tutte le date di una decade (da 01 a 09 e useremo
lo zero come chiave di ricerca) (da 10 a 19 e useremo 1 come chiave di ricerca) (da 20 a 29 e
useremo 2 come chiave di ricerca) oppure 3 per i fine mese.
If IsDate(rng.Value) And Left(rng.Text, 1) = 1 Then 'opp.= 0, opp. = 2, opp. = 3
(usando numeri come chiave di ricerca, NON vanno messi tra doppi apici)
ricerca su numeri: anche in questo caso l'istruzione si basa sulla ricerca di un valore (IsNumeric),
numerico in questo caso, e come chiave di ricerca sfrutteremo (Left(rng.Text, 1)) che vuol dire: il primo
valore a sinistra del numero, per cui potremo trovare per esempio, tutti i valori che cominciano con 5.
Ovviamente la ricerca dipende dal numero che useremo come chiave di ricerca. Se anzich cercare
solo i valori che iniziano per un determinato numero, volessimo cercare tutti i valori che iniziano per una
coppia di numeri (per esempio: 25..) dovremmo variare il secondo argomento della funzione Left,
sostituendolo con 2 (es: Left(rng.Text, 2)):
If IsNumeric(rng.Value) And Left(rng.Text, 1) = 5 Then 'solo il primo a sinistra = 5
If IsNumeric(rng.Value) And Left(rng.Text, 2) = 25 Then 'con i primi due a sinistra = 25
Come vedete queste istruzioni, e le successive, oltre a poterle variare nel modo di stabilire una chiave
di ricerca, sono facili da capire. Se poi qualcuno volesse rendere la chiave di ricerca come variabile
(negli esempi i valori sono costanti, cio inseriti nel codice), pu usare una cella da destinare
all'inserimento della chiave di ricerca, oppure usare una InputBox, e poi usare questi riferimenti
nell'uguaglianza (uguale a), esempio: la cella E1 dove scrivere ci che vorremo cercare, e l'istruzione
diventa:
If IsNumeric(rng.Value) And Left(rng.Text, 2) = Range("E1").Value Then
oppure con una InputBox :
dimmi = InputBox("Scrivi la coppia di numeri")
If dimmi = "" Then Exit Sub 'per uscire se non si scrive niente nella inputbox
http://ennius.interfree.it/ Pagina 284
MANUALE VBA X EXCEL
If IsNumeric(rng.Value) And Left(rng.Text, 2) = Val(dimmi) Then

Ultimo esempio:
ricerca su testo: in queste istruzioni, simili alle altre come impostazione, la chiave di ricerca andr
posizionata tra doppi apici, e potremo eseguire ricerche con lettera alfabetica (es: = "a" opp. = "b",
opp = "t") oppure per insiemi di lettere (es: = "ca" opp: = "bar", ecc.ecc) ricordandosi di modificare il
numero dei caratteri che la funzione Left dovr estrarre (Left(rng.Text, 1) opp Left(rng.Text, 2) opp
Left(rng.Text, 3) ecc..Varieremo anche la prima condizione da verificare, dicendo: se il valore da
cercare NON numerico e.... usando questa istruzione: IsNumeric(rng.Value) = False, in questo modo:
If IsNumeric(rng.Value) = False And Left(rng.Text, 1) = "a" Then
Sar possibile anche in questo caso rendere variabile la chiave di ricerca usando una cella oppure
una InputBox, in questo caso le modifiche sono uguali a quelle gi scritte sopra. Unica precisazione:
poich le ricerche su testo sono "CaseSensitive" (sensibili a maiuscole/minuscole, la "a" diversa dalla
"A") useremo questa semplice istruzione da inserire nella sezione "Generale - Dichiarazioni" del
modulo che ospiter la nostra macro: Option Compare Text Questo ci consentir di trovare il testo
comunque si sia scritta la nostra chiave di ricerca. Ed ora vediamo come comporre le routine:
questa sotto ricercher un dato (scegliamo il metodo UsedRange come identificazione area, e una
inputbox per reperire il dato da cercare) e basiamo la ricerca sul testo, prima lettera del valore che
sar nelle celle. Questa routine avviser in sequenza ogni riferimento ad ogni cella che corrisponder
alla chiave, ma non si fermer, selezionandola. La successiva routine simile a questa, ma si fermer,
selezionandola, ad ogni cella trovata:
Sub popop() 'nome macro
'dichiarazione della variabile "rng" di tipo Range
Dim rng As Range
'assegnazione alla variabile "dimmi" del valore reperito con la inputbox
dimmi = InputBox("Scrivi l'iniziale da cercare")
If dimmi = "" Then Exit Sub 'per uscire se non si scrive niente nella inputbox
'per ogni rng (Range o cella) nella zona del foglio di lavoro che contiene dati
For Each rng In ActiveSheet.UsedRange
'se il valore della cella (rng) NON un numero e la prima lettera uguale a "dimmi"
If IsNumeric(rng.Value) = False And Left(rng.Text, 1) = dimmi Then
'si da il messaggio del rif. alla cella e del nome ivi contenuto
MsgBox "La cella che cerchi " & rng.Address & " col valore: " & rng.Value
End If
'si continua il ciclo fino alla fine dell' UsedRange
Next rng
End Sub
e questa con la selezione della cella ad ogni chiave trovata:
Sub popup()
Dim rng As Range
dimmi = InputBox("Scrivi l'iniziale da cercare")
If dimmi = "" Then Exit Sub
For Each rng In ActiveSheet.UsedRange
If IsNumeric(rng.Value) = False And Left(rng.Text, 1) = dimmi Then
rng.Select 'questa seleziona la cella e la evidenzia
MsgBox "La cella che cerchi " & rng.Address & " col valore: " & rng.Value
End If
Next rng
End Sub
Se vorremo creare una routine che ci consenta di fermarci ed uscire quando avremo trovato il valore
che ci interessa, dovremo inserire un istruzione che ci ponga la domanda se ci vogliamo fermare. Se
risponderemo SI usciremo dal ciclo, altrimenti il ciclo continuer. Questa la routine (simile all'ultima
presente nel paragrafo precedente : "Ricerca di un dato")
Sub pipup()
Dim rng As Range
dimmi = InputBox("Scrivi l'iniziale da cercare")
If dimmi = "" Then Exit Sub
For Each rng In ActiveSheet.UsedRange
http://ennius.interfree.it/ Pagina 285
MANUALE VBA X EXCEL
If IsNumeric(rng.Value) = False And Left(rng.Text, 1) = dimmi Then
rng.Select 'questa seleziona la cella e la evidenzia
Dim irisp As Integer 'Imposto la msgbox e relativa domanda con SI/NO
irisp = MsgBox("Cella " & rng.Address & " a nome " & rng.Value & " Vuoi fermarti ?",
vbYesNo) ' irisp tutta una riga
If irisp = vbYes Then 'se rispondo Si allora
Exit For 'esco dal ciclo e quindi dalla routine
End If
End If
Next rng

End Sub

Buon lavoro.

http://ennius.interfree.it/ Pagina 286


MANUALE VBA X EXCEL
Utilizzo del Codice per ripristinare un elenco di formule.
Applicazione del Metodo Autofill
Uno dei motivi di maggiore rabbia, quando inavvertitamente cancelliamo delle celle con dei valori,
celle che per contenevano anche delle formule. E tanto maggiore l'incavolatura quando
perdiamo tutto un bel range di celle, predisposte con fatica. E' possibile, tramite codice, predisporre
una macro che ci rimetta le cose a posto. Sar sufficiente associare un pulsante a questa macro, e le
nostre formule ritorneranno in tutte le celle da cui sono state cancellate ( o meglio, in tutto il range di
celle indicate nel codice).
Per capire, facciamo un esempio, la classica colonna dove riportiamo il saldo progressivo di un conto
dare/avere. avremo quindi nella colonna C il dare, nella D l'avere, ed in E il saldo, avremo una cella in
E di riporto a saldo, e nelle successive righe della colonna E le rispettive formule, ognuna con i propri
riferimenti. vediamo sotto un esempio:

B C D E
1 Operazione Dare Avere Saldo
2 riporto a saldo
3 =SE((C3+D3)<>0;E2-C3+D3;"")
4 =SE((C4+D4)<>0;E3-C4+D4;"")
5 =SE((C5+D5)<>0;E4-C5+D5;"")
6 =SE((C6+D6)<>0;E5-C6+D6;"")
7 =SE((C7+D7)<>0;E6-C7+D7;"")
8 =SE((C38+D8)<>0;E7-C8+D8;"")
9

Bene, prepareremo la nostra macro utilizzando per la formula lo stile R1C1, (che ricordo, Reimmette le
formule nelle celle interessate come formule residenti) ed il metodo AutoFill per riempire, in un colpo
solo, tutte le celle previste nel range di destinazione ( Range("E3:E8") ). Ovviamente decideremo noi
quanto lungo sar il nostro elenco, e sostituiremo i riferimenti alle celle. Baster a questo punto premere
il pulsante associato alla macro, e nelle nostre celle riappariranno le formule. Ci saremo in questo
modo protetti da eventuali errori, in barba alla distrazione! Questa la formula dell'esempio:
Sub ripristina()

Range("E3").Select
ActiveCell.FormulaR1C1 = "=IF((RC[-2]+RC[-1])<>0,R[-1]C-RC[-2]+RC[-1],"""")"
Selection.AutoFill Destination:=Range("E3:E8"), Type:=xlFillDefault

End Sub
La formula dice: selezionami la cella E3, e in questa cella mi inserisci la formula: SE la cella che si trova
due colonne a sinistra di questa RC[-2] e la cella che si trova una colonna a sinistra di questa RC[-1] ,
sono diverse da zero, allora mi prendi la cella che st una cella sopra a questa R[-1] (vedete che
manca il riferimento a C, e questo vuol dire: stessa colonna) mi ci sottrai (abbrevio)RC[-2] o/e mi sommi
RC[-1] , altrimenti mi lasci la cella vuota """" (nota: mentre in una formula sul foglio di lavoro lo spazio
vuoto si indica con due doppi apici, nel codice ne occorrono quattro, per avere lo stesso significato)
a questo punto, entra in gioco l'istruzione della riga successiva, dove troviamo AutoFill. il significato
questo: con ci che hai messo nella cella selezionata, mi ci RIEMPI anche tutte le celle che vanno da
E3 a E8. Poich questa operazione equivale al "trascinamento" sul foglio di lavoro, il bravo Excel,
provvede anche all'aggiornamento dei riferimenti nelle formule, in automatico.
Ricordo che un buon metodo per imparare e modificare il codice, quello di usare il "Registratore di
macro" (presente in questa sezione). Potrete vedere, compiendo voi le azioni necessarie, come viene
compilato il codice, e quindi, piano piano, assimilare le nozioni.
Buon lavoro.

http://ennius.interfree.it/ Pagina 287


MANUALE VBA X EXCEL
Una piccola raccolta di istruzioni di varia (f)utilit.
(sar aggiornata periodicamente; gli aggiornamenti saranno posti alla fine della pagina.)
Limitare l'area da visualizzare a video. (disabilita le barre di scorrimento)
Worksheets(1).ScrollArea = "A1:L22" '(area che rimane fissa a video)

'mentre per riapplicare lo scrolling


Worksheets(1).ScrollArea = ""

Nascondere le righe vuote. (in una tabella elenco, scelta una Colonna (la A per esempio) quando si
voglia riassumere i dati nascondendo ev. righe vuote)
Sub NascondeRiga()
ScopriRiga 'viene prima chiamata questa routine per scoprire ev. righe nascoste
Dim CL As Object
For Each CL In Range("A1:A50")
If CL.Value = "" Then CL.EntireRow.Hidden = True
Next CL
End Sub
e questa per scoprire tutte le righe nascoste:
Sub ScopriRiga()
Cells.EntireRow.Hidden = False
End Sub
Cancellare righe vuote (in una tabella o elenco, scelta una Colonna (la A per esempio) quando si
voglia cancellare le righe corrispondenti alle celle in A vuote )
Sub EliminaRighe()

For Each cella In Range("A1:A200")


If cella.Value = "" Then
cella.EntireRow.Delete
End If
Next cella

End Sub
Ridurre a icona Excel. (quando si voglia ridurre Excel a icona per lasciare lo schermo ad una userform
(in questo caso si sta sfruttando l'apertura della cartella))
Private Sub Workbook_Open()
Application.WindowState = xlMinimized
End Sub
e per ripristinare, all'uscita da Excel
Application.WindowState = xlMaximized
Stampare un foglio o una selezione di celle.
per un foglio
ActiveWindow.SelectedSheets.PrintOut Copies:=1, Collate:=True

per una selezione


Selection.PrintOut Copies:=1, Collate:=True
Disabilitare/Abilitare barre dei men. (attenzione: poich queste modifiche resterebbero su Excel
quando si chiude il file, e resterebbero anche alla riapertura altri file dove c' il bisogno che i men si
vedano, DOVRETE ripristinare i men usando le istruzioni al rovescio, nell'evento BeforeClose del
workbook)
'questa toglie la barra dei men
Application.CommandBars.ActiveMenuBar.Enabled = False
'questa toglie la barra men Standard
Application.CommandBars("Standard").Enabled = False
'oppure questa disabilita l'icona "nuovo" dalla barra men "Standard"
Application.CommandBars("Standard").Controls.Item(1).Enabled = False

per riattivarle:

http://ennius.interfree.it/ Pagina 288


MANUALE VBA X EXCEL
'questa rimette la barra dei men
Application.CommandBars.ActiveMenuBar.Enabled = True
'questa rimette la barra men Standard
Application.CommandBars("Standard").Enabled = True
'oppure questa abilita l'icona "nuovo" dalla barra men "Standard"
Application.CommandBars("Standard").Controls.Item(1).Enabled = True

Proteggere la visualizzazione del codice vba.


Spostarsi nell'Editor di Visualbasic, selezionare dal men Strumenti/Propriet di
VBAProject , e nella finestra che si apre scegliere "Protezione", mettere un segno di
spunta a "proteggi ecc. ecc" e inserita la password, salvare la cartella, uscire e
quando si rientra, aprire il progetto cartella: verr richiesta la password, altrimenti il
codice non sar visibile. (Questo anche se in apertura foglio, avremo disabilitato le
macro).
Automatizzare l'apertura di una UserForm. All'apertura della cartella di lavoro o di un foglio
all'apertura della cartella (WorkBook)
Private Sub Workbook_Open()
UserForm1.Show
End Sub
all'apertura di un Foglio (Worksheet)
Private Sub Worksheet_Activate()
UserForm1.Show
End Sub
Apertura di un file in sola lettura. Indicare il percorso che mira al file che interessa. L'apertura in sola
lettura non consente modifiche al file cos aperto.
Workbooks.Open Filename:= "C:\Documenti\NomeFile.xls", ReadOnly:=True
Eliminare le Interruzioni di pagina. Per eliminare in un colpo solo tutte le interruzioni di pagina presenti su
un Foglio (segnalato da Michele GiGi - e-mail : knightindustriesit@yahoo.it).
Cells.Select
ActiveSheet.ResetAllPageBreaks
Misurare la memoria usata da Excel. Se volete sapere quanta memoria sta utilizzando la vostra
applicazione, provate questa:
Sub MisuraMe()
'la lettura viene eseguita in byte e quindi la convertiamo in kb
Y = Application.MemoryUsed
X = Val(Y / 1024)
MsgBox "Microsoft Excel sta usando " & X & " Kb di memoria."
End Sub
Selezionare un Foglio di lavoro scrivendo il nome del foglio in una TextBox su una UserForm, e usando
l'evento Click di un CommandButton.
Private Sub CommandButton1_Click()
X = TextBox1.Text
Worksheets("" & X & "").Select
End Sub
Disabilitare il tasto destro del mouse. In questo modo si disabilita anche la comparsa del men
contestuale che appare quando si clicca destro sulle celle del foglio di lavoro:
per un foglio, con messaggio di avviso:
Private Sub Worksheet_BeforeRightClick(ByVal Target As Range, Cancel As Boolean)
MsgBox "Il tasto destro stato disabilitato."
Cancel = True
End Sub
per tutti i fogli, senza messaggio:
Private Sub Workbook_SheetBeforeRightClick(ByVal Sh As Object, ByVal Target As
Range, Cancel As Boolean) ' tutta una riga
Cancel = True
End Sub

http://ennius.interfree.it/ Pagina 289


MANUALE VBA X EXCEL
Nascondere Righe e/o Colonne. indicare il numero di riga (es. 10), e la lettera per la colonna, per
ripristinare, stesse istruzioni con False al posto di True:
ActiveSheet.Rows(10).Hidden = True
oppure per pi righe, indicare numero da : a numero, tra doppi apici:
ActiveSheet.Rows("8:12").Hidden = False
per le colonne:
Worksheets("Foglio1").Columns("C").Hidden = True
stesso discorso per pi colonne:
Worksheets("Foglio1").Columns("C:F").Hidden = True
Reperire il nome di un file che si apre. Quando si vuole memorizzare il nome di un file che si apre,
magari facendolo scrivere in una cella, (esempio in A1), creare una macro con questa istruzione:
(segnalazione di Luca Paolini). Si aprir la finestra "Apri File" e verr memorizzato il file che si selezioner :
NewFile = Application.GetOpenFilename
Range("A1").Value = NewFile
Salvare in automatico la cartella su cui si lavorato, alla chiusura della cartella stessa o di Excel. Si
sfrutta l'evento Workbook_BeforeClose, e si evita la richiesta di salvataggio che Excel ci propone, con
questa semplice istruzione:
Private Sub Workbook_BeforeClose(Cancel As Boolean)
ThisWorkbook.Save 'questa riga l'istruzione
End Sub
Inserire/Togliere BloccaRiquadri. L'opzione Bloccariquadri serve per tenere bloccate una parte di celle
del foglio di lavoro mentre le rimanenti celle possono scorrere liberamente agendo sulle barre di
scorrimento. Si possono bloccare solo le righe (selezionando prima l'intestazione di riga), oppure solo le
colonne (selezionando prima l'intestazione di colonna), oppure righe e colonne insieme se si seleziona
una cella e si applica bloccariquadri. il blocco avverr sempre a partire dalla riga sopra a quella
selezionata, o la colonna a sinistra rispetto a quella selezionata, o le righe sopra e le colonne a sinistra
rispetto alla cella selezionata. Esempio. selezioniamo la cella C5 (terza colonna e quinta riga): saranno
bloccate le colonne A e B e le righe dalla quarta alla prima. Queste le istruzioni per applicare o togliere
bloccariquadri (FreezePanes)
'Bloccare le righe (volendo bloccare le prime due righe):
ActiveSheet.Rows(3).Select
ActiveWindow.FreezePanes = True
oppure:
Rows("3:3").Select
ActiveWindow.FreezePanes = True

'Bloccare le colonne (volendo bloccare le prime 3 colonne A-B-C)


ActiveSheet.Columns("D").Select
ActiveWindow.FreezePanes = True
oppure:
Columns("D:D").Select
ActiveWindow.FreezePanes = True

'Sbloccare (togliere) ogni bloccariquadri:


ActiveWindow.FreezePanes = False
Passare da Stile riferimento A1 a Stile R1C1 - Stile A1 le Colonne sono identificate con Lettere
alfabetiche. Stile R1C1 le Colonne sono identificate con Numeri. La propriet ReferenceStyle si applica
solo all'oggetto Application, ossia a Excel e quindi a tutta la cartella di lavoro. Attenzione: ricordarsi
che una volta applicato uno stile, lo stesso rimane su Excel anche per successive aperture, ripristinare
quindi lo stile originario usando l'evento Workbook_BeforeClose.
per passare a Stile R1C1:
With Application
.ReferenceStyle = xlR1C1
End With

per ritornare a Stile A1:


With Application

http://ennius.interfree.it/ Pagina 290


MANUALE VBA X EXCEL
.ReferenceStyle = xlA1
End With
Proteggere un intervallo (celle o colonne o righe) da scrittura. Si pu sfruttare l'evento
SelectionChange del Worksheet e con Intersect limitare l'azione solo ad una determinata area.
L'esempio sotto blocca tutte le celle della colonna B. Ovviamente dovremo lasciare l'opzione
"bloccata" a tutte le celle.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Intersect(Target, Columns(2)) Is Nothing Then
ActiveSheet.Unprotect 'sproteggiamo il foglio se la cella selezionata non nella B
Exit Sub

Else
ActiveSheet.Protect 'e proteggiamo il foglio attivo
End If
End Sub

Eliminare la richiesta di Aggiornamento Collegamenti. - Quando una cartella di lavoro contiene


collegamenti ad altri fogli o celle di cartelle chiuse, viene posta da Excel una richiesta di aggiornare o
meno i collegamenti. E' possibile eliminare la richiesta sfruttando l'evento Workbook_Open ed
inserendo la seguente istruzione:
Private Sub Workbook_Open()
Application.AskToUpdateLinks = False 'istruzione
End Sub
Richiamare da Excel la Calcolatrice di sistema. - A volte pu tornare utile avere a disposizione su un
foglio di lavoro, una calcolatrice; questa una routine possibile (per Win XP) che sfrutta la Shell di
sistema:
Sub ChiamaCalcolatrice()
Dim Pippo
Pippo = Shell("C:\WINDOWS\System32\CALC.EXE", 1)
End Sub
Conoscere la versione del Sistema Operativo. - pu necessitare di impostare istruzioni vba che
cambierebbero se cambia il S.O. (ad esempio la chiamata alla Shell di sistema cambia tra Windows98
e WindowsXP). Per rintracciare via codice la versione che identifica il SO e creare quindi condizioni
diverse (If...Then...Else), si pu usare questa istruzione che restituisce un messaggio con la versione del
SO del computer che state usando:
Sub DimmiSO()
MsgBox Application.OperatingSystem
End Sub
--------------------------------------------------------
per WindowsXP si otterrebbe questa informazione: "Windows (32-bit) NT 5.01"
sar possibile quindi impostare istruzioni per quel sistema lasciando ad Else il compito
di altre istruzioni; esempio:
If Application.OperatingSystem = "Windows (32-bit) NT 5.01" Then
..istruzioni da eseguire in questo caso
Else
..istruzioni da eseguire in tutti gli altri casi
End If
Colorare una cella SE conterr un certo valore - Potremo sfruttare l'evento Change del Worksheet che
si verifica quando scriviamo in una cella, modificandone il contenuto (sia che la cella sia vuota o
anche cambiando un valore gi residente). Sfrutteremo l'argomento Target dell'evento, che identifica
la cella che ha subito il cambiamento, ponendo una condizione con If..Then
Private Sub Worksheet_Change(ByVal Target As Range)
If Target = 25 Then 'se il valore immesso nella cella uguale (esempio: 25), allora
Target.Interior.ColorIndex = 3 'si colora la cella di rosso
End If
End Sub

http://ennius.interfree.it/ Pagina 291


MANUALE VBA X EXCEL

http://ennius.interfree.it/ Pagina 292


MANUALE VBA X EXCEL
Progetto Rubrica Indirizzi.
Utilizzo: gestione di un database realizzato con Excel ad uso rubrica per indirizzi.
Viene presentata una semplice rubrica per indirizzi, utilizzando alcune delle procedure e degli strumenti
visti nei precedenti paragrafi di questa sezione. Impiegheremo anche una UserForm, finora non ancora
analizzata, la useremo per introdurre i dati nel nostro database. Cureremo anche la veste grafica per
ottenere un effetto gradevole. Tutto il progetto si affida a due soli fogli: il primo il foglio di apertura,
dove consulteremo l'archivio attraverso una Casella combinata (Combobox) che riporter tutti i nomi
presenti nel database, riportati in ordine alfabetico: cliccando sul nome desiderato, lo selezioneremo
e, nelle celle destinate ai dati correlati al nome selezionato, appariranno l'indirizzo, la citt, il cap, la
provincia, i telefoni, il fax. Queste celle sfruttano la funzione =CERCA.VERT. Nella foto sotto vediamo
come si presenta la pagina; la freccia indica la Casella combinata; in alto vediamo due
Commandbutton: "Inserisci Nuovi Dati" che aprir la UserForm con le caselle per l'inserimento di nuovi
dati, ed il pulsante "Modifica Dati" che aprir il secondo foglio (il database) sul quale potremo
modificare dati esistenti. Il terzo Commandbutton, sulla destra in basso, salva ed esce da excel,
chiudendolo. Se scaricherete il file, vedrete il codice associato ad ogni pulsante. Ricordo che per
lavorare sul codice di oggetti presi dalla "Casella degli Strumenti" o "Strumenti di controllo", necessario
entrare in "Modalit progettazione" cliccando sull'icona della "Squadra" presente sulla finestra degli
strumenti di controllo.

Sotto vediamo la UserForm richiamata dal pulsante "Inserisci nuovi dati". E' qui che dovremo inserire,
riempendo le relative caselle, i dati riguardanti il nuovo nominativo. Una volta completati tutti i campi,
si potr premere il pulsante "Registra", il quale, sempre via codice, copier il contenuto dei campi sul
secondo foglio, quello che contiene l'archivio dati (il database). E' presente un istruzione che
verificher che almeno il cognome e nome siano scritti, altrimenti si rifiuter di registrare i dati. Volendo
annullare e uscire, sar sufficiente premere il pulsante "Esci".

La foto sotto quella del secondo foglio, che contiene l'archivio dei dati; presente un'istruzione che
all'inserimento di un nuovo nominativo, automaticamente verr posizionato nel giusto ordine
alfabetico. Il pulsante "Indietro" consente di ritornare al foglio consultazione/inserimento. (primo foglio)

http://ennius.interfree.it/ Pagina 293


MANUALE VBA X EXCEL

Chi ha un p di dimestichezza con il Vba, potr leggere le istruzioni direttamente entrando nell'editor di
visualbasic.
File consultabile e scaricabile: Rubricas.zip 35 Kb

http://ennius.interfree.it/ Pagina 294


MANUALE VBA X EXCEL
Salvare (meglio: copiare) un file sul floppy. (31/05/03)
Un esigenza che spesso sentiamo quella di salvare il lavoro fatto oltre che sul nostro hard-disk, anche
facendone una copia su un floppy. Pratica seguita anche quando si voglia rendere disponibile una
copia di un file su altri computer, magari posti nello stesso ufficio ma non collegati in rete, oppure per
tutti coloro che a fine lavoro vogliono crearsi una copia di riserva da conservare su un floppy. In questo
esercizio prenderemo in esame la copia della cartella aperta su cui stiamo lavorando, quindi un file
.xls.
La procedura di base, quella che serve per copiare il file semplice: si basa sulla creazione di una
variabile sfruttando il metodo CreateObject("Scripting.FileSystemObject"), ed assegnando poi alla
variabile il percorso dove si trova il file da copiare, e la destinazione dove il file dovr essere copiato.
(Ricordo che per "percorso" si intende, in sequenza : 1) l'unit dove risiede il file - 2) la cartella ed ev.
sottocartella dove risiede il file - 3) il nome del file con l'estensione). L'istruzione sarebbe molto semplice,
vediamola (i nomi dei percorsi e dei file sono di esempio):
Set fs = CreateObject("Scripting.FileSystemObject")
fs.CopyFile "C:\ExcelWeb\Macedonia.xls", "A:\Macedonia.xls"
Dove: con Set fs settiamo una variabile CreateObject ("Scripting.FileSystemObject"), mentre con il
metodo CopyFile (assegnato a fs) indichiamo (tra doppi apici) il percorso del file da copiare, virgola,
seguita dal percorso per la destinazione, cio dove vogliamo che il file venga copiato (anche questo
percorso messo tra doppi apici).
Bastano solo queste due righe per eseguire la copia. Dovremo per munire la nostra routine di controlli
per evitare che si generino errori, i pi ricorrenti possono essere:
Il file da copiare non viene trovato, o perch non ancora creato, o perch si trova in un percorso
diverso da quello impostato nelle istruzioni, o addirittura perch il nome del file errato.
Il floppy non stato inserito nel lettore di floppy (l'unit A:\).
Il file pi grande (in byte) della dimensione che un floppydisk pu contenere (1.437 kb)
Inoltre sarebbe opportuno decidere di volta in volta il nome con il quale vogliamo sia nominata la
copia del file. Questa necessit si rivela quando, salvando periodicamente lo stesso file di origine, lo
dovremo identificare nel tempo. Sarebbe comodo chiamare la copia (nell'esempio : Macedonia)
Macedonia1, Macedonia2, ecc. oppure usare una data (senza le barre ( / ) : Windows NON consente
di usare barre ( / ) per definire nomi di file), come Macedonia310503, oppure Macedonia010603, ecc.
ecc.
Per fare ci dovremo rendere variabile la componente "nome file" inserita nel percorso di destinazione,
e dovendo per forza assegnare un nome, useremo una cella del foglio di lavoro dove scriveremo detto
nome, e useremo poi il riferimento a questa cella (magari assegnando la cella a una variabile) e
richiamare questa nel percorso di destinazione. A questo punto dovremo impiegare un altro controllo
per verificare che nella cella scelta esista un nome. Per il controllo Errori useremo queste impostazioni:
On Error Resume Next - posto immediatamente dopo il nome della routine.
Resume - posto immediatamente prima della fine routine (End Sub).
Err.Number - usato per intercettare la condizione : se si verifica l'errore numero....
Vediamo quindi l'intera routine, in verde i soliti commenti:
Sub SalvasuFloppy()
On Error Resume Next
'sotto: usiamo la cella C1 per scrivere il nome con il quale verr copiato il file, e
quindi 'controlliamo con : se il Range("C1") vuoto, allora avvisiamo ed usciamo
dalla routine
If Range("C1") = "" Then
MsgBox "DEVI INSERIRE UN NOME PER LA COPIA DEL FILE"
Range("C1").Select
Exit Sub 'si esce dalla routine
End If
'usiamo la variabile "nome" per memorizzare il contenuto della cella C1
nome = Range("C1").Value
'importante: poich si presuppone di voler copiare un file esistente, su cui abbiamo
'appena lavorato, necessario salvarlo perch le modifiche vengano salvate
sull'origine 'prima della sua copia sul floppy.
ThisWorkbook.Save
'ora controlliamo la dimensione del file che vogliamo copiare, dimensionando una
variabile "miadime" per "leggere" (con la funzione FileLen( "percorso e nome")) la
http://ennius.interfree.it/ Pagina 295
MANUALE VBA X EXCEL
dimensione file, 'se sar maggiore rispetto allo spazio di un floppy vuoto, si esce dalla
routine avvisando.
Dim miadime
miadime = FileLen("C:\ExcelWeb\Macedonia.xls")
If miadime > 1457000 Then
MsgBox "LA DIMENSIONE DEL FILE E'TROPPO GRANDE. IMPOSSIBILE COPIARE"
Exit Sub
End If
'sotto vediamo l'istruzione che provvede a copiare, dove, nel percorso di
destinazione, '(A:\) usiamo il nome preso nella cella C1
Set fs = CreateObject("Scripting.FileSystemObject")
fs.CopyFile "C:\ExcelWeb\Macedonia.xls", "A:\" & nome & ".xls"

'sotto: inseriamo i due controlli errore, in cui sfruttando il numero dell'errore di run-time
'che si genererebbe se non venisse trovato percorso o nome del file da copiare
(primo 'controllo) o se non fosse presente un floppy nel lettore di floppy (secondo
controllo), si 'esce dalla routine.
If Err.Number = 53 Then
MsgBox "FILE DI ORIGINE NON TROVATO"
Exit Sub
End If

If Err.Number = 71 Then
MsgBox "INSERIRE UN FLOPPY NEL LETTORE"
Exit Sub
End If
'se tutto andato liscio, si avvisa con questo messaggio:
MsgBox "COPIA ESEGUITA !"
'si cancella dalla memoria la variabile fs
Set fs = Nothing
Resume
End Sub

Mi sembra sia spiegato tutto abbastanza bene,

http://ennius.interfree.it/ Pagina 296


MANUALE VBA X EXCEL
Procedura per salvare un solo foglio di una cartella di lavoro. (26/05/03)
Questo esercizio applicabile ogni qualvolta si voglia salvare un unico foglio (non tutta la cartella) di
lavoro. Spesso usiamo Excel per gestire una piccola amministrazione che contempli l'emissione di
fatture e/o anche di documenti di trasporto (DDT). Necessit comune ad entrambi i documenti, al di l
delle routine usate per la registrazione degli stessi in appositi fogli archivio, quella di poter salvare una
copia del documento, e solo quello. In questo modo, oltre a disporre di un file .xls di dimensioni pi
piccole rispetto alla dimensione della cartella usata per la gestione dell'attivit, potremo gestire una
copia di una fattura, per rivederla per consultarla e/o per ristamparla. La maniera pi semplice
questa routine che apre la classica finestra "Salva con nome", in cui potremo definire noi il nome e la
cartella dove salvare la copia della fattura. Questa routine la abbineremo ad un pulsante "Salva
Fattura" che terremo sul foglio adibito alla compilazione della fattura:
Sub Salvafattura()
'copiamo il foglio usando il nome del foglio, in questo esempio "Fatture", e verr
creato un 'nuovo foglio che sar una copia del foglio Fatture:
Sheets("Fatture").Copy
'apriamo la finestra "Salva con nome". Dopo che avremo assegnato il nome e
selezionata la cartella di destinazione, premeremo il pulsante "Salva"
Application.Dialogs(xlDialogSaveAs).Show
'la copia del solo foglio che abbiamo copiato, stata salvata, e a questo punto
chiudiamo 'il foglio-copia attualmente in vista a video, ritornando al foglio originale
della cartella di 'lavoro.
ActiveWindow.Close
End Sub
Come vedete, tre semplici righe di istruzione ci hanno aiutato. La copia ora sar disponibile da
consultare quando vorremo. Nella routine sotto invece consideriamo una variante pi "automatizzata"
che ci consentir di saltare la presentazione della finestra "Salva con nome", in quanto sia il nome con il
quale salvare la copia della fattura, sia il percorso, lo assegneremo usando il codice vba. Come nome
sceglieremo la soluzione pi ovvia : il numero fattura che inevitabilmente assegneremo alla fattura, e
come percorso useremo una cartella precedentemente stabilita. vediamo la routine, come sempre
associata ad un pulsante posto sul foglio fattura:
Sub SalvafatturaAut()
Dim X As String 'questa variabile assimila il dato che in una cella, per prendere il
nome,
'con cui salvare il solo foglio, io ho messo la A1, voi metterete la cella che porta il
numero 'della fattura, vedi sotto
X = "Fattura" & Range("A1").Value
Sheets(1).Copy 'creo un nuovo foglio copia del foglio 1 (come esempio)
'queste sotto sono le istruzioni in cui si deve fornire il percorso, io ho messo C:\Temp,
voi 'metterrete la vostra cartella scelta per contenere le copie fatture:
ActiveWorkbook.SaveAs Filename:="C:\Temp\" & X & ".xls", FileFormat:= _
xlNormal, Password:="", WriteResPassword:="", ReadOnlyRecommended:=False _
, CreateBackup:=False
ActiveWindow.Close
End Sub
E la copia verr salvata in C:\Temp con il nome : Fatturanumerodellafattura.

http://ennius.interfree.it/ Pagina 297


MANUALE VBA X EXCEL
Sfruttare gli Eventi per posizionare le istruzioni. (24/04/03)
Davo per scontato che tutti i pellegrini che usano il vba, avessero sufficientemente chiaro che cos' un
evento e come sfruttarlo, ma dalle numerose richieste che mi giungono, ritengo di cercare di fare un
p di chiarezza, se ci riesco.
Per "EVENTO" si intende l'"AZIONE" che si deve compiere per ATTIVARE le istruzioni abbinate all'"Oggetto"
di cui l'evento fa parte. L'EVENTO si pu verificare per nostra azione diretta (come la pressione su un
pulsante (es.: evento Click)), o in conseguenza di azioni indirette che compiamo noi sul foglio o sulla
cartella di lavoro (come la selezione di un foglio di lavoro (es.: evento Activate)). Gli EVENTI non sono
uguali per tutti gli Oggetti; ogni Oggetto possiede eventi propri, non necessariamente simili ad altri
Oggetti.
L'oggetto Workbook (Cartella di lavoro) per esempio possiede l'evento Open, che altri oggetti non
hanno, e che, indipendentemente dalla nostra volont, si verifica tutte le volte che in Excel apriamo
una cartella di lavoro. Potremo per esempio sfruttare questo evento, per far apparire un messaggio di
saluto, o una userform, tutte le volte che apriremo la cartella (o file .xls che dir si voglia). Come? ma
semplicemente inserendo l'istruzione, tramite l'editor di visual basic, nell'apposita finestra. (vedere, su
questa sezione, "Editor di Visual Basic", dove ci sono foto che illustrano le spiegazioni.)
L'oggetto WorkSheet (Foglio di lavoro) non possiede l'evento Open, ma l'evento Activate, che NON si
verifica quando si apre la cartella di lavoro ma SOLO quando si attiva un Foglio, selezionandolo.
E' necessario quindi che ogni pellegrino, si documenti sul significato di ogni evento, per capire come
sfruttarlo e con quale sequenza si verifica rispetto ad un'altro evento dello stesso Oggetto. In genere,
nella finestrina degli Eventi, gli stessi sono elencati in ordine di sequenza. Rifacendoci al WorkSheet,
evidente che l'evento Deactivate (cio quando il foglio perde lo stato attivo, per es. perch si
seleziona un'altro foglio) si verifica sempre DOPO che si verificato l'evento Activate, ed infatti nel
men degli eventi appare dopo. Non questa la sede per elencare tutti gli Eventi di tutti gli Oggetti. La
Guida in linea del visual basic sufficientemente documentata : basta scrivere nella finestra "Indice"
della guida, la parola "Events", e nella finestra 3 "Selezionare un argomento" troverete l'elenco di tutti gli
eventi, singoli, o raggruppati per oggetti.
Suggerisco quindi, anzich scrivere a me per domande generiche sugli eventi, di munirsi della
necessaria pazienza e di andare a leggersi la guida, che almeno su questi argomenti chiara e ben
fatta. Questo sotto l'esempio tratto dalla guida, e che riguarda l'evento Change del WorkSheet
Evento Change
Si verifica quando celle del foglio di lavoro sono modificate dall'utente o mediante
un collegamento esterno.
Private Sub Worksheet_Change(ByVal Target As Range)
Target Specifica l'intervallo modificato. Pu essere costituito da pi di una cella.
Osservazioni
Questo evento non si verifica quando i valori contenuti nelle celle cambiano
durante una fase di ricalcolo. Utilizzare l'evento Calcola per intercettare un nuovo
calcolo nel foglio.
Esempio
Questo esempio modifica il colore delle celle modificate su blu.
Private Sub Worksheet_Change(ByVal Target as Range)
Target.Font.ColorIndex = 5
End Sub
Come vedete, l'esempio pi che chiaro. Basta leggere.....

http://ennius.interfree.it/ Pagina 298


MANUALE VBA X EXCEL
Lavorare con gli Shapes. (19/06/03)
Gli Shapes (le Forme) sono un "territorio" che non conosco molto bene, ma in seguito ad una richiesta,
visto poi che non difficile capirne le basi, presento un esercizio che forse pu interessare altri
pellegrini.
Intanto cosa sono gli Shapes: sono "oggetti" appartenenti al gruppo "Disegno", quali una Forma, una
figura a mano libera, un rettangolo, un cerchio, una casella di testo, un oggetto OLE o un'immagine, e
che si possono inserire sul foglio di lavoro semplicemente selezionando l'icona dell'oggetto posta nella
finestra "Disegno", e poi, cliccando in un punto del foglio di lavoro, trascinare tenendo premuto il
pulsante sinistro, per ottenere il dimensionamento voluto. Ogni oggetto Shape pu essere inserito non
solo manualmente, ma anche tramite codice vba: sconsiglio alle "reclute" l'inserimento tramite codice,
visto che la creazione di uno Shape, che peraltro si ottiene con il metodo AddShape, comporta la
definizione di un numero elevato di istruzioni (e a secondo il tipo di Shape scelto, di "nodi" )che servono
per il posizionamento dello Shape sul foglio di lavoro, oltre ai valori che ne determinano la dimensione
e le caratteristiche, operazione complessa per chi vuol compilarlo da solo. Per verificare quanto
appena detto, attivate il "registratore di macro", date un nome alla macro o lasciate il nome che
propone Excel, e poi inserite uno Shape, posizionandolo e dimensionandolo, agendo sui circoletti che
appaiono intorno al perimetro dello Shape, e dategli un colore; ad operazione ultimata, stoppate il
registratore e recatevi nell'editor di visual basic, su un modulo troverete la macro che Excel ha
compilato per voi, e vedrete tutte le istruzioni che servono a "creare" e impostare lo Shape. Qui sotto vi
riporto un esempio per creare uno Shape rettangolo :
ActiveSheet.Shapes.AddShape(msoShapeRectangle, 108.75, 30#, 84.75, 30#).Select
Selection.ShapeRange.Fill.Visible = msoTrue
Selection.ShapeRange.Fill.Solid
Selection.ShapeRange.Fill.ForeColor.SchemeColor = 11
Selection.ShapeRange.Fill.Transparency = 0#
Selection.ShapeRange.Line.Weight = 0.75
Selection.ShapeRange.Line.DashStyle = msoLineSolid
Selection.ShapeRange.Line.Style = msoLineSingle
Selection.ShapeRange.Line.Transparency = 0#
Selection.ShapeRange.Line.Visible = msoTrue
Selection.ShapeRange.Line.ForeColor.SchemeColor = 64
Selection.ShapeRange.Line.BackColor.RGB = RGB(255, 255, 255)
Ogni Shape comunque inserito, viene identificato da un nome che identifica il "tipo" di oggetto, ed un
numero progressivo per ogni oggetto Shape inserito, indipendentemente dal "tipo". Ad esempio, se
inseriamo un Rettangolo, nelle istruzioni andr identificato con Shapes("Rectangle 1"), se ne inseriamo
un secondo, il suo identificativo sar Shapes("Rectangle 2"), se inseriamo un "ovale" il suo idendificativo
sar Shapes("Oval 3") e cos via.
Attenzione : se cancelliamo uno Shape e poi ne inseriamo uno nuovo, il numero assegnato al nuovo
NON sostituisce il numero di quello cancellato, ma andr in progressione; Excel memorizza infatti tutti gli
oggetti Shape inseriti, anche quelli cancellati, ed assegna il numero successivo
Ma come caspita facciamo a conoscere con quale nome e numero Excel (il suo vba) identifica un
oggetto, visto che quando lo si inserisce (con una routine come quella sopra) col metodo AddShape, il
nome dell'oggetto viene assegnato usando una costante (tipo : msoShapeRectangle ) (vedi elenco
costanti) e non con Shapes("Rectangle X") ?
Mi permetto di suggerire un metodo pratico e veloce: inseriamo manualmente il o i nostri Shapes,
senza curarci di registrare niente; una volta inserito/i, attiviamo il registratore di macro indi clicchiamo
sul o sugli Shapes; ora fermiamo la registrazione e nella macro creata da Excel, andiamo a leggere:
troveremo il o i nomi con relativo numero indice e l'istruzione Select. Baster ricordarsi con quale ordine
abbiamo cliccato (selezionato) gli Shapes per trovare il relativo nome, un esempio:
ActiveSheet.Shapes("Rectangle 1").Select
ActiveSheet.Shapes("Rectangle 5").Select
ActiveSheet.Shapes("AutoShape 3").Select
ActiveSheet.Shapes("Freeform 2").Select
ActiveSheet.Shapes("AutoShape 4").Select
ActiveSheet.Shapes("Rectangle 6").Select
Un'altra possibilit di intervento sugli Shapes, ma questa la facciamo dal foglio di lavoro, quella di
richiamare, cliccando col destro del mouse sullo Shape, un men contestuale, e da questo scegliere
"Aggiungi testo" (e potremo inserire una parola o una frase) oppure scegliere "Formato Forme" che
http://ennius.interfree.it/ Pagina 299
MANUALE VBA X EXCEL
aprir la relativa finestra dove saranno possibili tutta una serie di regolazioni, dalla scelta del font ed il
suo colore, al centraggio del testo, al colore di fondo dello Shape, la sua trasparenza, la possibilit di
impostare sfumature di colore, bloccarlo o meno, ecc. ecc. Tutte operazioni che comunque possiamo
fare dopo aver attivato il registratore di macro, in modo da poter curiosare, ed apprendere, come il
codice imposta tutti i passaggi che noi abbiamo fatto.
Ma veniamo all'esercizio: vogliamo "disegnare" sul foglio delle aree da usarsi come "mappe", cio
identificativi di zone, come se si fosse su una cartina topografica. Vogliamo che ad ogni click si attivino
delle istruzioni, e che lo Shape cambi colore : ad ogni colore, vogliamo che vengano eseguite istruzioni
diverse. Useremo lo Shape come se fosse un Commandbutton, al quale ad ogni click facciamo
cambiare la Caption e quindi le istruzioni correlate.
Per prima cosa, useremo, per il disegno a mano libera, la Forma: "Figura a mano libera", reperibile dal
men Disegno/Forme/Linee/Figura a mano libera, cos come nella sottostante immagine:

Realizzeremo un perimetro che chiuderemo ad anello con un doppio click di sinistro, e dopo aver
impostato un colore, e regolata la trasparenza al 50%, otterremo una cosa del genere:

ora prepariamo una macro, dandogli un nome, nella quale inserire le nostre istruzioni. (quando la
macro sar compilata, tornando col destro sullo Shape, nel men contestuale sceglieremo: "Associa
macro" associandogli il nome della macro. Le istruzioni sono semplici, unica cosa che sottolineo la
necessit di selezionare lo Shape (per identificarlo) usando il metodo Select di cui Selection una
propriet che utilizzeremo usando l'istruzione With :
Sub Dimmi()
ActiveSheet.Shapes("Freeform 1").Select 'si seleziona lo shape
With Selection 'con la selezione attiva:
'sotto: Se il colore dello shape ugualr a verde, allora
If .ShapeRange.Fill.ForeColor.SchemeColor = 13 Then
'mi cambi in suo colore in giallo
.ShapeRange.Fill.ForeColor.SchemeColor = 3
'ed esegui queste istruzioni (io ho messo una semplice messagebox, ma potranno
essere 'eseguite qualsiasi tipo di istruzioni) :
MsgBox "Sono uno Shape"
Range("A1").Select 'per deselezionare lo shape

http://ennius.interfree.it/ Pagina 300


MANUALE VBA X EXCEL
Else 'altrimenti (cio se il colore non verde, e infatti sar giallo dopo il primo click)
'esegue queste altre istruzioni (nell'esempio ancora un messaggio)
MsgBox "Buongiorno a tutti"
'ora colora di nuovo di verde, creando l'alternanza per la condizione If
.ShapeRange.Fill.ForeColor.SchemeColor = 13
Range("A1").Select 'per deselezionare lo shape
End If
End With
End Sub
E questo, a parte il messaggio che non mostro, l'effetto del cambio colore:

Come vedete non difficile capire le istruzioni, l'unica cosa, non sono riuscito a trovare i codici colori
usati da Fill.ForeColor.SchemeColor, consiglio i volenterosi, di selezionare sul foglio lo Shape, attivare il
registratore di macro, e dalla finestra Formato Forme, cominciare a cambiare colore all'oggetto; in
questo modo, a fine registrazione, avrete i codici colore scritti nella macro che il registratore avr
creato. Potrete segnarveli e poi cancellare la macro.

Buon lavoro

http://ennius.interfree.it/ Pagina 301


MANUALE VBA X EXCEL
Sintassi (21/07/03)
Sicuramente uno degli aspetti nella compilazione di codice, come fare a scrivere, cio quale sintassi
usare, per far capire ad Excel determinati parametri. Un veloce esempio per illustrare cosa si intende,
viene da una recente domanda postami: "come scrivere l'istruzione per far capire ad Excel che i
riferimenti alle celle (cio gli indirizzi cella) che delimitano una zona che si intende selezionare, sono
rappresentati da valori scritti in due celle" . Simuliamo l'esempio: in A1 scriviamo C1, e in B1 scriviamo
H1:
A B C D E F
1 C1 H1
2
vorremo quindi selezionare la zona compresa tra C1 ed H1. La prassi di usare due celle per scriverci i
riferimenti ad altre celle, deriva dal fatto che si vogliono rendere variabili le zone da selezionare di volta
in volta, e in questo modo saremo noi ad indicare le aree da selezionare modificando i riferimenti nelle
due celle fisse (A1 e B1 o quelle che preferite voi). Non possiamo scrivere espressioni strane, tipo
Range("A1.Value:B1.Value").Select
o similari, perch il debugger ci d una una mazzolata in testa, e ci rimanda con foglio di via, all'asilo.
Per fortuna che ogni tanto la nostra cpu si rimette a funzionare, ed elabora: cosa ci vuole perch Excel
possa identificare una zona? I riferimenti alle celle ! Assegniamo quindi a due variabili questi riferimenti:
X = Range("A1").Value (ed X sar uguale a C1)
Y = Range("B1").Value (ed X sar uguale a H1)
Ora, per capire il perch della sintassi che adopereremo, bisogna precisare che il riferimento A1 in
Range("A1") (lo stesso per B1) viene visto come un riferimento letterale, cio una "stringa"e quindi posto
tra doppi apici; X e Y sono invece variabili (di tipo Variant), e NON vanno messe tra doppi apici
(scusate, ma meglio non mi riesce spiegarmi), per cui una istruzione come Range(X : Y) dovrebbe
andare bene, invece no perch ci sono i due punti ( : ) che indicano l'intervallo, che non sono di tipo
Variant, ma testo e quindi i due punti vano messi tra due doppi apici, concatenandoli con il segno di
concatenazione: & tra i due valori Variant - vediamo quindi la giusta sintassi:
Range(X & ":" & Y).Select
Quello che poi faremo con la selezione, non affare di questa pagina, ma la selezione C1:H1 ci sar.
Vediamo ora il caso in cui si voglia indicare un intervallo i cui la sintassi per i riferimenti mista: cio uno
dei riferimenti in stile notazione A1, e l'altro e reperito tramite una variabile. Supponiamo quindi di
voler identificare (e selezionare) tutte le righe che intercorrono tra la prima riga (la numero 1, ma potr
essere qualunque altra, ma definita a priori) e la riga corrispondente alla cella in quel momento attiva.
Non sapendo prima quale sar la cella attiva, useremo nelle istruzioni, una variabile che identifichi la
riga della cella attiva, tipo:
X = ActiveCell.Row (ed X sar uguale al numero di riga della cella selezionata in quel momento)
Rows(X).Select
L'istruzione giusta e con Rows(X) rispettiamo quanto sopra detto e selezioniamo la riga intera. Se ora
per cerchiamo di usare la sintassi appena vista per selezionare tutte le righe tra la riga numero 1 e la
numero X, scrivendo cos:
Rows("1:X").Select
otteniamo un bell'errore di run-time: "tipo non corrispondente"; infatti X una variabile Variant e come
tale non pu essere inserita in una "stringa" (gli intervalli messi tra doppi apici), a meno che non si usi la
sintassi prevista, cio tra due doppi apici e due segni di concatenazione ( & ). Questa sar allora la
giusta istruzione (in rosso la correzione):
X = ActiveCell.Row
Rows("1:" & X & "").Select
Attenzione! questo tipo di istruzioni (selezioni di intervalli) dovranno risiedere in macro appositamente
costruite e non bisogna inserirle nell'evento WorkSheet.Selection_Change; il perch facile capirlo:
l'attivazione delle istruzioni si basa appunto su un cambio di selezione, che quello che le istruzioni in
pratica fanno: cominciano a selezionare la prima riga (per proseguire fino alla riga X) ma l si fermano
in ossequio alle istruzioni che vengono ripetute, e trovando la prima riga come attiva, l si fermano.

Altro esempio
Ora vediamo un esempio in cui si vogliano salvare o aprire file i cui nomi sono rappresentati da due o
tre valori presenti in altrettante celle di un foglio di lavoro. Un tipico esempio potrebbe essere quello di
un foglio archivio fatture, dal quale, tramite macro, vogliamo aprire per consultazione una fattura
salvata in precedenza. Vediamo la situazione:
http://ennius.interfree.it/ Pagina 302
MANUALE VBA X EXCEL
N.Fatt Data Nominativo Imponibile ImportoIva TOTALE
1 1 07-08-03 Filippini Spa 1.000 200 1.200
2 2 31-08-03 Giocondi srl 1.500 300 1.800
3 3 31-08-03 Lippetti F. & C 2.000 400 2.400
e che si sia deciso, nel salvataggio del foglio emissione fattura, di usare, come nome da assegnare alla
copia, il N.Fatt, la data, ed il nominativo cliente, per cui il file salvato si presenterebbe:
107-08-03Filippini Spa.xls
oppure avremmo potuto salvarlo con nominativo, data, n.fatt. non ha importanza la chiave che
sceglieremo come ordinamento per il salvataggio, l'importante sar seguire sempre lo stesso ordine, sia
per salvare che per aprire poi una copia fattura. Una precisazione: visto che usiamo anche il campo
"Data" come componente del nome da salvare, ricordo che Windows NON consente l'uso di barre ( / )
nei nomi di files, per questo usiamo il trattino ( - ) come separatore di data. Ora dovremo decidere
quale campo scegliere da selezionare per attivare le istruzioni di apertura file, tenendo presente che
dovremo "concatenare" gli altri due campi che formano il nome del file da aprire. Supponiamo di
selezionare un campo "Nominativo": dovremo usare una variabile che "leghi" insieme i valori di tre celle:
il Nominativo , che sar Activecell in quanto lo selezioneremo
la Data, che sar una cella a sinistra rispetto all'Activecell (useremo Offset per reperire il valore)
il N.Fatt, che sar due celle a sinistra rispetto all'Activecell (useremo Offset per reperire il valore)
Quindi la sintassi da usare per comporre la variabile "nome" sar:
nome = Activecell.Offset(0, -2) & Activecell.Offset(0, -1) & Activecell
Selezionando quindi "Filippini Spa", "nome" sar uguale a: 107-08-03Filippini Spa
Ovviamente la sequenza della concatenazione e quindi degli Offset dipender dal campo che
decideremo di usare come chiave iniziale di apertura, se scegliessimo di selezionare un numero di
fattura, rendendo questo Activecell, "nome" sarebbe uguale a:
nome = Activecell & Activecell.Offset(0, 1) & Activecell.Offset(0, 2)
La routine per l'apertura della copia diventa (col primo caso):
Sub aprifile()
Dim X As String
nome = Activecell.Offset(0, -2) & Activecell.Offset(0, -1) & Activecell
X = "C:\VostraCartella\" & nome & ".xls"
Workbooks.Open Filename:=X, ReadOnly:=False
End Sub

Aggiorner questa pagina con altri "suggerimenti".

Buon lavoro.

http://ennius.interfree.it/ Pagina 303


MANUALE VBA X EXCEL
Utilizzare il VBA al posto della Funzione SOMMA.SE (05/05/03)
Ancora un esercizio con un doppio ciclo For Each ... Next per sostituire la funzione Somma.Se non
facilmente applicabile in uno schema di tabella come quello che prendiamo in esame.
Questo esercizio rivolto a tutti coloro che disponendo di una tabella con inseriti dati alla rinfusa,
vogliano reperire totali di valori, da riportare in un'altra tabella. Per "totali di valori" si possono ricercare
importi, numeri, numero presenze, ore, ecc. ecc. riferiti a nominativi precisi, quali Ditte, Operai,
Camere, Fascicoli, Nominativi in genere, Titoli i libri o di film, e chi pi ne ha pi ne metta. E' molto
importante definire lo schema di una tabella, cio come impostare campi (colonne) e record (righe),
molto dipende infatti da una loro impostazione precisa e ordinata, scegliendo la chiave di
registrazione pi opportuna. Nell'esempio prenderemo quindi come chiave di registrazione una Data.
Vediamo un esempio nel quale per ogni data immessa nella colonna A, abbiamo bisogno di registrare
quanti interventi eseguiamo presso una determinata Ditta. Useremo quindi le colonne seguenti la A,
per riportare il numero di interventi e a lato a quale ditta si riferiscono. Disponendo di pi operatori,
destineremo tante coppie di colonne per quanti operatori lavoreranno. Nell'esempio ne ho considerati
5, quindi 10 colonne.
Cosa vogliamo sapere? Desideriamo tenere sotto controllo il TOTALE del numero di interventi per
Cliente (ditta). Il risultato lo vogliamo in altra zona del foglio (ma potrebbe essere su un altro foglio).
Per comodit visiva per la zona di raccolta totali uso le celle da A16 a C27: nella colonna A
riporteremo i nomi delle Ditte e nella colonna C otterremo i totali per ogni ditta.

Abbiamo bisogno quindi di un ciclo che per ogni ditta riportata in colonna A, zona "raccolta", "spazzoli"
tutta la zona della tabella principale alla ricerca dello stesso nome ditta, e trovatala, cominci a
totalizzare il valore che si trova nella cella a sinistra. Per questa "spazzolatura" (ricerca) useremo un altro
ciclo interno al primo che, munito di un totalizzatore, restituisca alla fine la somma dei valori trovati.
Questo totale lo affideremo alla cella della colonna C, stessa riga del nome cercato. Per ovviare
all'ipotesi che i nomi scritti nella tabella degli interventi possano differire per maiuscole/minuscole dallo
stesso nome scritto nella tabella di raccolta, usiamo nel modulo che ospita la routine, sezione
"Generale - Dichiarazioni", l'istruzione : Option Compare Text
Option Compare Text
___________________________________________________________________
Sub CercaeSomma()
Dim CL As Object
Dim C As Object
'riga sotto: per ogni cella nel range A16:A27
For Each CL In Range("A16:A27")
'riga sotto: controllo se nella cella esiste un nome, se le cella vuota, passo alla
'successiva (con l'ultimo next)
If CL.Value = "" Then GoTo 10
'altrimenti inizio il secondo ciclo per controllare tutte le celle nel range D1:Y59
For Each C In Range("C2:K13")

http://ennius.interfree.it/ Pagina 304


MANUALE VBA X EXCEL
'se trovo in nome che in A (nel CL in quel momento attuale)
If C.Value = CL.Value Then
'allora incremento un totale col valore che nella cella accanto al nome trovato
tot = tot + C.Offset(0, -1).Value
End If
'controllo tutte le celle con Next C per controllare l'attuale nome
Next C
'finito il ciclo interno, assegno alla cella della colonna H, stessa riga di CL, il totale
ottenuto
CL.Offset(0, 2).Value = tot
'poi azzero il contatore
tot = 0
10:
'e proseguo il ciclo per la successiva cella in A che ripete il ciclo interno
Next
End Sub
In pratica il primo ciclo controlla, dall'inizio alla fine, tutte le celle del Range A16:A27, e per ogni cella,
attiva il secondo ciclo che ricerca nel Range C2:K13 tutte le celle il cui valore corrisponde, sommando i
valori che sono nella cella a sinistra (Offset(0, -1)). E' evidente che se le aree saranno diverse baster
indicare negli appositi range i riferimenti che ci necessitano. Se poi la tabella di destinazione risiedesse
su un'altro foglio, oltre ovviamente a definire il range diverso in cui si troveranno i nomi ditte di cui
vogliamo il totale, useremo l'accortezza di lanciare la macro da questo foglio, e nelle istruzioni
cambier solamente l'indicazione della zona dove effettuare la ricerca, aggiungendo il nome del
foglio, cos:
For Each C In Worksheets(1).Range("C2:K13")

Buon lavoro.

http://ennius.interfree.it/ Pagina 305


MANUALE VBA X EXCEL
Sostituzione di un valore esistente con un altro valore.
Lavorando con tabelle o elenchi, pu capitare di voler aggiornare dei dati, con altri dati nelle stesse
celle. Si potrebbe voler modificare, per esempio, un'aliquota iva in un elenco di articoli, che serve a
calcolare il prezzo di vendita (e quindi un valore numerico), oppure un valore percentuale di ricarico
(sempre valore numerico), o ancora un nome di un agente in una lista di calcolo provvigioni (valore
testo), o una data di scadenza formato data), insomma qualunque dato ci serva di voler modificare,
dove esistano pi valori uguali (se ci fosse da modificare un solo valore, forse conviene farlo
manualmente) e PURCHE' tutti i dati da modificare siano nello stesso campo (colonna), anche se su
righe non conseguenti. Se i valori da modificare fossero sempre gli stessi (modificando e modificatore),
potremmo usare una routine con questi valori gi impostati nel codice stesso, ma per rendere pi
gestibile la cosa, in modo da poter definire di volta in volta qual' il valore da modificare e qual' il
valore che va in sostituzione, e su quale campo eseguire l'intervento, useremo tre variabili per
l'assegnazione di tre celle dove scriveremo: il valore che vogliamo modificare(A1), il valore che lo
sostituisce(B1), il riferimento alla colonna (campo) dove vogliamo effettuare le sostituzioni(C1).
Supponiamo quindi di avere un elenco cos formato (vedi sotto), e di dover provvedere alla modifica
dell'aliquota iva del 20 sostituendola con una nuova aliquota: 15 (utopia). In A1 scriveremo 20 (il valore
da modificare) in B1 scriveremo 15 (il valore in sostituzione) e in C1 il riferimento alla colonna relativa
all'inizio colonna dove intendiamo fare le sostituzioni (F2). L'elenco sar lungo (supponiamo) 300 righe.
A B C D E F G H
1 20 15 F
2 Codice Articolo Costo Ricarico Prezzo al.iva Imp.Iva Prezzo Ven
3
Questa sar la nostra routine che cercher nel range F2:F300 tutte le celle che portano il valore 20, e lo
sostituir col valore 15:
Sub FindValore()
Dim X, Y, Z, W 'dichiarazione variabili di tipo Variant (numeri o lettere)
X = Range("A1").Value 'assegnazione delle variabili alle celle, in questo caso : X=20
Y = Range("B1").Value 'nuovo valore in sostituzione : Y=15
Z = Range("C1").Value 'colonna su cui operare : Z=F
'assegnazione del Range di intervento (lunghezza: dalla cella 2 alla 300)
W = Z + "2:" & Z + "300"
'inizio ciclo ricerca
With Worksheets(1).Range(W) ' (W=F2:F300)
Set c = .Find(X, LookIn:=xlValues) 'c = cerca il valore X (in A1) da cercare in W
If Not c Is Nothing Then
firstAddress = c.Address
Do
c.Value = Y 'se X trovato, sostituzione del valore presente in c con Y (range B1)
Set c = .FindNext(c) 'prosecuzione del ciclo ricerca
If c Is Nothing Then
Exit Sub
End If

Loop While Not c Is Nothing And c.Address <> firstAddress


End If

End With
End Sub

Se avessimo voluto sostituire dei valori fissi (20 in 15), questa la routine (pi semplice):
Sub FindValoreFisso()

With Worksheets(1).Range(F2:F300) 'range in cui eseguire la ricerca


Set c = .Find(20, LookIn:=xlValues) 'si cerca il valore 20
If Not c Is Nothing Then
firstAddress = c.Address
Do

http://ennius.interfree.it/ Pagina 306


MANUALE VBA X EXCEL
c.Value = 15 'si sostituisce con il valore 15
Set c = .FindNext(c)
If c Is Nothing Then
Exit Sub
End If

Loop While Not c Is Nothing And c.Address <> firstAddress


End If

End With
End Sub

http://ennius.interfree.it/ Pagina 307


MANUALE VBA X EXCEL
Operazioni su numeri con risultato nella colonna a lato. (23/04/03)
E' proprio vero che le esigenze di ognuno di noi sono talmente varie che non possibile definire degli
esempi da standardizzare. Rimane tuttavia la possibilit di citare tutte le possibili applicazioni che si
presentano di volta in volta, cercando di spiegare le necessit occorrenti ai vari casi, e relative
soluzioni proposte, sperando cos di poter fornire esempi assimilabili per altre esigenze.
Questa volta riporto ancora un esercizio risolto con il solito ciclo For Each ...Next, ma in cui ovviamente
sono diversi, dagli altri esempi visti, le problematiche riscontrate.
Vediamo il problema : in una colonna in cui il numero di righe pu variare, sono inseriti dei numeri. si
richiede una macro che prenda il valore contenuto nella cella A1 e lo sottragga al valore contenuto
nella cella A2,
il risultato deve essere collocato nella cella B1 e cosi di seguito con la cella A2 sottratta ad A3 ed il
risultato in B2. Il tutto deve essere ripetuto fino a che la macro trova le celle della colonna A contenenti
un valore.
Forse un immagine spiega meglio cosa si vorrebbe ottenere:

In B1 abbiamo la differenza di A1-A2 (10-20=-10), in B2 la differenza di A2-A3 (20-30=-10), in B3 la


differenza di A3-A4 (30-50=-20), in B4 la differenza di A4-A5 (50-30=20), ecc. ecc.
La routine semplice: visto che non sapremo quanto sar lungo l'elenco nella colonna A, useremo la
funzione End per trovare l'ultima cella che contiene dati, quindi eseguiremo un ciclo che per ogni cella
della colonna A, otterr il valore della cella stessa in quel momento identificata, lo sottrarr al valore
della cella successiva (identificata con Offset(1, 0)) e questo risultato lo inserir nella cella a sinistra
rispetto alla cella in quel momento attiva, identificandola con Offset(0, 1). Questa la routine:
Dim CL As Object
'sotto: reperisco tutta l'area che contiene dati nella
'colonna A: dalla prima cella: Cells(1, 1) all'ultima trovata
'occupata: Cells(1, 1).End(xlDown)
Set zona = Range(Cells(1, 1), Cells(1, 1).End(xlDown))
'poi inizio il ciclo di ricerca con: per ogni CL (cella)
'contenuta in "zona"
For Each CL In zona
'nella cella accanto a quella selezionata (CL) la cella selezionata
'ma con CL.Offset(0, 1) identifico la cella, stessa riga (0) ed
'una colonna a destra) e in questa faccio fare la differenza tra la cella attiva e la
cella sottostante identificata con CL.Offset(1, 0)
CL.Offset(0, 1) = CL.Value - CL.Offset(1, 0)
'con Next si passa alla cella successiva alla prima selezionata, fino alla fine delle
celle 'presenti in "zona"
Next

End Sub
Un esercizio molto semplice ma che ci abitua al concetto di ciclo, suggerendoci anche come reperire
gli estremi di un'elenco e a identificare le altre celle che ci interessano con Offset.

http://ennius.interfree.it/ Pagina 308


MANUALE VBA X EXCEL
Splittare (dividere, separare) un file di testo importandolo in Excel.

Termine italianizzato dell'inglese To Split, che vuol dire : dividere. Vagando in quell'immensa banca dati
che la Guida in Linea di Excel (purtroppo a volte di non facile consultazione), ho trovato delle
istruzioni, e curiosando fra le righe, venuto fuori che potrebbero interessare dei "pellegrini", visto
anche un certo tipo di richieste pervenutemi. Si tratta della possibilit di importare dei file di testo e
comporre in un foglio di lavoro, una tabella divisa in righe e colonne con i dati provenienti dal file di
testo. Sono necessari alcuni accorgimenti per ottenere un risultato valido, come quello di usare un
separatore, come la virgola o il punto e virgola, tra una parola e l'altra di una stessa riga del file di
testo, in modo che excel, per ogni parola e per ogni separatore, assegni la parola ad una cella, e
saranno tante celle sulla stessa riga, per quante parole e separatori sono presenti nella riga del file di
testo. Per ogni riga successiva presente nel file di testo, saranno assegnate altrettante righe sul foglio di
lavoro. L'aspetto pi interessante di questo metodo forse rappresentato dal fatto che molti database
in circolazione, conservano i loro dati non in tabelle, ma in file, magari non con estensione .Txt, ma che
del Formato testo ne fanno la loro struttura, infatti i dati sono conservati in stringhe di testo dove i dati
dei vari campi sono dati separati dalla virgola. Sar possibile quindi importare uno di questi database
perch Excel provveda a creare una tabella con i dati cos caricati. E conosciamo tutti l'importanza di
lavorare con Excel con dati inquadrati in tabelle.. Potremo anche predisporre dei nostri file di testo per
creare elenchi da importare e gestire in Excel. Esemplificando, potremmo disporre di un file di testo
come l'esempio sotto:
nome file: Miofile.txt
Codice,Articolo,costo,ricarico,prezzo,aliva,imp.iva,vendita
2210ab,borsa,36,80%,,20
2310ab,borsello,41,90%,,20
2410ab,busta,36,100%,,20
2410bb,bustina,25,100%,,20
e questa sar la tabella che Excel ci creer facendogli importare un file di testo compilato come
l'esempio sopra (va da se che le formule nelle celle le dovremo compilare DOPO aver importato il file) :

Precisazioni : nel file di testo, dopo i valori di percentuale, ci sono due virgole senza nessun valore in
mezzo: Excel interpreta lo spazio vuoto tra due virgole, come uno scarto di colonna, tant' che nella
tabella i valori corrispondenti (20) vengono posizionati nella colonna "aliquota iva" come deve essere.
Attenzione al formato celle che ospiteranno i dati, dovranno essere settate in funzione del tipo di dato
che ospiteranno; la colonna D stata impostata a formato celle: "percentuale". Questo per evitare
interpretazioni errate da parte di Excel. Una precisazione : per importare valori con decimali, non si pu
adoperare la virgola, perch Excel la interpreta come separatore di elenco, ma il punto e virgola.
Questa comunque la routine, dove dovr essere indicato il percorso completo del file da importare,
mentre sar possibile definire in quale cella far importare il file; nell'esempio ho usato la A1:
Sub miofile()
With ActiveSheet.QueryTables.Add(Connection:="Text;C:\Documenti\Miofile.Txt", _
Destination:=Range("A1"))
.Name = "Split"
.FieldNames = True
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.RefreshStyle = xlInsertDeleteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
http://ennius.interfree.it/ Pagina 309
MANUALE VBA X EXCEL
.TextFilePromptOnRefresh = False
.TextFilePlatform = 850
.TextFileStartRow = 1
.TextFileParseType = xlDelimited
.TextFileTextQualifier = xlTextQualifierSingleQuote
.TextFileConsecutiveDelimiter = False
.TextFileTabDelimiter = True
.TextFileSemicolonDelimiter = True
.TextFileCommaDelimiter = True
.TextFileSpaceDelimiter = False
.TextFileColumnDataTypes = Array(1, 1, 1, 1)
.TextFileTrailingMinusNumbers = True
.Refresh BackgroundQuery:=False
End With
End Sub
Alcune considerazioni: l'istruzione si basa sull'oggetto QueryTables che utilizza il metodo Add per creare
una (letteralmente) "tavola di consultazione" con dati provenienti da una fontedati (in questo caso un
documento di testo). La QueryTables possiede numerose propriet che consentono di "pilotare" le
impostazioni nella formazione della tabella. Qu sotto riporto alcune spiegazioni, mentre invito gli
eventuali interessati ad andarsi a scoprire le altre nella guida in linea (del Visual Basic Editor).
Parametri da modificare per:
IMPORTARE TESTO SEPARATO DA VIRGOLA PER AVERE TESTO SU PIU' COLONNE
(esempi precedenti):
.AdjustColumnWidth = True
.TextFileTextQualifier = xlTextQualifierSingleQuote
.TextFileCommaDelimiter = True

IMPORTARE TESTO SEPARATO DA PUNTO E VIRGOLA PER AVERE TESTO SU PIU'


COLONNE (in questo caso possibile usare la virgola per definire numeri decimali):
.AdjustColumnWidth = True
.TextFileTextQualifier = xlTextQualifierdDoubleQuote
.TextFileCommaDelimiter = False

IMPORTARE TESTO SEPARATO DA VIRGOLA PER AVERE TESTO SU UNA COLONNA (stile
CSV, separato da virgole):
.AdjustColumnWidth = False
.TextFileTextQualifier = xlTextQualifierSingleQuote
.TextFileCommaDelimiter = False

I file .CSV sono file che possibile usare come database per il Web. Il motore di ricerca usato nella
sezione "le vs domande" su questo sito, sfrutta codice Javascript per "pescare" i dati che formano il
database del motore, in un file .CSV, che si ottiene salvando un solo foglio di Excel, selezionando come
formato di salvataggio il formato .CSV. A chi interessa pu leggersi su "le vs domande", pag. 6, "salvare
file in formato .csv", dove presente anche la routine per farlo.
Se qualcuno, mi vorr illuminare sull'argomento, sar il benvenuto.

http://ennius.interfree.it/ Pagina 310


MANUALE VBA X EXCEL
Uno strano comportamento. (09/02/03)
Segnalo un caso a cui non trovo risposta. Usando un "CommandButton" preso da "Strumenti di
Controllo" alias "Casella degli Strumenti" (e quindi un oggetto ActiveX), e sfruttando il suo evento Click
per eseguire istruzioni, ho notato che alcune istruzioni vengono eseguite in maniera impropria. Le
indicazioni che seguono hanno due precisi scopi:
primo: segnalare ad altri questo comportamento, ed eventualmente come aggirare il fatto.
secondo: se qualcuno conosce il perch del comportamento e mi vuole cortesemente illuminare.
Ma veniamo al fatto: Copiare un range di dati da un foglio in un altro foglio. Operazione eseguibile in
molti modi e comunque necessit abbastanza diffusa nei nostri lavori. Altra necessit richiesta
all'operazione, trovare la prima riga libera sul foglio destinazione, dove incollare i dati copiati. Quindi
prepariamo le nostre istruzioni e le assegniamo ad un pulsante che risiede sul foglio di partenza. Queste
le istruzioni e relativi commenti:
Set Zona = Worksheets(1).Range("tuazona") 'si assegna alla variabile Zona un range
di celle del foglio1 al quale range stato assegnato il nome "tuazona, nell'esempio il
range A2:B20.
Worksheets(2).Select 'si seleziona il foglio di destinazione (foglio 2)
'sotto: si inizia un ciclo di ricerca, a partire dalla riga 2 del foglio 2, cercando la prima
riga con l'istruzione "While Cells(iRow, 1).Value <> "" "che vuol dire: fino a che non
trovi una riga (iRow), nella colonna A (, 1) con la cella vuota, passi alla riga
successiva (iRow + 1) quando la trovi, esci dal ciclo (Wend)
Dim iRow As Integer
iRow = 2
While Cells(iRow, 1).Value <> ""
iRow = iRow + 1
Wend
'trovata la riga con la cella vuota, incollo i dati contenuti in Zona
Zona.Copy Cells(iRow, 1)
E qui avviene lo strano comportamento: inserendo l'istruzione nell'evento Click di un CommandButton
posto sul foglio1, i dati presenti in "tuazona", anzich venire copiati nella prima riga libera, colonna A,
del foglio2, vengono incollati nella colonna A ma del foglio1, in coda ai dati presenti. Eppure le
istruzioni vengono seguite: se sospendiamo le istruzioni del ciclo di ricerca, vediamo che il foglio 2 viene
regolarmente selezionato. Ed qui, sul foglio 2 che dovrebbe avvenire la ricerca della prima riga
libera. Invece la routine seleziona il foglio2 e poi incolla sul foglio1 (dove risiede il Commandbutton)
eseguendo l il ciclo di ricerca.
Che la routine funzioni, non c' dubbio: basta provare in questi altri modi:
Assegnare le istruzioni ad una macro, ed associare la macro ad un pulsante creato con gli strumenti
Disegno/Rettangolo o addirittura allo stesso evento Click del CommandButton, richiamando per la
macro e non inserendo direttamente ivi le istruzioni.
Usare una Userform da richiamare con un Commandbutton o pulsante messo sul foglio 1, ed assegnare
le istruzioni ad un Commandbutton posto sulla stessa Userform (evento Click).
Assegnare le istruzioni all'evento Click di un Commandbutton, ma posto sul foglio 2, cio lo stesso della
destinazione.
Sotto: l'immagine del foglio1 con i pulsanti:

http://ennius.interfree.it/ Pagina 311


MANUALE VBA X EXCEL
Sotto: l'immagine del foglio 2 con l'incollaggio eseguito perfettamente usando uno qualsiasi dei tre
pulsanti tranne il pulsante "Archivia" sul foglio1, oppure usando il pulsante "Archivia" ma sul foglio 2:

Sotto: l'immagine del Foglio 1 e cosa avviene se si usa il pulsante "Archivia" con le istruzioni poste
nell'evento Click: i dati sono incollati al di sotto dei dati di partenza:

Nota: le istruzioni impiegate copiano tutto: dati e formati, compreso i bordi e il colore celle.

allego file d'esempio da scaricare e utilizzare : EsempioCB.xls 20 Kb

http://ennius.interfree.it/ Pagina 312


MANUALE VBA X EXCEL
Passare da Stringhe a Formule
Quando le formule hanno bisogno di una rappresentazione visiva, ma si vuole anche che vengano
tradotte in formule per eseguire il calcolo, cominciano i dilemmi, perch se scegliamo da
Strumenti/Opzioni/Visualizza e spuntiamo la casella di "Formule", vedremo, sul foglio di lavoro, le
formule, ma non i risultati. Questo esempio lo presento a seguito di una domanda rivoltami , e pu
interessare tutti quei lavori dove si debba illustrare il calcolo che porta ad un risultato, come per
esempio preventivi o fatture di/per lavori nel campo edilizio, dove si usi fornire le spiegazioni di come
un risultato si ottenuto, attraverso la scrittura della formula che l'ha generato. E qui casca l'asino
quando si voglia automatizzare il calcolo. Infatti il problema di far accettare una formula come
descrizione, non esiste, in quanto sufficiente scegliere da "Formato Cella" il formato Testo, e tutto ci
che verr scritto nella cella sar da excel considerato sempre e soltanto testo (cio una stringa di
testo), ma esiste il problema di far capire ad excel che nella cella accanto (per esempio) a quella che
contiene la stringa testo, vogliamo che avvenga il calcolo rappresentato dalla stessa stringa testo.
Ipotizziamo di avere in A1 la visualizzazione della formula come stringa, ed in B1 di volere il conteggio
generato dalla formula. Sar inutile tentare con formule (in B1) tipo =A1 oppure ="="&A1 perch
otterremo solo una copia della stringa. Si pu ovviare alla bisogna con l'utilizzo di una riga di codice,
inserita in una macro, oppure in un evento tipo Change del Foglio di lavoro, usando un'istruzione cos:
Range("B1").Formula = "=" & Range("B1").Offset(0, -1)
oppure
Range("B1").Formula = "=" & Range("A1")

Il nocciolo dell'istruzione "=" & che rende in B1 il contenuto di A1 preceduto dal segno uguale e quindi
formula.
Due precisazioni importanti e necessarie:
La descrizione della formula in A1 (stringa) dovr essere scritta SENZA il segno di uguale come in questo
esempio: (4.00+3.15+2.22)*2.55 e NON =(4.00+3.15+2.22)*2.55 , pena un errore del debugger che
non riconosce il dato per la presenza finale di due segni di uguale.
Nella descrizione della formula in A1 (stringa) per indicare i decimali, DOVRA' essere usato il PUNTO al
posto della VIRGOLA, come si usa nella sintassi inglese. Ricordo che l'operazione di conversione da
stringa a formula, avviene attraverso il codice Vba, che "ragiona" in inglese: se gli si fornisce una stringa
da interpretare dove i decimali sono virgole, il Vba non la riconosce e si genera un errore. Excel poi
convertir il risultato fornito dal codice in sintassi italiana, con le virgole al posto dei punti: sar infatti
sufficiente controllare la formula in B1 per vederla cos: =(4+3,15+2,22)*2,55
Sotto vediamo meglio un esempio di un foglio di lavoro normalmente usato per il "COMPUTO
METRICO", dove si f appunto uso di caselle (Colonna E9) che ospitano numeri che rappresentano
misure da usare per ottenere le quantit (Colonna G). E' in questa colonna (G) dove l'istruzione
contenuta nella macro, deve effettuare la conversione il formula della stringa numeri della cella E.

Poich su fogli di questo tipo si preferisce preimpostare una certa lunghezza di righe, sar necessario
predisporre una formula per ogni riga, ma nel caso che si salti una riga per ottenere una impostazione

http://ennius.interfree.it/ Pagina 313


MANUALE VBA X EXCEL
grafica gradevole, le celle nella colonna G (che non trovano stringhe da convertire nelle celle relative
alla colonna E) porterebbero dei segni di uguale che esteticamente non sono graditi. Si pu
predisporre una routine che controlli se esistono dati nelle celle colonna E, e solo in questo caso,
svolgano la conversione. Queste istruzioni eseguono un ciclo di ricerca dal Range E7 fino alla E201, e se
trovano stringhe numeri, le convertono in formula, altrimenti non eseguono la conversione.
Sub calcola2()
On Error Resume Next
Dim CL As Object
For Each CL In Range("E7:E201")
If CL = "" Then
GoTo 10
Else
CL.Offset(0, 2).Formula = "=" & CL
End If
10:
Next
Resume
End Sub
Buon lavoro.

http://ennius.interfree.it/ Pagina 314


MANUALE VBA X EXCEL
Sub Totali in vba - come ottenerli. (28/06/03)
I questo esercizio che presento, vedremo come applicare dei subtotali ad un elenco di dati, nei campi
(colonne) che ospitano valori numerici. Vedremo anche la stessa tecnica applicata ad un elenco
filtrato, e come evidenziare in grassetto i caratteri dei subtotali, cambiando anche colore sia ai fonts
sia alle celle.
Oltre a svariate procedure che possiamo realizzare con istruzioni appropriate in vba, questa volta
seguiremo una procedura tipica del foglio di lavoro, tradotta in codice vba, che quella che
possiamo ottenere tranquillamente (senza bisogno del codice) andando sul men Dati e scegliendo
l'opzione "Subtotali". Questa procedura da foglio gi stata descritta su questo sito, sezione "primi
passi", articolo "Usare il filtro".
Ottenere subtotali una necessit che si pu avere quando si disponga di elenchi dati di cui vogliamo
dei parziali relativamente ad un periodo (es: una data di fine mese in un elenco fatture), oppure ad un
nominativo, oppure a quanto venduto di un determinato articolo, ecc. ecc. Le necessit di ognuno
sono tante che impossibile esemplificarle, l'importante afferrare il concetto. Vediamo una tabella
creata come esempio:

In questa tabella troviamo 5 campi: data fatt, nominativo, imponibile, iva, totale (imp. + iva); se si
dovesse identificare i campi con un numero (che in una tabella parte sempre da sinistra), data fatt
sarebbe il numero 1, nominativo il numero 2, ecc. ecc.; parlo di numeri e non di intestazioni di campo,
perch gli "argomenti" del metodo vba "Subtotal" che useremo, identificano i campi su cui agire in
base al "numero di campo".
Dovremo altres decidere in base a quale "Gruppo" ottenere i subtotali (per gruppo si intendono
ognuno dei campi a disposizione), cio in questo esempio, dovremo decidere se vorremo i subtotali
organizzati per il "Gruppo" "Data fatt" oppure "Nominativo", visto che mi sembra assurdo volerlo per gli
altri campi, di cui invece vorremo la SOMMA. Vediamo intanto la sintassi del Metodo Subtotal: (tra
parentesi gli argomenti separati da una virgola)
espressione.Subtotal(GroupBy, Function, TotalList, Replace, PageBreaks, SummaryBelowData)
(invito i "pellegrini" ad abituarsi a consultare la "guida in linea (vedi)" digitanto Subtotal in "cerca" e
selezionando "Metodo Subtotal" nella finestra degli argomenti trovati, per leggersi i significati relativi agli
argomenti)
Ed ora vediamo due esempi della procedura, nella quale organizzeremo i Subtotali raggruppati prima
per data fatt. e poi per nominativo, con relative immagini:
Sub ApplicaSubtotali()
'per prima cosa identifichiamo l'area, compreso le intestazioni di campo, su cui
agire. 'Poich si presuppone che non sapremo quanto lungo sar il nostro elenco,
usiamo End 'per reperire l'ultima cella occupata lato destro della tabella, ed
assegniamo l'area alla 'variabile "zona":
Set zona = Range(Cells(3, 1), Cells(3, 5).End(xlDown))
'ora applichiamo a "zona" i subtotali, organizzandoli per "Data fatt.", campo n. 1
(GroupBy:=1), usando la funzione Somma (Function:=xlSum), e chiedendo il
subtotale ai campi 3, 4 e 5 (imponibile,iva, totale) con (totallist:=Array(3, 4, 5)).
L'istruzione sotto 'tutta unica, si va a capo con _ (barra bassa) per mancanza di
spazio
http://ennius.interfree.it/ Pagina 315
MANUALE VBA X EXCEL
zona.Subtotal GroupBy:=1, Function:=xlSum, totallist:=Array(3, 4, 5), _
Replace:=True, PageBreaks:=False , SummaryBelowData:=True

End Sub
e questa l'immagine del risultato in cui si vedono i subtotali organizzati in funzione delle date uguali :

Vediamo subito anche un'altra routine necessaria : la rimozione dei subtotali, una volta analizzati i
risultati. Capire queste istruzioni facile: si identifica l'area a cui si sono applicati i subtotali (zona) e si
rimuovonocon RemoveSubtotal:
Sub RimuoviSubtotali()
Set zona = Range(Cells(3, 1), Cells(3, 5).End(xlDown))
zona.RemoveSubtotal
End Sub
Importante: questo risultato con i subtotali organizzati per Gruppi di date stato ottenuto grazie
all'ordinamento progressivo ascendente con cui le fatture sono state registrate, cio ogni fine mese, e
quindi le date uguali sono una seguente all'altra. Ma cosa succeder quando andremo ad applicare il
subtotale sul campo"Nominativo", che non porta i nominativi "raggruppati", ma distesi nei vari mesi?
Succederebbe che per ogni nominativo verrebbe fornito un subtotale, in quanto cambia il nominativo
ad ogni riga, ed otterremmo un elenco molto lungo di subtotali che non servirebbero allo scopo. E
allora? Allora impariamo una regola che dovremo tenere sempre presente: dovremo "raggruppare" i
Nominativi (in questo caso) usando un ordinamento che ponga in ordine alfabetico i nominativi (e
quindi raggruppandoli), e i loro dati correlati. In questo modo come se applicassimo un filtro che
riunisca tutti i valori uguali, solo che anzich filtrare un nominativo per volta, li "filtriamo" tutti.
Inseriremo le istruzioni per l'ordinamento PRIMA delle istruzioni per i subtotali, ed il gioco fatto.
Vediamo le istruzioni e l'immagine del risultato:
Sub ordinaapplicaSt()
'impostiamo la zona su cui agire
Set zona = Range(Cells(3, 1), Cells(3, 5).End(xlDown))
'sotto; con la zona, applichiamo l'ordinamento ascendente sul campo Nominativo,
che 'inizia come dati dalla cella B4
With zona
.Sort Key1:=Range("B4"), Order1:=xlAscending, Header:=xlGuess, _
OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom
End With

'indi usiamo il metodo Subtotal agendo sul GroupBy:=2 , cio il campo Nominativo
zona.Subtotal GroupBy:=2, Function:=xlSum, totallist:=Array(3, 4, 5), _
Replace:=True, PageBreaks:=False, SummaryBelowData:=True
End Sub
e questo sar il risultato:

http://ennius.interfree.it/ Pagina 316


MANUALE VBA X EXCEL

Anche qui vorremo rimuovere i subtotali, ma dovremo seguire una strada diversa rispetto alle istruzioni
per la rimozione vista sopra in quanto abbiamo modificato anche l'ordinamento di tutti i dati. In questo
caso, dovremo ricostruire l'elenco come era in origine, impostato sulle date fattura ed useremo ancora
un ordinamento ascendente ma basato questa volta sulla chiave "Data fatt.", cio sulla colonna A a
partire dalla cella A4, e queste le rispettive istruzioni, ma con l'istruzione RemoveSubtotal posta PRIMA di
quella sull'ordinamento:
Sub RimuoviordinaapplicaSt()
Set zona = Range(Cells(3, 1), Cells(3, 5).End(xlDown))
zona.RemoveSubtotal
With zona
.Sort Key1:=Range("A4"), Order1:=xlAscending, Header:=xlGuess, _
OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom
End With
End Sub
Questa procedura in realt non ripristina la tabella proprio come era all'origine, in quanto si avr un
ordinamento progressivo sulle date, ma con nominativi posti in ordine alfabetico; nessun danno perch
gli importi relativi ad ogni nominativo saranno quelli giusti, ma.....esiste un'altro modo, che dovremo
prevedere quando creeremo i campi di una tabella: lasceremo la prima colonna, la A, come colonna
contatore, partendo quindi da uno incrementando una unit per ogni riga. In questo modo, se
applicheremo ordinamenti basati su date, o nominativi, o altro, potremo sempre ritornare all'ovile
scegliendo come chiave d'ordinamento per il ripristino, la colonna con i numeri, ed i dati ritorneranno
veramente come prima.
Come promesso in apertura articolo, ora vediamo come colorare caratteri, renderli grassetto, e
colorare le celle che ospiteranno i sub totali. Vediamo subito un immagine che chiarisce cosa intendo,
e poi la routine e le spiegazioni:

http://ennius.interfree.it/ Pagina 317


MANUALE VBA X EXCEL

Per la routine useremo una macro a parte, che richiameremo a fine di una delle precedenti routine, in
modo che applicheremo l'ordinamento, i sub totali e infine questa:
Sub ColoraSt()
Dim CL As Object
'sotto: settiamo come zona SOLO le celle della colonna sulla quale stiamo
applicando i 'subtotali, nell'esempio sopra, la colonna 2 (nominativo) dalla B3
all'ultima cella occupata
Set zonac = Range(Cells(3, 2), Cells(3, 2).End(xlDown))
'inizia il ciclo per ogni cella in zonac
For Each CL In zonac
'per identificare su quale riga si formeranno i subtotali (non possiamo
predeterminarlo 'prima), cerchiamo la parola "Totale", che pu trovarsi la prima a
destra o l' ultima a 'sinistra nelle celle che spazzoliamo con in ciclo For Each, se
"Totale" viene trovato, 'allora:
If Right(CL.Value, 6) = "Totale" Or Left(CL.Value, 6) = "Totale" Then
'con la cella (CL) cos trovata, impostiamo il colore rosso al font ed il grigio nella
cella:
With CL
.Font.ColorIndex = 3
.Interior.ColorIndex = 15
'con Offset(0, 1) identifichiamo la cella a destra di quella trovata e coloriamo,
'aggiungendo il Grassetto al font
.Offset(0, 1).Font.ColorIndex = 3
.Offset(0, 1).Interior.ColorIndex = 15
.Offset(0, 1).Font.Bold = True
'lo stesso facciamo con la cella : due celle a destra (Offset(0 , 2))
.Offset(0, 2).Font.ColorIndex = 3
.Offset(0, 2).Interior.ColorIndex = 15
.Offset(0, 2).Font.Bold = True
'e quindi con la terza (Offset(0 , 3))
.Offset(0, 3).Font.ColorIndex = 3
.Offset(0, 3).Interior.ColorIndex = 15
.Offset(0, 3).Font.Bold = True

End With ' fine con


End If
Next 'passa alla cella successiva fino alla fine delle celle in zonac
End Sub

http://ennius.interfree.it/ Pagina 318


MANUALE VBA X EXCEL
E quindi la routine "ordinaapplicaSt" vista sopra, con l'aggiunta del richiamo alla macro ColoraSt,
diventa cos:
Sub ordinaapplicaSt()
'impostiamo la zona su cui agire
Set zona = Range(Cells(3, 1), Cells(3, 5).End(xlDown))
'sotto; con la zona, applichiamo l'ordinamento ascendente sul campo Nominativo,
che 'inizia come dati dalla cella B4
With zona
.Sort Key1:=Range("B4"), Order1:=xlAscending, Header:=xlGuess, _
OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom
End With

'indi usiamo il metodo Subtotal agendo sul GroupBy:=2 , cio il campo Nominativo
zona.Subtotal GroupBy:=2, Function:=xlSum, totallist:=Array(3, 4, 5), _
Replace:=True, PageBreaks:=False, SummaryBelowData:=True

ColoraSt 'si richiama la macro per colorare fonts e celle


End Sub
Quando si rimuoveranno i subtotali, usando la macro RimuoviordinaapplicaSt() spariranno anche le
impostazioni di colore e grassetto, senza bisogno di aggiungere istruzioni. Ognuno potr scegliersi i
colori che preferir semplicemente cambiando il valore assegnato a ColorIndex. (per la tabella Colori
vedi in questa sezione : "Colori e ColorIndex").

Buon lavoro.

http://ennius.interfree.it/ Pagina 319


MANUALE VBA X EXCEL
Suonare con Excel. (13/06/03) - Aggiornato al 22/08/03
Far emettere suoni ad Excel pu essere utile quando si voglia essere avvisati se per esempio in una
cella compare un determinato valore, testo, numero o data che sia.
Sembra per che i progettisti di Excel abbiano deciso di fare a meno di suoni. Si legge infatti, nella
guida in linea a proposito della propriet CanPlaySounds : "Questa propriet non deve essere utilizzata.
Le note sonore sono state eliminate da Microsoft Excel." Pare che gli unici suoni gestiti tramite Excel,
siano i suoni legati al famoso "Assistente di Office", infatti, sempre nella guida in linea, alla propriet
Sounds, viene riportato il seguente esempio:
"In questo esempio lAssistente di Office viene visualizzato, animato e messo in grado di riprodurre
suoni.":
With Assistant
.Visible = True
.On = True
If Not Sounds Then Sounds = True
.Animation = msoAnimationGreeting
End With
Esiste tuttavia la possibilit di eseguire file .wav, sfruttando una libreria di Sistema, la "winmm.dll".
Vediamo come fare:
Inseriamo, nella sezione "Generale - Dichiarazioni" di un Modulo la seguente dichiarazione: ( tutta
un'istruzione anche se su due righe, se copiate NON dimenticate il trattino basso _)
Declare Function sndPlaySound32 Lib "winmm.dll" Alias "sndPlaySoundA" _
(ByVal lpszSoundName As String, ByVal uFlags As Long) As Long
Creiamo (nello stesso Modulo) e diamo il nome alla macro che ospiter il richiamo alla Funzione
sndPlaySound32. Come argomento della funzione, dovremo scrivere il percorso completo ed il nome
del file .wav da suonare. Ognuno scriver il proprio, come esempio ho usato C:\Temp ed il nome di in
file copiato l da Windows\Media (la cartella dei suoni di sistema). Potrete usare anche suoni registrati
da voi, con la vostra voce, usando l'utility "Registratore di suoni" di Windows. Unico suggerimento:
poich durante l'esecuzione della macro non sar possibile eseguire nessuna operazione sul foglio di
lavoro, consiglio di utilizzare suoni brevi per non bloccare il foglio troppo a lungo.
Sub MioSuono()
Call sndPlaySound32("C:\Temp\ringin.wav", 0)
End Sub
Ora sceglieremo un evento per inserire l'istruzione che far scattare in automatico l'esecuzione del
suono se si verificher una certa condizione: nell'esempio sotto ipotizzo che se nella cella A1 compare
la parola "pippo" (attenzione alle maiuscole/minuscole (*)), si attiva il suono tramite il richiamo della
macro su esposta (MioSuono):
Private Sub Worksheet_Change(ByVal Target As Range)
If Range("A1").Value = "pippo" Then
MioSuono
End If
End Sub
* Ricordo che per ovviare all'inconveniente delle maiuscole/minuscole, quando si fa uso di "testo" nel
codice, possiamo inserire nella sezione "Generale - Dichiarazioni" (del Worksheet in questo caso)
l'istruzione:
Option Compare Text
Aggiornamento
Nasce un problema quando si voglia inviare la cartella con il file vaw ad un amico, o spostare il file
vaw in una cartella diversa : cambiando il percorso che mira al file vaw, il file non verr trovato e
quindi niente suono. Ma esiste la possibilit di "incorporare" il file vaw nella cartella in modo che diventi
un tutt'uno con il file sonoro. Questa soluzione stata suggerita da Stefano Luise, e-mail
stefano_luise@yahoo.com e questa la sua spiegazione:
Ho trovato questa routine di un certo Tiziano Marmiroli - Microsoft MVP - Office
(t.marmiroli@mvps.org) e segnalo il modo per farlo facendo s che il file sia unico:

Menu Inserisci> Oggetto> Da file


e inserisci il tuo file wav. Prendi nota del nome che Excel gli assegna
(es. "Oggetto 1").

http://ennius.interfree.it/ Pagina 320


MANUALE VBA X EXCEL
Da Visual Basic Editor:

---------------------------------------------
Private Sub Workbook_Open()
Sheets("Foglio1").Shapes("Oggetto 1").Select
Selection.Verb Verb:=xlPrimary
End Sub

'sostituire a "Oggetto 1" il nome dell'oggetto e


'a "Foglio1" il nome del foglio che lo contiene

---------------------------------------------

All'apertura del foglio parte il suono.

Ciao,

Stefano
Un grazie a Stefano.
Buon lavoro.

http://ennius.interfree.it/ Pagina 321


MANUALE VBA X EXCEL
Le TextBox nelle UserForm e il SetFocus.

Quando si usano delle istruzioni in vba per controllare se i dati immessi in una TextBox sono
corrispondenti alle nostre esigenze, o non restino vuote (senza dati), necessario utilizzare degli "eventi"
che attivino questi controlli, eventi legati ad "oggetti" presenti sulla UserForm. In genere io uso l'evento
Click di un CommandButton, al quale faccio prima controllare l'esattezza dei dati ammessi nelle
TextBox, e se tutto Ok, l'esecuzione delle istruzioni previste per quell'evento. Tipico esempio quello
sotto.
Private Sub CommandButton1_Click()
If TextBox1 = "" then 'Se la textbox1 vuota
MsgBox "Inserire i dati richiesti" 'fai apparire questo messaggio
TextBox1.SetFocus 'riporti il focus sulla TextBox1
Exit Sub 'esci dalla routine e non esegui le istruzioni sottostanti
End If
Range("A1") = TextBox1 'in caso la textbox1 contenga dati, esegue questa istruzione
End Sub

Come vediamo, usiamo l'istruzione SetFocus per riportare il focus sulla textbox interessata. Poich
l'esecuzione di questa istruzione affidata all'"oggetto" CommandButton che in questo momento ha il
focus, il codice esegue il comando senza fallire. Questo perch dopo aver generato l'evento
Click(Index As Long) il controllo attivo passa all'"oggetto" immediatamente successivo sulla userform,
che possieda la propriet "TabIndex" . ( Quando si inseriscono oggetti sulla userform, tutti gli oggetti
inseriti che possiedono questa propriet, ricevono un indice progressivo assegnato dal programma, il
valore indice (TabIndex) inizia con zero (0) assegnato al primo oggetto, e si incrementa di un valore per
ogni altro oggetto inserito. E' quindi questo valore che determina la sequenza di selezione oggetti
generata per esempio, dal tasto Invio.) Ritornando al nostro Click, l'istruzione TextBox1.SetFocus Porta il
focus sull'oggetto indicato anzich lasciarlo all'oggetto previsto dal successivo valore presente nel
TabIndex del CommandButton.
E dopo questa lungagnata, "Non mi faccio un brodo? Ma me lo faccio doppio!" Come diceva un
comico in una reclame televisiva. E' successo, e non me ne ero mai accorto, che se invece di un
evento Click di un CommandButton, si voglia scegliere un evento proprio della stessa TextBox1 per
ottenere questo benedetto controllo immissione dati, siamo necessariamente portati ad utilizzare due
eventi tipici: AfterUpdate oppure Exit. Per entrambi questi eventi, sembra non intercettino un istruzione
come TextBox1.SetFocus in quanto l'evento stesso successivo alla lettura dell'istruzione, e come tale
segue la normale procedura di selezione dell'oggetto successivo rappresentato dal suo TabIndex. In
parole povere, non si riesce a far ritornare il focus sulla TextBox1. (Questa istruzione in effetti viene
eseguita, ma tanto rapida che non la vediamo, vedremo solo ci che Exit o AfterUpdate fanno alla
fine: quella di spostare il focus sull'oggetto successivo). Tra l'altro, per un esempio come quello citato
all'inizio, dove si voglia controllare se una textbox rimane vuota, l'evento AfetUpdate non interverrebbe
comunque: AfterUpdate vuol dire: "dopo l'aggiornamento", ma se in una textbox non scriviamo niente,
non l'abbiamo "aggiornata" e quindi l'evento non viene attivato.
Rimane quindi un'unica possibilit, se vogliamo usare un evento di una textbox, quello di scegliere
l'evento Exit . E non sar pi necessario usare un istruzione SetFocus, ma sfruttare il metodo Cancel
dell'evento Exit con una semplice istruzione come questa:
Cancel = True
Questa istruzione equivale ad interrompere l'uscita dalla textbox (exit) e lascia il focus sulla textbox
stessa. Andr posizionata subito sotto l'istruzione If...Then in modo che si interrompa l'uscita
riposizionando lo "Stato Attivo" (focus) sulla textbox, e possano essere eseguite le successive istruzioni.
Presento un esempio nel quale si controlla che nella textbox si inseriscano solo numeri e non lettere o
numeri e lettere (IsNumeric) e un controllo che impedisca l'immissione di valori negativi, il tutto con la
segnalazione di un messaggio di "Errato", e la selezione del valore immesso come non valido. Questo
l'esempio:
Private Sub TextBox1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
Dim MyVar, MyCheck, Search, SearchString, where
Dim X
X = Mid(TextBox1, 1, 1) 'legge il primo carattere nel textbox
MyVar = TextBox1.Value 'Assegna il valore alla variabile.
MyCheck = IsNumeric(MyVar) ' Restituisce Vero.
http://ennius.interfree.it/ Pagina 322
MANUALE VBA X EXCEL
If MyCheck = False Or X = "-" Then 'se non un numero o se inizia col segno meno, allora
Cancel = True 'QUESTO IL PUNTO IN CUI POSIZIONARE CANCEL
SearchString = TextBox1.Text 'text che contiene i dati
Search = TextBox1 'text con parola da cercare
where = InStr(SearchString, Search)
If where Then
TextBox1.SelStart = where - 1 ' l'inizio della selezione e
TextBox1.SelLength = Len(Search) ' la lunghezza.
'TextBox1.SetFocus
MsgBox "Errato !!"
End If

Else
TextBox2.SetFocus
End If
End Sub
Se sar stato di aiuto per qualcuno, tanto meglio. Buon lavoro.

http://ennius.interfree.it/ Pagina 323


MANUALE VBA X EXCEL
Traduttore Funzioni Italiano-Inglese e viceversa.

Dopo varie richieste presento un traduttore delle Funzioni da italiano a inglese e viceversa, che potr
aiutare nel reperire la corrispondenza nelle due lingue. Il database sul foglio2, e potr essere
ampliato a piacimento, baster poi variare i riferimenti ai nomi che identificano le aree che formano il
RowSource delle ListBox. Sotto un immagine:

File scaricabile e consultabile : Tradfunzioni2000.zip 42 Kb

http://ennius.interfree.it/ Pagina 324


MANUALE VBA X EXCEL
La Funzione Trim - precisazioni (23/06/03)
Abbiamo gi visto, nell'articolo "Funzioni Stringa" in questa sezione, come lavora la funzione TRIM.
La Funzione Trim serve per rendere un valore stringa (cio del testo) SENZA spazi iniziali o finali (con le
Funzioni Trim non vengono eliminati gli spazi "intermedi" ).
Cio se in una cella ci troviamo con una stringa tipo:
Procopio Lacustre
applicando la funzione Trim ci troveremmo ad aver eliminato gli spazi prima di Procopio e dopo
Lacustre, MA non avremmo eliminato gli spazi tra Procopio e Lacustre, ed avremo:
Procopio Lacustre
E fin qui niente di nuovo, sotto il sole. Ma la funzione TRIM possiede una sorella gemella che corrisponde
all'italiano ANNULLA.SPAZI . Anche qui niente di nuovo; quasi tutte le funzioni disponibili (in italiano) sul
foglio di lavoro, hanno le corrispondenti funzioni in inglese da usare con il codice vba, e viceversa.
Solo che la funzione Annulla.Spazi f qualcosa di diverso dalla sorella Trim. Leggiamo cosa dice la
guida in linea in merito alla funzione Annulla.Spazi :
"Rimuove tutti gli spazi dal testo ad eccezione dei singoli spazi tra le parole. Utilizzare la funzione
ANNULLA.SPAZI sul testo creato con altre applicazioni che pu presentare una distribuzione irregolare
degli spazi."
Quel "singoli" la chiave che differenzia le due funzioni, che dovrebbero operare in uguale maniera,
ma se si adopera la funzione Annulla.Spazi, la frase sopra diventa cos:
Procopio Lacustre
Anche un sordo nota che in questo caso sono stati eliminati tutti gli spazi vuoti, tranne uno tra Procopio
e Lacustre. E questo alla faccia di noi "pellegrini" che troppo spesso diamo per scontato che le cose
simili si comportino similmente, o quanto meno erriamo nel considerarle uguali.
In realt le due funzioni devono essere usate con modalit diverse. La funzione Trim, via codice, ci
consente di modificare il testo contenuto in una cella, AGENDO direttamente sulla cella stessa,
esempio:
Sub miaElido()
Range("A1") = Trim(Range("A1"))
End Sub
In questo caso verranno eliminati solo gli spazi iniziali e finali, ma non intermedi, e lo facciamo
direttamente nella cella stessa. Per vederla lavorare come lavora Annulla.Spazi, la funzione Trim va
trasformata in FORMULA.
Come tale, per, non potr essere inserita nella stessa cella che si vuole "trimmare" (si genera un errore
di tipo "riferimento circolare") ma dovremo usare un'altra cella per ospitare la cella "trimmata", cos.
Sub miaElidos()
Range("A2").Formula = "=TRIM(A1)"
End Sub
Ed avremo in A2 il nome senza spazi tranne lo spazio tra le due parole. Mi sembrava doveroso far
notare le diversit nell'uso che si fa della stessa funzione, italiana o inglese che sia.

Buon lavoro.

http://ennius.interfree.it/ Pagina 325


MANUALE VBA X EXCEL
Triplo Ciclo For .. Next
I cicli For ... Next sono legati al concetto di insiemi. Questi insiemi possono essere oggetti di vario tipo :
controlli, barre di comando, celle del foglio di lavoro, fogli di lavoro, ma anche matrici, valori, ecc.
ecc. Quando si deve eseguire una verifica o una ricerca su ogni componente di un insieme, come per
esempio cercare un valore in una serie di celle (Range), allora e utile ricorrere proprio alla struttura di
un ciclo For ... Next.
Sono due tra le strutture cicliche di controllo (ne esistono altre) :
un ciclo che cercher PER OGNI componente dell'insieme, usando la forma For Each <elemento> di un
<insieme> ... Next <passa all'elemento successivo>. un esempio
Per ogni cella (C)<elemento> nell'<insieme> Range("A1:A20"). In questo caso viene
assegnato un indice implicito rappresentato dal numero di celle presenti nel Range
A1:A20, indice che identifica numericamente le 20 celle. L'istruzione Next, posta alla
fine del ciclo, non fa altro che passare all'indice successivo, ripetendo le istruzioni,
fino a che non ha raggiunto l'indice 20, dopodich esce dal ciclo.
For Each C in Range("A1:A20")
...istruzioni
Next
oppure un ciclo, posto un valore iniziale ed un valore finale, che si baser su un contatore (indice non
implicito) che si incrementer di una unit ad ogni Next fino a raggiungere il valore finale, usando la
forma For I <I il contatore>= 1 To 20 ... Next <passa al valore successivo rappresentato da I>. Un
esempio
Questa forma consente di "spazzolare" un intervallo di <elementi> di un <insieme>,
dichiarando noi l'indice per quanti <elementi> (1 To 20 ) dovr essere ripetuto il ciclo
(20 volte) ed identificando l'<elemento> con il contatore (o indice). Rifacendoci
all'esempio sopra, dove si scorre la colonna A fino alla cella 20, identificate come
<insieme> dall'oggetto Range, in questo caso useremo Cells come <elemento>
dell'oggetto Foglio (in questo caso l'<insieme>). Visto che per identificare le celle del
foglio di lavoro, usiamo due indici, il primo sempre l'indice di riga, il secondo
sempre l'indice di colonna (es.: Cells(1, 3) = C1), useremo al posto dell'indice di riga il
numero rappresentato dal contatore ( I ) per scorrere tutte le righe fino alla 20.
For I = 1 To 20
Cells(I, 1) seguono istruzioni
Next
I una variabile che pu essere identificata con qualsiasi lettera o nome, N oppure
X o ancora Cont, o quel che vi pare, l'importante che poi usiate quello che avrete
scelto come contatore al posto dell'indice riga, oppure assegnare il tipo di variabile
con Dim, es.:
Dim Cont as Integer
For Cont = 1 To 20
Cells(Cont, 1) seguono istruzioni
Next
Fatte queste premesse, passo ad illustrare un esempio scaturito da una richiesta, strettamente legato a
cicli For.. Next, e lo propongo in due varianti.
Vediamo il problema:
In una tabella, formata da 10 colonne e da 10 righe, si trovano dei numeri, da 1 a 100. Si voleva che,
cancellando uno qualsiasi dei numeri rimasti, i numeri successivi a quello cancellato, scalassero di una
cella, e si ripristinasse la progressione dei i numeri rimasti, lasciando quindi vuota l'ultima cella. Vediamo
le tabelle: nella prima stato eliminato il valore nella cella evidenziata in giallo; come si nota, manca il
numero 64

http://ennius.interfree.it/ Pagina 326


MANUALE VBA X EXCEL

Si vuole quindi che a partire dal 65, si scali di una cella, ricreando la naturale progressione, e questo
sar il risultato finale, in cui i numeri sono in progressione ed l'ultima cella a restare vuota.:

Vediamo come procedere:


abbiamo bisogno di un ciclo che controlli tutte le celle di una stessa riga della tabella, e quindi lavori
avanzando colonna dopo colonna.
abbiamo bisogno di un secondo ciclo, che una volta completato il ciclo per le colonne della prima
riga, passi alla riga successiva dell'elenco per ripetere il ciclo sulle colonne, e che questo ciclo scorra
fino alla fine tutte le righe.
Visto che stiamo cercando se una cella sar vuota, inseriremo un controllo If .. Then. Se troveremo una
cella vuota, e qu ho scelto la soluzione pi veloce, cancello l'intera tabella, assegno alla prima cella
(A1) il valore 1, e rigenero l'intera sequenza dei numeri fermandomi a 99, con un terzo ciclo For.. Next,
dopodich esco da tutti i cicli con Exit For (ripetuto due volte perch due sono i cicli "esterni"
inizializzati.). Se invece non verr trovata nessuna cella vuota, il terzo ciclo (interno) non si verifica e si
uscir dalla routine quando tutte le celle sono state controllate. Questa la routine:

Sub Riordina()
'istruzione necessaria per non vedere lo scorrere dei cicli
Application.ScreenUpdating = False
'assegnazione alla variabile "zona" del range su cui operare
Set zona = Range("A1:J10")
'inizio del primo ciclo esterno, che inizializza l'indice riga (rwIndex); cio a partire
dalla 'riga 1 (e poi fino alla riga 10)
For rwIndex = 1 To 10
'inizia il secondo ciclo, che nella riga ora selezionata (la 1) scorre tutte le colonne,
'dall'indice colonna 1 fino alla 10 (colIndex)
For colIndex = 1 To 10
'con l'<insieme> Foglio1, per l'<elemento> Cella (indice riga, indicecolonna)(questi
indici 'rappresentati ora da rwIndex e da colIndex)
With Worksheets("Foglio1").Cells(rwIndex, colIndex)
'se la cella vuota, allora
If .Value = "" Then
http://ennius.interfree.it/ Pagina 327
MANUALE VBA X EXCEL
'cancelliamo tutta l'area assegnata a "zona"
zona.ClearContents
'assegnamo alla prima cella dell'area "zona" (A1) il valore 1
zona.Cells(1) = 1
'inizio del terzo ciclo, partendo dalla cella 2 (la cella uno gi stata inizializzata con
1) e 'fino al valore rappresentato dal numero di celle (zona.Cells.Count= 100) - 1
perch 'dovr mancare una cella, l'ultima
For I = 2 To zona.Cells.Count - 1
'I ora un contatore, e determina su quale cella della "zona" si interviene,
sommando al 'valore della cella precedente (la I -1) la cella attuale, una unit (1)
zona.Cells(I) = zona.Cells(I - 1) + 1
Next I
'finito con Next I il terzo ciclo che ha poste nelle celle la progressione dei numeri fino
a 99, si esce dai due cicli precedenti aperti, e si salta a End Sub
Exit For: Exit For
End If
End With
Next colIndex
Next rwIndex

End Sub
Ho preparato anche la routine per riempire tutta la tabella con numeri da 1 a 100, ripristinando la
tabella completa: Questa la routine, inutili mi pare, i commenti:
Sub Riempi()
Application.ScreenUpdating = False
Set zona = Range("A1:J10")
zona.ClearContents
For I = 2 To zona.Cells.Count
zona.Cells(1) = 1
zona.Cells(I) = zona.Cells(I - 1) + 1
Next
End Sub
Questa invece la seconda variante, promessa all'inizio. Presupponendo che si voglia il comportamento
relativo al problema (quello di scalare celle e ripristino della progressione) MA il tutto su una tabella
dove il numero di celle vuote sia superiore ad 1, e dove quindi necessario "contare" quante celle
vuote si trovano per determinare quante celle vuote lasciare alla fine.
Come procedere:
dovremo usare i due cicli For..Next per scorrere tutte le righe e tutte le colonne, per cercare quante
celle vuote sono presenti.
ci affideremo ad un contatore (cont) che memorizzi quante celle vuote sono presenti con
If .Value = "" Then
cont = cont + 1
End If
Alla fine dei due cicli di ricerca, controlleremo se il valore del contatore maggiore di 0 (zero), in caso
sia maggiore, iniziamo il ciclo di azzeramento tabella, riassegnazione alla prima cella del valore 1, ed
incremento delle altre celle di una unit in progressione, ottenendo dove fermarci dal valore ottenuto
dal conteggio di quante celle ci sono nella tabella, meno il valore rappresentato dal contatore.
Sub Riordina()
Application.ScreenUpdating = False
Set zona = Range("A1:J10")
For rwIndex = 1 To 10
For colIndex = 1 To 10
With Worksheets("Foglio1").Cells(rwIndex, colIndex)
If .Value = "" Then
cont = cont + 1
End If
End With
Next colIndex
http://ennius.interfree.it/ Pagina 328
MANUALE VBA X EXCEL
Next rwIndex

If cont > 0 Then


zona.ClearContents
For I = 2 To zona.Cells.Count - cont
zona.Cells(1) = 1
zona.Cells(I) = zona.Cells(I - 1) + 1
Next
End If
End Sub

Buon lavoro.

http://ennius.interfree.it/ Pagina 329


MANUALE VBA X EXCEL
Trovare il Path
Tutte le seguenti macro dovranno essere inserite in un modulo ed associate ad un relativo pulsante.
Per avere in percorso completo del file attualmente aperto in Excel:
Sub DimmiPath()

MsgBox "Il path " & ThisWorkbook.Path

End Sub
Per trovare un file o tutti i file data una cartella e una estensione. Nell'esempio sotto, verranno cercati
tutti i file con estensione .xls ( .Filename = "*.xls" ) nella cartella Documenti ( .LookIn = "C:\Documenti" ) .
H H

Verr riportato il numero di quanti file ci sono ed il loro nome, in ordine alfabetico.
Sub Trovafile()

Set fs = Application.FileSearch
With fs
.LookIn = "C:\Documenti"
.Filename = "*.xls"
If .Execute > 0 Then
MsgBox "There were " & .FoundFiles.Count & _
" file(s) found."
For i = 1 To .FoundFiles.Count
MsgBox .FoundFiles(i)
Next i
Else
MsgBox "There were no files found."
End If
End With

End Sub
Una variante alla precedente routine, la seguente, di cui riporto solo il passo da modificare. Nella
precedente macro, la cartella in cui eseguire la ricerca inserita nel codice, e quindi fissa. Per eseguire
la ricerca in altre cartelle sarebbe necessario modificare il codice. La variante che vi sottopongo
consentir di scegliere la cartella in cui eseguire la ricerca, semplicemente scrivendo il percorso
completo della cartella, in una cella del foglio di lavoro, ad esempio in A1 (dove scriveremo, sempre
per esempio, C:\MiaCartella)
H H

Set fs = Application.FileSearch
With fs
.LookIn = "Range(A1)" 'parte da modificare
Per avere l'elenco di tutti i file .xls presenti nella cartella dove risiede il file attualmente aperto in Excel
Sub QualiFile()
With Application.FileSearch
For i = 1 To .FoundFiles.Count
MsgBox .FoundFiles(i)
Next I
End With
End Sub
Per avere il percorso (path) predefinito utilizzato da Excel per aprire i file.
Sub Default()
MsgBox "L'attuale percorso predefinito " & _
Application.DefaultFilePath
End Sub

http://ennius.interfree.it/ Pagina 330


MANUALE VBA X EXCEL
Utilizzare le InputBox per inserire dati sul Foglio di lavoro.
Spesso vorremmo disporre, per introdurre dati su determinate celle del foglio di lavoro, di una
maschera che raccolga il dato da immettere, e lo "scarichi" poi in una cella per attivare le procedure
presenti sul foglio stesso. Queste maschere di introduzione dati, altro non sono che "Finestre di Dialogo"
(le ImputBox).
Ecco una semplice routine, da inserire in un modulo e da associare ad un pulsante che attivi l'InputBox.
Nell'esempio utilizzo la Cella A1 come destinazione del dato inserito, potrete modificare il riferimento
per la cella che pi vi aggrada. In verde sono i commenti :
Sub Richiesta()
Dim Message, Title, MyValue
'sotto: Imposta il messaggio.
Message = "Inserisci Quel che Vuoi :"
Title = "Inserimento Dati" ' Imposta il titolo.

' Visualizza il messaggio, il titolo


MyValue = InputBox(Message, Title)
If MyValue <> "" Then 'se l'inputbox diverso da vuoto
Range("A1").Value = MyValue 'allora copia in A1 il testo
End If
End Sub
E' possibile utilizzare la stessa InputBox per inserire pi dati in celle diverse, se i dati corrispondono a
valori predeterminati. Ipotizziamo di dover introdurre 3 tipi di dati condizionali (SE) in tre diverse celle. In
A1 vorremo numeri solo SE compresi tra 1 e 100, in A2 sempre numeri solo SE compresi tra 200 e 300, ed
infine in A3 vorremo dati solo SE sono testo. Ricordo che, anche qui, i riferimenti e i valori condizionali
potranno essere adattati alle vostre esigenze, compreso l'inserimento, tramite ElseIf ......Then di nuove
istruzioni prima di End If.
Sub multi()
Dim Message, Title, MyValue
Message = "Inserisci Quel che vuoi :"
Title = "Inserimento Dati"

MyValue = InputBox(Message, Title)


If MyValue >= 1 And MyValue <= 100 Then
Range("A1").Value = MyValue

ElseIf MyValue >= 200 And MyValue <= 300 Then


Range("A2").Value = MyValue

ElseIf MyValue <> IsNumeric(MyValue) Then


Range("A3").Value = MyValue

End If
End Sub
Utilizzare le InputBox ci consente quindi di "reperire dati" (valori, date, testo) da utilizzare in qualunque
contesto si voglia : all'interno di routine per assegnare valori a delle variabili, oppure per inserire o
modificare dati presenti in celle di un foglio di lavoro. Un altro semplice esempio pu essere quello di
usare due InputBox per modificare il valore di una cella, aggiungendo o togliendo valori (come in un
carico e scarico di giacenze di un magazzino). Usiamo la cella D1 come esempio, ed usiamo la
dizione breve per chiamare le InputBox:
Sub Carica
'dichiariamo la variabile "carico" come vettore del valore da aggiungere
carico = InputBox("Inserisci la quantit da caricare")
'per evitare l'errore "Tipo non Corrispondente" se non scriviamo niente o premiamo il
pulsante "Annulla" sulla InputBox, useremo questa istruzione sotto:
If carico = "" Then Exit Sub '(se carico vuoto o nullo si esce dalla routine)
'qui e poi necessario dichiarare il "tipo" di valore che intendiamo trasferire; potremo
usare 'un generico Val(carico), ma in questo caso il valore rappresentato da "carico"
"passerebbe" solo se/o come numero intero. Nel caso di numeri decimali, sar
http://ennius.interfree.it/ Pagina 331
MANUALE VBA X EXCEL
meglio 'usare il formato Double (CDbl). Quindi si render il valore presente nella cella
D1 uguale a questo stesso valore pi il valore rappresentato da "carico"
Range("D1").Value = CDbl(carico) + Range("D1").Value
End Sub

Per lo scarico useremo un'altra istruzione (non ripeto i commenti)


Sub Scarica
scarico = InputBox("Inserisci la quantit da scaricare")
If scarico = "" Then Exit Sub
Range("D1").Value = Range("D1").Value - CDbl(scarico)
End Sub
Buon lavoro.

http://ennius.interfree.it/ Pagina 332


MANUALE VBA X EXCEL
Cosa sono e come usare le MessageBox (MsgBox)
Premesso che in VBA la "MsgBox" una "funzione", la guida di Excel la definisce come una "finestra di
dialogo". In effetti, avendo la possibilit di poter scegliere tra due pulsanti: SI e NO, come se si
dialogasse con la domanda che appare nella finestra, rispondendo ad una delle due opzioni. In
realt (e questo e solo ci che penso io) per "finestra di dialogo" si dovrebbe intendere una finestra
nella quale sia possibile inserire delle variabili, come accade con le InputBox (che una finestra di
introduzione dati (quindi variabili)- vedi in questa stessa sezione : "usare le InputBox").
La funzione MsgBox di Excel sfrutta una libreria presente nel SistemaOperativo (Windows) inserita dai
progettisti del SO per segnalarci gli errori di Sistema. In Excel, tramite il VBA, possibile richiamare
questa libreria e "pilotare" la comparsa di messaggi con le opportune istruzioni : la pi semplice,
questa:
MsgBox (chiama la finestra del messaggio) " Ciao!!!" (tra doppi apici, il messaggio che apparir nella
finestra)
Le finestre di messaggio, d'ora in avanti chiamate msgbox, saranno associate ad eventi decisi da noi
per fornire indicazioni, per avvisare di un errore, per dare una conferma, per una descrizione, per
obbligare una scelta, per...per...per... chi pi ne ha, pi ne metta.
La Sintassi (in programmazione) da usare :
MsgBox(prompt[, buttons] [, title] [, helpfile, context])
Per la spiegazione degli argomenti predefiniti rimando alla Guida in linea, sottolineando solo il
significato della parola prompt : con questa si intende il messaggio che vogliamo sia visualizzato;
mentre di seguito riporto le Costanti dell'argomento "buttons" che sono quelle che ci consentono di
scegliere il "tipo" di msgbox che vogliamo far apparire: dal pi semplice (con un bottone di OK) a
quelle con 2 o 3 pulsanti. Gli argomenti sono opzionali, cio si possono non inserire. Vediamole sotto
(non tutte):
Costante Valore Descrizione di come appare
vbOKOnly 0 Visualizza solo il pulsante OK.
VbOKCancel 1 Visualizza i pulsanti OK e Annulla.
VbAbortRetryIgnore 2 Visualizza i pulsanti Termina, Riprova, e Ignora.
VbYesNoCancel 3 Visualizza i pulsanti S, No e Annulla.
VbYesNo 4 Visualizza i pulsanti S e No.
VbRetryCancel 5 Visualizza i pulsanti Riprova e Annulla.
VbCritical 16 Visualizza l'icona di messaggio critico.
VbQuestion 32 Visualizza l'icona di richiesta di avviso.
VbExclamation 48 Visualizza l'icona di messaggio di avviso.
VbInformation 64 Visualizza l'icona di messaggio di informazione.
Quando adoperiamo una costante, la sintassi dell'istruzione sar diversa dal primo esempio, e andr
quindi compilata:
MsgBox ("Ciao !!!", vbInformation)
Solo che se adoperiamo questa istruzione il debugger ci segnala un errore di compilazione:
necessario assegnare l'istruzione ad una variabile, di tipo String (e va dimensionata) o di tipo Variant e
si pu omettere il dimensionamento (Dim), per cui sar sufficiente impostare la nostra istruzione cos :
dimmi = MsgBox ("Ciao !!!", vbInformation)
ed otterremo questo risultato:

La lunghezza di un messaggio pu arrivare fino a circa 1024 caratteri, dipende dal tipo di carattere
usato (i caratteri (font) normalmente usati, non occupano tutti uno stesso "spazio": in una stringa di
testo, il carattere " i ", per esempio, occupa meno spazio di una " a " o di una " g ", come pure un
carattere minuscolo occupa meno spazio delle stesso maiuscolo. Forse non tutti sanno che l'unico
carattere che mantiene lo stesso spazio per ogni lettera, il Courier). Se il messaggio suddiviso su pi
righe, possibile includere, tra ciascuna coppia di righe, un ritorno a capo (Chr(13)), un carattere di
avanzamento riga (Chr(10)) o una sequenza ritorno a capo-avanzamento riga (Chr(13) & Chr(10)). Il
http://ennius.interfree.it/ Pagina 333
MANUALE VBA X EXCEL
caratteri appena esposti, possono essere sostituiti dalle costanti corrispondenti, come nello specchietto
sotto:
vbCr pu sostituire Chr(13)
vbLf pu sostituire Chr(10)
vbCrLf pu sostituire Chr(13) + Chr(10)
Questo sotto, un esempio su come si pu compilare codice per far apparire un messaggio su pi
righe, all'apertura della cartella di lavoro:
Sub Messaggio()
Dim Lem As String

Lem = Lem & "Questo un esempio :" & vbLf & vbLf
Lem = Lem & "L'Autore :" & Chr(13) & vbLf
Lem = Lem & "Pinco Pallino" & vbLf
Lem = Lem & "Questo Programma" & vbLf
Lem = Lem & " tutelato dai" & vbLf & vbLf
Lem = Lem & "diritti d'Autore !!" & vbLf
Lem = Lem & "(non esiste, falso)" & vbLf & vbLf
Lem = Lem & "del Codice VBa di questo messaggio" & vbLf
Lem = Lem & "si raccomanda di fare tutte" & vbLf
Lem = Lem & "le variazioni che volete." & vbLf
Lem = Lem & "l'Autore lo concede (?!?!?)" & vbLf
Lem = Lem & "Ha......Ha......Ha"

MsgBox Lem
End Sub
e questo il messaggio generato dal codice sopra:

Ora vediamo come poter gestire due tipi di msgbox piuttosto utilizzate. vbYesNo e vbYesNoCancel.che
si presenteranno in questa forma rispettivamente :

Intanto notiamo che nella prima, la X di chiusura disabilitata : si pu uscire solo con un Si o con un No.
Nella seconda invece la X abilitata : infatti il pulsante Annulla, corrisponde alla chiusura della finestra
(e quindi alla X) SENZA avere optato n Si n No.
La prima la useremo per inserire nell'esecuzione del codice, una scelta operativa: a secondo del
pulsante che l'utente sceglier, compileremo le istruzioni necessarie : per una o due opzioni. Perch
una o due opzioni se gi con un pulsante rispondiamo praticamente a due diverse condizioni; in
http://ennius.interfree.it/ Pagina 334
MANUALE VBA X EXCEL
questo esempio, rispondendo Si, otteniamo un risultato, rispondendo No, otteniamo di non modificare il
risultato, per cui restano comunque due alternative:
Sub Prova1()
pippo = MsgBox("ciao! Vuoi proseguire ?", vbYesNo)
If pippo = vbYes Then
MsgBox "Pippo"
End Sub
L'effetto di questa istruzione sar: se rispondi Si, appare un messaggio, in caso contrario non succede
niente. implicito nel tipo di domanda (Si/No) avere No se Non si risponde Si e quindi non occorre
definire un istruzione per il caso No. Diverso il seguente esempio, nel quale se Non si risponde Si ,
avendo No come alternativa, vorremo sfruttare questa condizione per impostare una seconda
istruzione :
Sub Prova2()
pippo = MsgBox("ciao! Vuoi proseguire ?", vbYesNo)
If pippo = vbYes Then
MsgBox "Pippo"
Else
MsgBox "Ciao !!!"
End Sub
In questo caso, se si risponde Si, appare il messaggio "Pippo", se Non si risponde Si, appare "Ciao !!!" (si
sfrutta il No di vbYesNo con Else)
Diversa la finestra che otteniamo con vbYesNoCancel, nella quale, in un'istruzione come Prova2, il
pulsante Annulla ci consentirebbe di uscire senza avere scelto n Si n No. E' possibile comunque
sfruttare anche il pulsante Annulla ( o la X di chiusura), per ottenere una terza possibile azione, diversa
dalla chiusura, che obbligher una terza alternativa. Questo un esempio:
Sub Prova3()
pippo = MsgBox("ciao! Vuoi proseguire ?", vbYesNoCancel)
If pippo = vbYes Then
MsgBox "Pippo"
ElseIf pippo = vbCancel Then
MsgBox "Urca !!!"
Else
MsgBox "Ciao !!!"
End If
End Sub
Come si vede, vengono sfruttati tutti e tre i pulsanti, per ottenere tre alternative obbligate, escludendo
un uscita senza scelte.
Questa sotto invece una diversa sintassi che usa il vbYesNo, ma che imposta come valore predefinito
vbNo per NON compiere una azione. L'istruzione dice: col messaggio "Sicuro ecc..", se rispondi Si,
avviene l'azione prevista da Cancel (Cancel = True), altrimenti Non avviene detta azione (Cancel =
False)
Cancel = (MsgBox("Sicuro di voler chiudere la finestra ?", vbYesNo) = vbNo)
Se non avessimo usato questo tipo di istruzione, ma quella impostata nell'esempio Prova1, il VbNo non
sarebbe stato definito e l'azione Cancel sarebbe equivalsa ad un Si.: lasciando invariata l'istruzione
avremmo concesso a Cancel la sua funzione che quella di Chiudere.

http://ennius.interfree.it/ Pagina 335


MANUALE VBA X EXCEL
Usare le UserForm.
Abbiamo gi visto che Excel consente di inserire degli "Oggetti" nei nostri fogli di lavoro allo scopo di
migliorare la gestione delle nostre applicazioni. Un "oggetto" che ci pu aiutare parecchio la
USERFORM, cio una finestra che si apre, su comando, e che ci consente di immettere nuovi dati, o di
vedere, modificare dati gi inseriti; oltre alla praticit di un simile accorgimento, daremo anche un
aspetto un p pi "professionale" ai nostri lavori. Cominciamo quindi a vedere "come" inserire una
"userform". Dovremo aprire l' "Editor di Visual basic", e dal men "inserisci" selezionare "Userform", vedi
immagine sotto

una volta confermato con un click, apparir, nella finestrina "progetto", l'icona della cartella "Form", e
nella zona "codice" sulla destra, la nostra userform1 con relativa "casella degli strumenti", cio gli
"oggetti" che a loro volta potranno essere inseriti nella form stessa, vedi immagine sotto

Ricordo, che ogni "oggetto" possiede delle "propriet" , visibili nella finestra inferiore, posta a sinistra,
sotto la finestra "progetto", e che sono modificabili nelle impostazioni: la propriet "caption", che di
default impostata a "Userform1", la propriet che consente di modificare il nome che vedremo
nella barra del form, e che potremo modificare, per esempio in "Inserimento Dati", semplicemente
sostituendo la nuova frase a "Userform1". Vedi immagini sotto

http://ennius.interfree.it/ Pagina 336


MANUALE VBA X EXCEL

E questo sar l'effetto della modifica fatta:

Rimando tutti i "pellegrini" come me, alla guida in linea, per scoprire il significato delle varie "propriet"
legate ad ogni oggetto. Ogni "oggetto" possiede le proprie "propriet" e non necessariamente sono le
stesse degli altri oggetti.
Proseguendo nelle spiegazioni, faremo un esempio: realizzeremo una "Maschera di introduzione dati",
cio inseriremo nella form gli strumenti necessari alla raccolta dei dati, e saranno le textbox, e i pulsanti
necessari ad avviare le debite istruzioni, tipo un pulsante "Registra" ed un pulsante "Esci". Cominciamo
ad inserire le Textbox : dalla "casella degli strumenti" inseribili nella form, selezioniamo l'icona della
"Casella di Testo", in inglese "textbox", e spostandoci poi sulla form, clicchiamo su un punto e
trasciniamo: appare un'area tratteggiata che corrisponde alla dimensione che assumer la textbox
stessa:

rilasciando il pulsante del mouse vedremo la textbox disegnarsi, ancora col bordo tratteggiato, in
attesa di eventuali ridimensionamenti, da effettuarsi trascinando i quadratini che la circondano.
Contemporaneamente, nella finestra delle propriet appariranno le propriet della textbox, compreso
il nome, che sar TextBox1. Ogni altra textbox che verr inserita sar nominata col numero in sequenza
(textbox2, 3, ecc), questo per identificare in maniera univoca ogni oggetto inserito.

http://ennius.interfree.it/ Pagina 337


MANUALE VBA X EXCEL

Nelle caselle di testo, con la form in funzione, dovremo inserire i nostri dati, come se fossero delle celle
di un foglio di lavoro. Questi stessi dati saranno poi trasferiti in zone opportune del nostro foglio di
lavoro, quando premeremo il pulsante "Registra". Per identificare che tipo di dati vogliamo inserire in
una textbox, useremo una "Etichetta" (in inglese Label) che posizioneremo vicino alla textbox, e
inseriremo nella propriet "Caption" dell'etichetta, l'identificativo di ci che dovr essere inserito nella
textbox. SE la textbox dovr corrispondere ad un nome di un elenco, nella caption dell'etichetta
scriveremo "Nominativo". Per inserire l'etichetta nella form, useremo lo stesso procedimento usato per la
textbox (l'icona dell' etichetta la prima a sinistra rispetto a quella textbox). Questo l'effetto che
otterremo:

Nell'esempio che stiamo preparando, utilizzeremo solo 5 campi, giusto per imparare a lavorare, quindi,
oltre al nome, inseriremo un indirizzo , la citt, una data di nascita ed un campo "appunti". Quando
avremo di inserire le 5 textbox che accoglieranno i dati, e le relative etichette per indicare i campi,
avremo una form che si presenter cos:

Come vedete sono stati inseriti tutti i campi previsti, le relative etichette, e due pulsanti che serviranno
per registrare i dati, oppure annullare ed uscire. Un unica cosa da segnalare: la textbox5, quella che
ospiter i dati relativi ad "Appunti", visto che potr contenere anche informazioni contenenti molte
parole, ha dovuto essere modificata in due "propriet" che consentono di accettare testi lunghi : la
propriet "Multiline" stata impostata a True, (di default False) il che consentir di poter disporre di
pi righe dove scrivere, e la propriet "ScrollBars" (di default None) stata impostata su
"fmScrollBarsVertical", che consente di far apparire una barra di scorrimento verticale se il testo inserito
supera il numero di righe dato dall'attuale altezza della textbox5. A questo punto prendiamo in esame
il codice necessario a far funzionare la nostra applicazione.
Avremo bisogno di un comando per far apparire la nostra userform, e per questo useremo un pulsante
che metteremo sul foglio dove intendiamo far apparire la nostra "maschera di introduzione dati".
Prenderemo un "CommandButton" dalla "Casella degli strumenti" del foglio di lavoro, e nell'evento Click
del commandButton inseriremo la seguente istruzione:
Private Sub CommandButton1_Click()
UserForm1.Show
End Sub

http://ennius.interfree.it/ Pagina 338


MANUALE VBA X EXCEL
Questa istruzione far aprire la form sul nostro foglio di lavoro. Inseriremo i dati previsti e quindi
premeremo il pulsante "Registra dati". Le istruzioni di ci che vogliamo sia fatto andranno posizionate
nell'evento Click di questo pulsante (anche questo, essendo il primo commandbutton inserito nella
form, si chiamer CommandButton1). In precedenza, avremmo dovuto decidere in quale foglio, e in
quali celle, vorremo creare il nostro archivio. Supponiamo quindi di usare lo stesso foglio1, e di usare le
celle che vanno da A3 a E3 (5 campi).Le istruzioni sarebbero queste:
Private Sub CommandButton1_Click()
Worksheets("Foglio1").Range("A3") = TextBox1.Text
Worksheets("Foglio1").Range("B3") = TextBox2.Text
Worksheets("Foglio1").Range("C3") = TextBox3.Text
Worksheets("Foglio1").Range("D3") = TextBox4.Text
Worksheets("Foglio1").Range("E3") = TextBox5.Text
End Sub
Poich quando si fa eseguire un comando, preferibile far eseguire dei controlli per verificare che uno
o tutti i dati siano inseriti in maniera giusta, inseriremo una verifica sul campo "Nominativo": se ci
scorderemo di inserire questo dato, l'esecuzione delle istruzioni verr interrotta. In questo modo
eviteremo di registrare dei dati "incompleti". Questa sar la giusta impostazione delle istruzioni:
Private Sub CommandButton1_Click()
If TextBox1 = "" Then 'controlla che il textbox1 non sia vuoto, se vuoto allora
MsgBox "Bisogna inserire il Nominativo" 'avvisa con un messaggio
TextBox1.SetFocus 'posiziona il focus sul textbox1
Exit Sub 'ed esce dalla routine senza completare il resto delle istruz.
End If
Worksheets("Foglio1").Range("A3") = TextBox1.Text
Worksheets("Foglio1").Range("B3") = TextBox2.Text
Worksheets("Foglio1").Range("C3") = TextBox3.Text
Worksheets("Foglio1").Range("D3") = TextBox4.Text
Worksheets("Foglio1").Range("E3") = TextBox5.Text
End Sub
Ma la nostra istruzione non completa: compilata cos funziona, ma ogni volta che registreremo nuovi
dati, questi prenderanno il posto di quelli precedenti gi inseriti, ed allora addio al nostro archivio:
Sostituiremo dati esistenti con quelli nuovi, il che non va bene. Dobbiamo munire l'istruzione di un
comando che cerchi, nella zona destinata all'archivio, una riga vuota, e l, scarichi i nuovi dati. E'
possibile seguire diverse procedure, noi ne sceglieremo una sola, basata sulla propriet End Select e
sullo "Scarto" (Offset) (IMPORTANTE!!: per capire il funzionamento di End Select vi rimando in questa
sezione, al paragrafo "Copia/Incolla 2") e le nostre istruzioni saranno:
Private Sub CommandButton1_Click()
If TextBox1 = "" Then
MsgBox "Bisogna inserire il Nominativo"
TextBox1.SetFocus
Exit Sub
End If
Sheets("Foglio1").Select
Range("A1").Select
Selection.End(xlDown).Select
ActiveCell.Offset(1, 0).Select
ActiveCell = TextBox1.Text
ActiveCell.Offset(0, 1) = TextBox2.Text
ActiveCell.Offset(0, 2) = TextBox3.Text
ActiveCell.Offset(0, 3) = TextBox4.Text
ActiveCell.Offset(0, 4) = TextBox5.Text
End Sub
Con la routine sopra avremo i nostri dati inseriti sempre in nuove righe.
Questa invece l'istruzione che inseriremo nell'evento Click del secondo pulsante, che ci consente di
chiudere la form e scaricarla dalla memoria:
Private Sub CommandButton2_Click()
Unload Me
Set UserForm1 = Nothing
http://ennius.interfree.it/ Pagina 339
MANUALE VBA X EXCEL
End Sub
Non ancora finita: poich quando si ha a che fare con le date dobbiamo tenere presente che il
Visual Basic un linguaggio di programmazione concepito in inglese, e gli Inglesi, a differenza di noi,
usano mettere prima il mese, poi il giorno ed infine l'anno. Se scriviamo una data scritta nel nostro
sistema in un campo di testo, ed usiamo il codice per trasferire la data in una qualunque cella di un
foglio di lavoro, il codice legge la data in italiano, ma la converte nel sistema inglese come tale la
riporta nella cella. E' necessario quindi usare un'istruzione che "insegni" al codice a "rispettare" il nostro
formato. Questa istruzione la posizioneremo in un evento che sia antecedente all'esecuzione della
registrazione: useremo quindi l'evento "AfterUpdate" della textbox4 (quella che porter la data di
nascita), e questa l'istruzione:
Private Sub TextBox4_AfterUpdate()
TextBox4 = Format(TextBox4, "mm/dd/yy")
End Sub
Questa istruzione viene letta ed eseguita dal codice prima che noi si clicchi sul pulsante "Aggiorna
Dati" e quindi vedremo nella textbox4 la data scritta in modo giusto. Poich per trasferire un formato
specifico dalla userform (oggetto ActiveX) al Foglio di lavoro (l'esempio della data) il codice deve
poter interpretare il giusto formato, per convertirlo in modo che Excel lo capisca come tale,
necessario usare delle istruzioni particolari. Vi rimando per questo al paragrafo "il Vba e le date".

http://ennius.interfree.it/ Pagina 340


MANUALE VBA X EXCEL
Usare le UserForm in sostituzione di MessageBox o di InputBox
A seguito di una domanda rivoltami, mi pare utile esaminare un utilizzo delle UserForm al posto delle
Finestre di Dialogo. Il motivo semplice le UserForm si possono personalizzare a piacere : nella
dimensione della stessa, nella posizione in cui appaiono sullo schermo, nel tipo dimensione e colore dei
caratteri, nel titolo; si possono inserire immagini come sfondo o come immagine incorniciata. Risultano
decisamente pi conformabili alle esigenze dell'utente. Per contro, necessitano di un maggior lavoro
nella realizzazione del progetto, e diverse righe in pi di codice da compilare. Vediamo un esempio,
useremo due userform, una come Finestra di messaggio (msgbox), e l'altra come Finestra di
introduzione dati (inputbox). Nell'esempio simuliamo di voler controllare l'inserimento di un determinato
dato (la parola ALLOGGIO o la parola UFFICIO) in una cella (C3) e di voler essere avvisati se si
inseriscono dati diversi. Una volta introdotto il dato giusto, facciamo apparire una finestra di inserimento
dati (la inputbox), che ci chieder di inserire i Mq del locale. Una precisazione: per quanto riguarda il
controllo inserimento delle parole, il vba CaseSensitive, cio sensibile alle maiuscole o minuscole;
dovremo decidere prima di compilare l'istruzione nel codice, se la parola sar ALLOGGIO, oppure
alloggio, o ancora Alloggio, perch se nella cella preposta la scriveremo diversa da quanto contenuto
nel codice, verr segnalata come errore. Vediamo come procedere: intanto dovremo sfruttare un
"evento" che attivi il controllo, e useremo il SelectionChange del Foglio di lavoro, il WorkSheet. In questo
modo faremo controllare se la cella C3 sar vuota, o se invece conterr una parola. Se inseriremo una
parola uguale a quella prevista, allora si aprir la finestra di immissione dati (inputbox), in caso contrario
scatter la finestra di messaggio che ci avviser che il dato inserito errato, canceller il contenuto
della cella C3 e la selezioner posizionandoci il focus se si premer il pulsante Annulla, oppure scriver
la parola giusta se selezioneremo una delle due opzioni previste sulla form, e che altro non sono che
due "Etichette" (Label) la cui propriet "Caption" stata impostata con il giusto termine. Per quanto
riguarda invece l'evento che attiver la comparsa della inputbox, ho usato il Worksheet_Change che
controlla se la cella C3 subisce un cambiamento: se rester vuota o se il dato immesso diverso da
quello previsto (alloggio o ufficio), non succede niente, se invece corrisponder al termine previsto, si
attiver chiedendoci di immettere i Mq con la conferma sul pulsante OK. Vediamo il codice: questo
attiva la comparsa della UserForm1, usata come MsgBox:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Range("C3") = "" Then Exit Sub
If Range("C3") = "ALLOGGIO" Or Range("C3") = "UFFICIO" Then
Exit Sub
Else
UserForm1.Show
End If

End Sub
e questa l'immagine della nostra UserForm1

Nota: le due Label "ALLOGGIO" e "UFFICIO", si presentano rilevate, come un pulsante, perch si agito
sulla propriet "SpecialEffect" delle label impostandole a "fmSpecialEffectRaised". Sono possibili altri
effetti.
Questo invece il codice contenuto nella UserForm1: nell'evento "Activate" della userform inseriamo le
istruzioni per il posizionamento della form sul foglio di lavoro: Top (dall'alto) e Left (da sinistra) con i valori
espressi in punti. Poi sfruttiamo la propriet Caption della Label1 dicendogli (via codice) il testo che
apparir nella label stessa. Le altre istruzioni sfruttano l'evento Click del commandbutton1 e delle Label
per l'esecuzione delle stesse:
http://ennius.interfree.it/ Pagina 341
MANUALE VBA X EXCEL
Private Sub UserForm_Activate()
Top = 120
Left = 165
Label1.Caption = "ATTENZIONE ! il dato immesso NON valido. Inserire solo:"
End Sub
'sotto: Pulisce la cella C3, la seleziona, e chiude la form
Private Sub CommandButton1_Click()
Range("C3") = ""
Range("C3").Select
End
End Sub
'sotto: copia nella cella C3 la parola ALLOGGIO, poi chiude la form
Private Sub Label2_Click()
Range("C3") = "ALLOGGIO"
End
End Sub
'sotto: copia nella cella C3 la parola UFFICIO, poi chiude la form
Private Sub Label3_Click()
Range("C3") = "UFFICIO"
End
End Sub
Ora vediamo il codice per l'attivazione della UserForm2, usata come finestra di introduzione dati
(inputbox).
Private Sub Worksheet_Change(ByVal Target As Range)
If Range("C3") = "" Then Exit Sub
If Range("C3") = "ALLOGGIO" Or Range("C3") = "UFFICIO" _
And Range("D3") = "" Then
UserForm2.Show
End If
End Sub
Da notare solo che nella seconda istruzione (If Range....) oltre all'operatore OR (oppure) viene usato
anche l'operatore AND ( e ) per creare un'ulteriore condizione di controllo nel ciclo If....Then.....End If .
Se la cella C3 uguale ad ALLOGGIO oppure a UFFICIO, e la cella D3 vuota, allora mi fai apparire la
UserForm2, in caso contrario non si attiva. Un'altra nota da segnalare per i meno esperti questa:
quando una istruzione diventa lunga e si deve andare a capo, per far capire al codice che la nuova
riga la prosecuzione della precedente, si usa inserire dopo l'ultima lettera della riga stessa, uno spazio
seguito dalla barretta grande _ come nell'esempio = "UFFICIO" _ E questa l'immagine della UserForm2

Da segnalare che in questa userform il testo che vediamo nella Label1, anzich "caricarlo"
all'attivazione della form stessa, stato inserito direttamente nella finestra delle propriet della Lavbel1,
come nella foto sotto

http://ennius.interfree.it/ Pagina 342


MANUALE VBA X EXCEL

E questo il codice contenuto nella UserForm2


'questa istruzione pone le coordinate per la posizione della form sul foglio
Private Sub UserForm_Activate()
Top = 120
Left = 165
End Sub
'questa istruzione copia il valore immesso nella TextBox1 dentro la cella D3
Private Sub CommandButton1_Click()
Range("D3").Value = TextBox1.Value
End
End Sub
' possibile modificare l'istruzione sopra perch esegua un controllo che la TextBox1
non 'sia vuota
Private Sub CommandButton1_Click()
If TextBox1 = "" then Exit Sub 'se la textbox vuota, esce dalla routine
Range("D3").Value = TextBox1.Value
End
End Sub
'oppure avvisare con un messaggio
Private Sub CommandButton1_Click()
If TextBox1 = "" Then
MsgBox "Inserire i Mq."
TextBox1.SetFocus
Exit Sub
End If
Range("D3").Value = TextBox1.Value
End
End Sub

File con l'esempio, scaricabile e consultabile: Form-Box2000.zip 31 Kb


H H

http://ennius.interfree.it/ Pagina 343


MANUALE VBA X EXCEL
Usare Gif Animate nelle UserForm
Usare delle immagini per abbellire o personalizzare le nostre UserForm, abbastanza semplice, basta
intervenire sulla propriet "Picture" della UserForm, digitando o selezionando il percorso dove risiede
l'immagine che vogliamo sia inserita. Le altre "propriet" su cui potremo intervenire per gestire come
posizionare l'immagine nell'userform sono "PictureAlignment", "PictureSizeMode", che invito a scoprire
nelle varie combinazioni, e la "propriet" "PictureTiling" che andr impostata a True se vorremo che un
immagine piccola sia ripetuta fino a riempire tutta l'area della userform. Al di l dei modi di
impostazione immagine, tutte le immagini che potremo inserire saranno sempre e solo "statiche". E'
possibile invece inserire delle immagini in movimento, cio le classiche Gif Animate. Questo ci
permetter di creare dei nostri Logo animati, rendendo pi piacevole il nostro foglio di lavoro.
Bisogner disporre di un programma per la creazione di Gif animate, con il quale realizzare le nostre gif,
oppure utilizzare una qualsiasi gif animata, di cui internet pieno, basta solo cercare. Questo un
esempio di gif animata

Excel non dispone della possibilit diretta di accettare Gif animate, a meno che non si carichi un
apposito "controllo", cio una libreria (.dll) che si incarichi di far "dialogare" Excel con una Gif animata.
Per fare questo, dall'editor di visual basic, nella casella degli strumenti disponibili per una UserForm,
dovremo selezionare, con il pulsante destro del mouse, la casella stessa, e, dal men contestuale che
appare, scegliere : "Controlli aggiuntivi", oppure, meglio ancora, dalla barra dei menu, scegliere
"Strumenti/Riferimenti, e apparir questa finestra: dovremo selezionare nella finestra dei "Riferimenti
disponibili", il "controllo" che ci interessa (in questo caso Gif89 1.0). Quando nella finestra "Riferimenti
disponibili" non troviamo il "controllo" voluto, (perch ancora non "caricato"), dovremo premere il
pulsante "Sfoglia" per cercare la cartella dove avremo copiato la libreria (.dll) che ci interessa,

Con la pressione sul pulsante "Sfoglia", si aprir la finestra "Aggiungi riferimento", come questa sotto, che
la classica finestra di ricerca/apri file; di default la ricerca viene eseguita nella cartella di sistema
predisposta a contenere tutte le librerie, che per Windows 98x/2000/XP la cartella System32 presente
come sottocartella della cartella Windows sul vostro hard-disk. (nelle versioni precedenti detta cartella
si chiama System). A questo punto baster selezionare la libreria che ci interessa e cliccare sul pulsante
"Apri". Fatto questo, troveremo nella finestra "Riferimenti disponibili" (immagine precedente) la libreria
cos "caricata" e potremo selezionarla mettendo un segno di spunta nel quadratino a lato.

http://ennius.interfree.it/ Pagina 344


MANUALE VBA X EXCEL

Fatti questi passi, troveremo l'icona che rappresenta il nuovo controllo, inserita nella casella degli
strumenti relativa alla userform: baster selezionare detta icona, e cliccare e trascinare in una zona
libera della userform, cos come facciamo per gli altri controlli. A questo punto il "controllo" pronto per
ospitare la nostra Gif animata, dovremo solo usare la propriet "FileName" del controllo indicando il
percorso della Gif che vogliamo caricare, oppure sfruttare l'evento Activate della UserForm per fornire
via codice detto percorso, sul tipo di:
Private Sub UserForm_Activate()
Gif89a1.Filename = "C:\Documenti\ennius.gif
End Sub
Nell'immagine sotto sono evidenziati : la finestra delle propriet del controllo inserito (Gif89a1), la
propriet FileName, e sulla form, l'oggetto (Gif Control) ancora selezionato

Credo che non tutti abbiano il tempo di rintracciare questo "controllo", che si trova disponibile per free
download su molti siti che trattano VisualBasic, per cui chi vorr lo potr scaricare da questa pagina: Il
file andr poi copiato nella cartella System32 di Windows, per poterlo poi "caricare" dalla finestra
"Aggiungi riferimento". una precisazione: il "controllo" viene riconosciuto e lavora bene su Excel XP, non
l'ho provato su versioni precedenti.
Controllo da scaricare : GIF89.zip 23 Kb
H H

http://ennius.interfree.it/ Pagina 345

Potrebbero piacerti anche