In linea di massima le operazioni che si possono compiere sono le stesse di quelle che siamo abituati a compiere sul foglio attivo: selezioni ed individuazione di intervalli, lettura e scrittura di valori, ecc.
C'è solo bisogno di allargare le nostre vedute. Basta indicare al codice che, invece di lavorare sulle celle del foglio attivo, abbiamo intenzione di lavorare su celle di altri fogli.
Lavorando su oggetti diversi quali possono essere due differenti fogli per trattare (leggere o scrivere) valori che si trovano in un foglio o in un altro in linea di massima occorre specificare il foglio sul quale il valore è residente o sul quale vogliamo scrivere il valore. Non è sufficiente un generico:
Range("D5") = Range("B5") ma a volte è necessario specificare sia il foglio di destinazione che il foglio di origine come nell'esempio:
Sheets("Foglio1").Range("A9") = Sheets("Foglio3").Range("A1").
Per chiarirci le idee io penso che nell'uso del VBA dobbiamo acquisire un po' una mentalità militare per comprendere come in questo ambiente regna la gerarchia.
Questa gerarchia di oggetti viene a formare come una piramide alla cui cima sta l'oggetto da cui hanno origine tutti gli altri oggetti intermedi che a loro volta contengono altri oggetti via via più piccoli e più numerosi.
E' così che, partendo dall'oggetto Application, che rappresenta il padre dell'intera applicazione Excel, arriviamo, passando attraverso oggetti intermedi (Workbooks, Sheets, ecc), verso gli oggetti di ordine inferiore (Range, Cells per scendere fino a Font, Interior, ecc).
Nelle nostre istruzioni occorre solo porre attenzione a fare i giusti riferimenti ai giusti oggetti. Tanto per rimanere nel tema diciamo subito che per lavorare con celle di fogli diversi, le nostre azioni possono essere eseguite
Queste possono essere le situazioni in cui possiamo venire a trovarci:
Fatte queste premesse possiamo passare ad esaminare le istruzioni che di volta in volta occorre utilizzare.
Per copiare i valori da una cella di un foglio ad un'altra cella di un altro foglio:
Per compiere questa azione saremmo tentati a scrivere una cosa del genere:
Sheets("Foglio2").Range("A1").Select
Purtroppo l'istruzione genera un errore se il Foglio2 non è già attivo (ma in questo caso il riferimento al foglio sarebbe inutile). Il motivo dell'errore sollevato da questa istruzione è che non si può selezionare una cella in un foglio che non sia quello attivo e che l'istruzione non riesce ad eseguire contemporaneamente le due azioni: attivare il foglio e selezionare la cella indicata.
Vediamo subito un esempio destinato a fallire:
A questa istruzione possiamo (dobbiamo) sostituire una delle seguenti istruzioni:
Vediamo gli esempi corretti per ciclare tra i fogli e selezionare le celle usando le due sintassi:
oppure l'altra:
In genere è inutile effettuare selezioni. Sarà sufficiente lavorare a distanza, cioè lavorare su ogni foglio senza andarci fisicamente, e potremo cambiare la routine come mostrato qui di seguito:
Es. 1a Modificare una cella per ogni foglio senza effettuare alcuna selezione
In tutti i casi in cui occorre compiere molte azioni su un singolo oggetto, per semplificare le istruzioni, è possibile usare l'istruzione With. L'istruzione With può anche essere nidificata, ma l'istruzione With più interna, pur riferendosi ad un oggetto diverso da quello più esterno, dovrà comunque riferirsi ad un oggetto gerarchicamente inferiore a quello a cui il primo With si riferisce.
With Sheets("Foglio1")
With .Range("K1")
With .Font
In questa serie di With ci riferiamo all'oggetto Font dell'oggetto Range dell'oggetto Sheets rispettandone rigorosamente la scala gerarchica.
In una serie di With nidificati non ci si potrà riferire ad un altro oggetto gerarchicamente uguale o superiore a quello puntato dal With più esterno. Se col primo With ci riferiamo ad un determinato Foglio, col secondo With dovremo riferirci ad una cella di quel foglio e non ad un altro foglio o una cella di un altro foglio. Se col secondo With vogliamo riferirci ad un'altra cella dello stesso foglio, dobbiamo prima chiudere il precedente riferimento alla cella e riaprirne un altro che si riferisca ad un'altra cella.
With Sheets("Foglio1")
With .Range("K1")
...........
End With
With .Range("K5")
...........
End With
End With
Gli oggetti dipendenti dall'oggetto puntato da With saranno contraddistinti da un punto (.) usato come prefisso:
Se il nostro lavoro dovrà svolgersi su due differenti fogli magari diversi da quello attivo, anche se è lecito pensare di usare l'istruzione With per semplificare le nostre azioni, è tuttavia necessario decidere quale dei fogli e relative celle deve essere indicato da With e quale trattare senza With.
Se scriviamo: With Sheets("Foglio1") con un successivo With nidificato nel primo dovremo riferirci ad una cella dello stesso Foglio1: With .Range("K1") oppure: With .Range("K1").Font ma non possiamo riferirci a celle di un altro foglio. Vediamo un esempio pratico:
Di seguito propongo alcuni esempi per chiarire i concetti sin qui esposti.
Questo esempio mostra una ulteriore espansione dell'Esempio visto sopra
Questo che segue è simile al precedente
Con questo esempio spazzoliamo tutti i fogli di una cartella per controllare se la cella C10 è vuota
Nel seguente esempio il foglio attivo è uno diverso dal Foglio1 e senza spostarci da questo eseguiamo alcune azioni sul Foglio1. Uso tre With nidificati ognuno dei quali si riferisce a vari oggetti gerarchicamente via via più bassi:
Sheets ---> Range ---> Font
Sheets ---> Range ---> Interior
Per entrare nell'Interior dell'oggetto Range, dobbiamo prima uscire da Font dello stesso oggetto Range.
Nello scrivere la routine dobbiamo porre la massima attenzione al punto ( . ) da scrivere prima delle proprietà dell'oggetto a cui ci riferiamo:
Con questo codice siamo in grado di lavorare sul Foglio1 anche se ci troviamo su un altro foglio.
Volendo fare a meno delle istruzioni With il nostro codice si leggerebbe pressappoco così:
Sheets("Foglio1").Range("K2").Font.Name = "Arial"
Sheets("Foglio1").Range("K2").Font.FontStyle = "Grassetto"
Sheets("Foglio1").Range("K2").Font.Size = 11
Sheets("Foglio1").Range("K2").Interior.ColorIndex = 40 ecc
In questo esempio, da una tabella globale, vogliamo estrarre, di volta in volta, i vari elementi e deporli, senza ripetizioni, in un altro foglio e segnalarne tutte le occorrenze.
| Cod Art | Operatore | Prodotto | Confez. | Pezzi venduti |
|---|---|---|---|---|
| 35031 | Andrea | Tonno | scatole | 181 |
| 84040 | Massimo | Coca Cola | bottiglie | 53 |
| 67030 | Maurizio | Maccheroni | confezione | 115 |
| 48012 | Silvano | Maionese | vasetti | 20 |
| 10060 | Alessio | Tonno | scatole | 107 |
| 20070 | Giovanni | Maionese | vasetti | 127 |
| 53040 | Giuseppe | Maccheroni | confezione | 438 |
| 61040 | Oreste | Mostarda | vasetti | 425 |
| 22050 | Massimo | Alici | scatole | 402 |
| 53021 | Alessio | Maionese | vasetti | 182 |
| 09071 | Giovanni | Pane | confezione | 130 |
| 65020 | Oreste | Maccheroni | confezione | 220 |
| 15024 | Andrea | Tonno | scatole | 355 |
| 24021 | Silvano | Pane | confezione | 170 |
| 04010 | Silvano | Coca Cola | bottiglie | 128 |
| 07020 | Maurizio | Alici | scatole | 119 |
| 21049 | Giuseppe | Mostarda | vasetti | 95 |
| 20081 | Silvano | Maccheroni | confezione | 225 |
| 23030 | Massimo | Alici | scatole | 15 |
ottenendo, a seconda della scelta effettuata, degli elenchi così composti:
| Operatore | Occorrenze | Prodotto. | Occorrenze |
Confez | Occorrenze | ||
|---|---|---|---|---|---|---|---|
| Andrea | 2 |
Tonno | 3 |
scatole | 6 |
||
| Massimo | 3 |
Coca Cola | 2 |
bottiglie | 2 |
||
| Maurizio | 2 |
Maccheroni | 4 |
confezione | 6 |
||
| Silvano | 4 |
Maionese | 3 |
vasetti | 5 |
||
| Alessio | 2 |
Mostarda | 2 |
||||
| Giovanni | 2 |
Alici | 3 |
||||
| Giuseppe | 2 |
Pane | 2 |
||||
| Oreste | 2 |
Con la routine che verrà presentata tra poco si potrà agire su due fogli da un qualsiasi foglio della cartella di lavoro. Ossia:
a prescindere da quale sia il foglio attivo preleveremo i dati dal foglio denominato "Vendite" e depositati, dopo l'elaborazione, nel foglio denominato "Riepilogo".
Unico vincolo è quello di scrivere nella cella "I1" la colonna della tabella da esaminare:
es: 1 per la colonna 1, 2 per la colonna 2, ecc.
Le azioni che compieremo nel codice saranno queste:
determiniamo l'intervallo di origine con le ormai note istruzioni:
dopo di questo si legge il contenuto della cella "I1" e se ne verifica il valore:
dopo di questo si passa a lavorare nell'intervallo precedentemente determinato per creare un elenco univoco di tutti gli elementi della colonna in esame usando una Collection:
quindi si conclude trasferendo i dati trovati nel foglio di destinazione.
Con With Sheets("Riepilogo") si punterà al foglio denominato "Riepilogo"
dopo aver contato, nel foglio di origine le occorrenze di ciascun elemento contenuto nella collection si aggiorna la nuova tabella fel foglio di destinazione denominato "Riepilogo" (notate come ci si riferisce alle celle del foglio "Riepilogo" anteponendo un punto ( . ) a queste celle.
Questo che segue è il codice completo:
Se qualcosa ancora non è chiaro, penso che potremmo tornare sull'argomento.