excel-vba
Errori comuni
Ricerca…
Riferimenti qualificanti
Quando ci si riferisce a un worksheet
, un range
o singole cells
, è importante qualificare completamente il riferimento.
Per esempio:
ThisWorkbook.Worksheets("Sheet1").Range(Cells(1, 2), Cells(2, 3)).Copy
Non è completamente qualificato: i riferimenti di Cells
non hanno una cartella di lavoro e un foglio di lavoro associati. Senza un riferimento esplicito, Cells fa riferimento a ActiveSheet
per impostazione predefinita. Quindi questo codice fallirà (produrrà risultati errati) se un foglio di lavoro diverso da Sheet1
è il ActiveSheet
corrente.
Il modo più semplice per correggere ciò è utilizzare un'istruzione With
come segue:
With ThisWorkbook.Worksheets("Sheet1")
.Range(.Cells(1, 2), .Cells(2, 3)).Copy
End With
In alternativa, è possibile utilizzare una variabile del foglio di lavoro. (Questo sarà probabilmente il metodo preferito se il tuo codice deve fare riferimento a più fogli di lavoro, come copiare i dati da un foglio a un altro.)
Dim ws1 As Worksheet
Set ws1 = ThisWorkbook.Worksheets("Sheet1")
ws1.Range(ws1.Cells(1, 2), ws1.Cells(2, 3)).Copy
Un altro problema frequente è fare riferimento alla raccolta dei fogli di lavoro senza qualificare la cartella di lavoro. Per esempio:
Worksheets("Sheet1").Copy
Il foglio di lavoro Sheet1
non è completo e manca di una cartella di lavoro. Questo potrebbe fallire se nel codice vengono referenziate più cartelle di lavoro. Invece, utilizzare uno dei seguenti:
ThisWorkbook.Worksheets("Sheet1") '<--ThisWorkbook refers to the workbook containing
'the running VBA code
Workbooks("Book1").Worksheets("Sheet1") '<--Where Book1 is the workbook containing Sheet1
Tuttavia, evitare di utilizzare quanto segue:
ActiveWorkbook.Worksheets("Sheet1") '<--Valid, but if another workbook is activated
'the reference will be changed
Allo stesso modo per gli oggetti range
, se non esplicitamente qualificato, l' range
si riferirà al foglio attualmente attivo:
Range("a1")
Equivale a:
ActiveSheet.Range("a1")
Eliminazione di righe o colonne in un ciclo
Se vuoi eliminare righe (o colonne) in un ciclo, dovresti sempre eseguire il ciclo partendo dalla fine dell'intervallo e tornare indietro in ogni passaggio. In caso di utilizzo del codice:
Dim i As Long
With Workbooks("Book1").Worksheets("Sheet1")
For i = 1 To 4
If IsEmpty(.Cells(i, 1)) Then .Rows(i).Delete
Next i
End With
Perderai alcune righe. Ad esempio, se il codice cancella la riga 3, la riga 4 diventa la riga 3. Tuttavia, la variabile i
cambierà in 4. Quindi, in questo caso il codice mancherà di una riga e ne controllerà un'altra, che non era nell'intervallo in precedenza.
Il codice giusto sarebbe
Dim i As Long
With Workbooks("Book1").Worksheets("Sheet1")
For i = 4 To 1 Step -1
If IsEmpty(.Cells(i, 1)) Then .Rows(i).Delete
Next i
End With
ActiveWorkbook vs. ThisWorkbook
ActiveWorkbook
e ThisWorkbook
volte vengono utilizzati in modo intercambiabile dai nuovi utenti di VBA senza comprendere appieno a che cosa si riferisce ogni oggetto, questo può causare un comportamento indesiderato in fase di esecuzione. Entrambi questi oggetti appartengono all'oggetto dell'applicazione
L'oggetto ActiveWorkbook
fa riferimento alla cartella di lavoro attualmente nella vista più in alto dell'oggetto dell'applicazione Excel al momento dell'esecuzione. (es. La cartella di lavoro che puoi vedere e interagire con il punto in cui viene fatto riferimento a questo oggetto)
Sub ActiveWorkbookExample()
'// Let's assume that 'Other Workbook.xlsx' has "Bar" written in A1.
ActiveWorkbook.ActiveSheet.Range("A1").Value = "Foo"
Debug.Print ActiveWorkbook.ActiveSheet.Range("A1").Value '// Prints "Foo"
Workbooks.Open("C:\Users\BloggsJ\Other Workbook.xlsx")
Debug.Print ActiveWorkbook.ActiveSheet.Range("A1").Value '// Prints "Bar"
Workbooks.Add 1
Debug.Print ActiveWorkbook.ActiveSheet.Range("A1").Value '// Prints nothing
End Sub
L'oggetto ThisWorkbook
fa riferimento alla cartella di lavoro a cui appartiene il codice nel momento in cui viene eseguita.
Sub ThisWorkbookExample()
'// Let's assume to begin that this code is in the same workbook that is currently active
ActiveWorkbook.Sheet1.Range("A1").Value = "Foo"
Workbooks.Add 1
ActiveWorkbook.ActiveSheet.Range("A1").Value = "Bar"
Debug.Print ActiveWorkbook.ActiveSheet.Range("A1").Value '// Prints "Bar"
Debug.Print ThisWorkbook.Sheet1.Range("A1").Value '// Prints "Foo"
End Sub
Interfaccia a singolo documento e interfacce a più documenti
Si noti che Microsoft Excel 2013 (e versioni successive) utilizza Single Document Interface (SDI) e che Excel 2010 (e successivi) utilizza Multiple Document Interfaces (MDI).
Ciò implica che per Excel 2013 (SDI), ogni cartella di lavoro in una singola istanza di Excel contenga la propria interfaccia utente della barra multifunzione:
Al contrario, per Excel 2010, ciascuna cartella di lavoro in una singola istanza di Excel utilizzava un'interfaccia utente nastro comune (MDI):
Ciò solleva alcuni problemi importanti se si desidera eseguire la migrazione di un codice VBA (2010 <-> 2013) che interagisce con la barra multifunzione.
È necessario creare una procedura per aggiornare i controlli dell'interfaccia utente della barra multifunzione nello stesso stato in tutte le cartelle di lavoro per Excel 2013 e versioni successive.
Nota che :
- Tutti i metodi, gli eventi e le proprietà delle finestre a livello di applicazione di Excel rimangono inalterati. (
Application.ActiveWindow
,Application.Windows
...) - In Excel 2013 e versioni successive (SDI) tutti i metodi, gli eventi e le proprietà delle finestre a livello di cartella di lavoro ora operano nella finestra di livello superiore. È possibile recuperare l'handle di questa finestra di livello superiore con
Application.Hwnd
Per ottenere maggiori dettagli, vedere la fonte di questo esempio: MSDN .
Ciò causa anche alcuni problemi con userforms non modali. Vedi qui per una soluzione.