Perché la macro Excel risulta lenta quando think-cell è attivato?
Un problema comune che può causare problemi di prestazioni in macro VBA è l’uso della funzione .Select
. Ogni qualvolta viene selezionata una cella in Excel, ogni singolo add-in di Excel (compreso think-cell) riceve una notifica su questo evento di modifica della selezione, che rallenta considerevolmente la macro. Specialmente le macro create utilizzando il registratore macro tendono a dare questo tipo di problema.
- Blog Office: "Qual è il modo più rapido di analizzare un intervallo esteso in Excel?"
- MSDN: Improving Performance in Excel 2007: "Reference Excel objects such as Range objects directly, without selecting or activating them" (MSDN: Incrementare le prestazioni in Excel 2007: "Riferimento diretto ad oggetti Excel come oggetti Range, senza selezionarli o attivarli" (nella sezione "Faster VBA Macros")).
Esempio: Come evitare l’uso dell’istruzione .Select
Analizziamo la seguente macro semplice AutoFillTable
:
Sub AutoFillTable()
Dim iRange As Excel.Range
Set iRange = Application.InputBox(prompt:="Enter range", Type:=8)
Dim nCount As Integer
nCount = iRange.Cells.Count
For i = 1 To nCount
Selection.Copy
If iRange.Cells.Item(i).Value = "" Then
iRange.Cells.Item(i).Range("A1").Select
ActiveSheet.Paste
Else
iRange.Cells.Item(i).Range("A1").Select
End If
Next
End Sub
Questa funzione apre una finestra di immissione che chiede all'utente di specificare un intervallo di celle. La funzione si sposta su tutte le celle dell'intervallo. Quando trova una cella che non è vuota, copia il contenuto della cella negli appunti. La funzione incolla quindi il contenuto degli appunti in ogni cella vuota successiva.
AutoFillTable
utilizza gli appunti per copiare il contenuto della cella. Pertanto, la funzione ha bisogno di selezionare ogni cella che viene manipolata, in modo che Excel sappia da quale cella copiare e in quale cella incollare. La soluzione consigliata è illustrata nella seguente funzione AutoFillTable2
:
Sub AutoFillTable2()
Dim iRange As Excel.Range
Set iRange = Application.InputBox(prompt:="Enter range", Type:=8)
Dim iCellMaster As Excel.Range
For Each iCell In iRange.Cells
If iCell.Value = "" Then
If Not iCellMaster Is Nothing Then
iCellMaster.Copy (iCell)
End If
Else
Set iCellMaster = iCell
End If
Next iCell
End Sub
AutoFillTable2
si differenzia, rispetto alla versione precedente, per due importanti aspetti:
- Cosa più importante, non richiede più di selezionare una cella. Al contrario, quando viene trovata una cella che non è vuota, questa viene memorizzata nella variabile
iCellMaster
. Successivamente, ogni qualvolta viene trovata una cella vuota, tutto il contenuto diiCellMaster
viene copiato iniCell
. - Utilizza la funzione del linguaggio Visual Basic
For Each … Next
per visitare tutte le celle dell’intervallo. Ciò garantisce già un miglioramento della leggibilità.