Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
http://ennius.interfree.it/ Pagina 1
MANUALE VBA X EXCEL
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
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:
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):
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.
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
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 :
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
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.
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.
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.
http://ennius.interfree.it/ Pagina 18
MANUALE VBA X EXCEL
Posizionare le Istruzioni
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:
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:
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:
(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
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
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
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:
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:
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
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.
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:
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")
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
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:
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:
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:
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:
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.
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 :
Oppure
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:
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,
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:
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) :
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):
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]])
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.
Funzione DateAdd Restituisce un valore Variant (Date) contenente una data alla quale stato
aggiunto un intervallo di tempo specificato.
Sintassi
DateAdd(interval, number, date)
date Obbligatoria. Valore Variant (Date) o stringa che rappresenta una data a cui viene
aggiunto l'intervallo.
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)
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)
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
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
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
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
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
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" ):
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.
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:
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:
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 :
Sub selezona()
With zona
.Font.ColorIndex = 0
.Font.Bold = False
End With
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
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.
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:
Sub selezonadue()
With zona
.Font.ColorIndex = 0
.Font.Bold = False
End With
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
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.
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
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
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
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
:
http://ennius.interfree.it/ Pagina 72
MANUALE VBA X EXCEL
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.
http://ennius.interfree.it/ Pagina 73
MANUALE VBA X EXCEL
Propriet Descrizione
Settings Imposta e restituisce in forma di stringa i valori di velocit in baud, parit, bit
di dati e bit di stop.
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:
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
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:
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.
http://ennius.interfree.it/ Pagina 76
MANUALE VBA X EXCEL
Impostazione Valore Descrizione
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..
comEvDSR 4 Modifica della linea DSR (Data Set Ready). Questo evento
viene generato solo con la modifica di DSR da 1 a 0.
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.
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:
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
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)
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 )
e questo il risultato:
http://ennius.interfree.it/ Pagina 82
MANUALE VBA X EXCEL
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/
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)
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:
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.
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:
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:
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:
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.
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:
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 :
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:
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.
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
Come vedete, un simpatico modo di abbellire i nostri lavori; questi tre esempi:
http://ennius.interfree.it/ Pagina 99
MANUALE VBA X EXCEL
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
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.
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
End Sub
In questo modo, ci che verr scritto nelle celle G1 ecc, sar usato come valore di confronto.
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
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.
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
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)
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
'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.
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
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
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
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.
'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
Intervallo.Copy ("pippo")
With Range("pippo")
.Sort Key1:=.Offset(0, 0), Order1:=xlAscending, header:=xlYes
End With
End Sub
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
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
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"
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
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"
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
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"
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
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")
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
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)
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:
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
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
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.
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
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)
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.
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:
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:
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).
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:
Come si nota le Label sono aggiornate per i nuovi campi. Altrettanto succeder per gli altri fogli.
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.
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)
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:
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
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:
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.
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
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.
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
End Sub
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.
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
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:
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.
End With
End If
Next 'continuo il ciclo
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
Sheets(1).Select
Range("A1").Select
Selection.End(xlDown).Select
ActiveCell.Offset(1, 0).Select
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
'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)
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
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".
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:
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
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
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
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
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
DSum
DVar
DVarP
ritorna
ed avremo :
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:
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.
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.
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.
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 :
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 :
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)
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.
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")
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
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)"
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.
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.
Buon lavoro.
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")
'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
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:
Buon lavoro.
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
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
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.
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))
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
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
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
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))
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
Fine:
End Sub
Ancora grazie a Marco.
Application.ScreenUpdating = False
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))
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
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
Buon lavoro.
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.
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)
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.
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
'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.
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:
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:
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)
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
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
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.
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"
'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
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
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.
'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
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.
Dim CL As Object
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:
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:
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
'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
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.
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"
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
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)
Else
MsgBox "Nome non Trovato"
End If
End With
End Sub
With Worksheets(1).Range("A2:H100")
Dim Message, Title, MyValue
Dim X As String
X = MyValue 'viene assegnato alla X il contenuto della Inputbox
Set c = .Find(X, LookIn:=xlValues, LookAt:=xlWhole)
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()
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.
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.
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.
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()
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 riattivarle:
Else
ActiveSheet.Protect 'e proteggiamo il foglio attivo
End If
End Sub
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)
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
'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
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
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
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
Buon lavoro.
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")
Buon lavoro.
End With
End Sub
Se avessimo voluto sostituire dei valori fissi (20 in 15), questa la routine (pi semplice):
Sub FindValoreFisso()
End With
End Sub
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.
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 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.
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.
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
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:
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:
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
'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
Buon lavoro.
---------------------------------------------
Private Sub Workbook_Open()
Sheets("Foglio1").Shapes("Oggetto 1").Select
Selection.Verb Verb:=xlPrimary
End Sub
---------------------------------------------
Ciao,
Stefano
Un grazie a Stefano.
Buon lavoro.
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.
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:
Buon lavoro.
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.:
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
Buon lavoro.
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
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
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.
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
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.
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
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
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.
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