¿Por qué mi macro de Excel se ralentiza al activar think-cell?
Un problema común que puede causar problemas de rendimiento en las macros de VBA es el uso de la función .Select
. Cada vez que se selecciona una celda en Excel, se notifica a todos los complementos de Excel (incluido think-cell) este evento de cambio de selección, lo que ralentiza la macro de forma considerable. Las macros que se crean mediante la grabadora de macros son especialmente propensas a este tipo de problema.
- Blog de Office: "Cuál es el método más rápido para analizar un rango grande en Excel?"
- MSDN: Mejora del rendimiento en Excel 2007: "Referenciación de objetos de Excel como objetos de rango directamente, sin seleccionarlos ni activarlos" (en el apartado, "Macros de VBA más rápidas").
Ejemplo: Cómo evitar el uso de la instrucción .Select
Echemos un vistazo a la siguiente macro sencilla 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
Esta función abre un cuadro de entrada que pide al usuario que especifique un rango de celdas. La función pasa por todas las celdas del rango. Si encuentra una celda que no está vacía, copia su contenido en el portapapeles. La función pega el contenido del portapapeles en cada celda vacía posterior.
AutoFillTable
utiliza el portapapeles para copiar el contenido de la celda. Por lo tanto, la función tiene que seleccionar cada celda manipulada para que Excel sepa qué celda debe copiar y en qué celda debe pegar. La solución recomendada se muestra en la siguiente función 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
difiere en dos aspectos importantes de su predecesora:
- Pero más importante aún, ya no necesita seleccionar una celda. En lugar de ello, cuando se encuentra una celda que no está vacía, dicha celda se almacena en la variable
iCellMaster
. A partir de ese instante, cada vez que se encuentra una celda vacía, todo el contenido deiCellMaster
se copia eniCell
. - Utiliza la característica de lenguaje Visual Basic
For Each … Next
para pasar por cada celda del rango. Esto ya supone una mejora de legibilidad.