Ancora una procedura per Copiare/Incollare  (07/01/03)

Utilizzo : Copia/Incolla dati in celle NON contigue con destinazione in celle contigue.

A differenza del metodo descritto in "Copia/Incolla 3" (vedi), in questa pagina useremo istruzioni differenti (avanzate) per ottenere lo stesso risultato, cioè la copia di dati in colonne non contigue, con incollaggio dei dati copiati in zone contigue. Presento due diversi modelli, che hanno in comune l'utilizzo di nuove istruzioni :

  • UsedRange (proprietà)

  • SpecialCells (Metodo)

  • xlLastCell (Costante)

  • Union (Metodo)

Gli esempi che seguiremo saranno:

  1. Con un elenco (tabella) di dati,  la copia dei dati inseriti nell'ultima riga, in Celle non contigue, e relativo incollaggio dei dati così copiati, in una zona dello stesso foglio o di un altro foglio, ma in Celle contigue, con inserimento nella zona destinazione con ricerca della prima riga libera (progressione).

  2. Sempre partendo da un elenco (tabella di dati) posti su più colonne, la copia di Colonne non contigue con incollaggio dei dati così copiati, in una zona dello stesso foglio o di un altro foglio, ma in Colonne contigue. (quindi non solo i dati presenti nell'ultima riga, ma tutti i dati presenti in una o più colonne con incollaggio nella zona di destinazione, con sostituzione in questa zona dei dati già presenti con i nuovi dati (aggiornamento totale).

Vediamo intanto le spiegazioni circa le nuove istruzioni:

La proprietà UsedRange. In effetti la Guida è un pò avara di chiarimenti, e comunque, per Excel, lo UsedRange è la zona che, sul foglio di lavoro, va dalla cella A1 all'ultima cella del foglio, rappresentata dall'incrocio dell'ultima riga con l'ultima colonna, in pratica tutto il foglio. E' possibile "pilotare" la zona da assegnare all' UsedRange, semplicemente indicando il riferimento ad una cella che serva da inizio zona: se usiamo quindi  UsedRange con SpecialCells e la costante xlLastCell, tutto ciò che si troverà sotto e a destra di questa cella, rappresenterà l'UsedRange, purchè contenga dati, anche in celle non contigue. In realtà l'UsedRange, su un foglio vuoto, da solo non potrebbe agire (o meglio, identificherebbe SOLO la cella iniziale scelta) se non definiamo alcuni parametri: fino a quale cella si dovrà intendere la zona coperta da UsedRange, e/o quale tipo di celle comprendere. Useremo quindi il metodo SpecialCells  il quale fa riferimento a tutte le celle che risponderanno al "tipo" specificato. Per definire il "tipo" useremo delle "Costanti" specifiche. Eventualmente queste costanti si possono sommare, col risultato di comprendere più "tipi".  Vediamo sotto uno specchietto di queste costanti .

Tipo

Significato

xlCellTypeNotes

Celle contenenti note

xlCellTypeCostants

Celle contenenti costanti

xlCellTypeFormulas

Celle contenenti formule

xlCellTypeBlanks

Celle vuote

xlCellTypeLastCell

Ultima cella del foglio di lavoro

xlCellTypeVisible

Tutte le celle visibili

Vediamo un esempio e relative istruzioni. E' possibile assegnare un nome a questa cella, e usare il nome come riferimento nelle istruzioni. Nell'esempio sotto, per meglio capire, useremo la cella F13 come riferimento inizio zona, ed evidenzieremo l'UsedRange, che si fermerà alla cella L22 perchè questa è l'ultima cella che contiene dei dati.

Questa l'istruzione che abbiamo usato:

Sub Miazona()
Set LastCell = ActiveSheet.UsedRange.SpecialCells(xlLastCell)
Range(Range("F13"), LastCell).Select
End Sub

E' evidente che se invece che selezionare una zona, avessimo voluto pulirne le celle, avremmo adoperato un'istruzione appropriata, tipo Range(Range("F13"), LastCell).ClearContents, oppure avremmo potuto decidere il tipo di font, il grassetto, il colore celle, ecc. ecc. con un comando unico.

Due precisazioni: usare una costante specifica su un foglio che non contiene il "tipo" di celle previsto dalla costante scelta, genera un errore. Quindi assicurarsi di usare la o le costanti giuste in funzione del tipo di celle che vorremo comprendere. L'altra è che se usiamo UsedRange assegnando una cella di inizio zona, e non esistono dati nelle celle sottostanti e a destra di questa cella, ma esistono dati sopra, (sia a destra che a sinistra) rispetto alla cella inizio zona, l'UsedRange cercherà la prima cella sopra e la prima cella sopra a destra occupate, e comprenderà le celle in queste zone, non sotto. Esercitatevi su un foglio per meglio capire, anche variando le costanti, con xlBlanks o xlVisible.

L'ultima istruzione prevista a inizio foglio, è il metodo Union - Union consente di unire più intervalli discontinui, utile quando si voglia, per esempio, copiare range di celle non contigui. Questo metodo ha come "argomenti", i riferimenti alle celle che esso unisce. Esempio:

Dim c1, c2, c3, Intervallo As Range
Set c1 = Range("A1")
Set c2 = Range("D1")
Set c3 = Range("G1")
Set Intervallo = Union(c1, c2, c3)
Intervallo.Copy

Ed ora passiamo agli esempi  del Copia/Incolla. Per il primo modello, useremo la tabella già usata per il "Copia/incolla3". Per questo esempio, ipotizzeremo di avere una tabella con dei dati che inseriremo riga per riga, e di cui vorremo copiare solo i dati di alcune colonne (in questo caso evidenziate in giallo), MA di voler copiare solo i dati inseriti nell'ultima riga. (il perchè lo lascio decidere a voi, potrebbe essere che non tutte le righe debbano essere copiate, o un altro motivo, l'importante è vedere quali istruzioni compileremo per questa operazione.) Quindi i dati da copiare si trovano sulla stessa riga, MA in colonne discontinue. I dati poi li vorremo incollare in una zona dello stesso foglio o anche di un altro foglio, e che l'elenco che si formerà con l'incollaggio formi una nuova tabella però con colonne contigue. Questa sotto l'immagine della ipotetica tabella:

e vediamo allora le istruzioni, e relative spiegazioni:

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

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

Intervallo.Copy
'copia di Intervallo, cioè delle celle discontinue prec. assegnate
Range("L1").Select
'selezione della cella dove incollare i dati copiati (sullo stesso foglio)
Selection.End(xlDown).Select 
'selezione dell'ultima cella occupata a partire da L1
ActiveCell.Offset(1, 0).Select 
'selezione della cella sotto l'ultima occupata (che è vuota)
ActiveSheet.Paste ActiveCell 
'incollaggio (Paste) di  Intervallo nella cella ora attiva. 'Trattandosi di cinque celle, è sufficiente selezionare una prima cella, ed Excel "scaricherà" in sequenza (cioè contigui) sulla stessa riga,  i cinque dati memorizzati.
'sotto: elimina il tratteggio intorno alle celle copiate

Application.CutCopyMode = False

End Sub

Ricordo ai lettori che la procedura per incollare, utilizzando End più Offset(1, 0), dovrà trovare le prime due celle di inizio elenco (L1 e L2) occupate o con una intestazione di campo, o qualsiasi altro valore (basta anche un punto).

Vediamo ora il secondo esempio di Copia/Incolla. Sempre usando la tabella dell'esempio precedente, questa volta copieremo non più i dati delle celle dell'ultima riga, ma le intere colonne, discontinue (le gialle) qualunque sia la lunghezza raggiunta, e incolleremo i dati sul Foglio2. In questo caso, anzichè cercare nella destinazione, la prima riga libera per scaricare i dati, trattandosi ad ogni copia/incolla di trasferire TUTTE le righe delle colonne interessate, provvederemo alla cancellazione dei dati presenti in  tutta la zona di destinazione (utilizzeremo UsedRange) visto che ricostruiremo un nuovo elenco aggiornato. Sul foglio2, per identificare la cella che ci servirà come inizio elenco per incollare i dati, la B6, gli assegneremo un nome, che definiremo come più ci piace (in questo esempio il nome sarà "pippo"). Sotto la tabella che forma l'elenco di destinazione:

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

Sub incolladue()

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


'dichiarazioni delle variabili come Range
Dim c1, c2, c3, c4, c5 Intervallo As Range

'comincia l'assegnazione non più di una singola cella della colonna A ad una variabile, ma di tutte le righe che porteranno dati a partire dalla prima cella (A1) e fino all'ultima cella occupata (End), e queste sono le istruzioni da impostare, per ogni variabile (colonna):
With Foglio1.Range("A1")
Set c1 = Range(.Cells(1), .End(xlDown))
End With
With Foglio1.Range("B1")
Set c2 = Range(.Cells(1), .End(xlDown))
End With
With Foglio1.Range("D1")
Set c3 = Range(.Cells(1), .End(xlDown))
End With
With Foglio1.Range("F1")
Set c4 = Range(.Cells(1), .End(xlDown))
End With
With Foglio1.Range("I1")
Set c5 = Range(.Cells(1), .End(xlDown))
End With

'a questo punto sono state identificate e assegnate tutte le colonne da inizio colonna fino 'all'ultima riga occupata
Set Intervallo = Union(c1, c2, c3, c4, c5)
'assegnazione ad Intervallo dell'UNIONE delle 'zone precedentemente assegnate alle variabili.

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

'ora la pagina (Foglio2) è pronta per copiare/incollare i dati, con il metodo Copy applicato all'oggetto Range

' oggetto.Copy [destinazione]


Intervallo.Copy ("pippo")


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

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

End Sub