excel-vba
Errores comunes
Buscar..
Referencias de calificación
Cuando se hace referencia a una worksheet
, un range
o cells
individuales, es importante calificar completamente la referencia.
Por ejemplo:
ThisWorkbook.Worksheets("Sheet1").Range(Cells(1, 2), Cells(2, 3)).Copy
No está completamente calificado: las referencias de Cells
no tienen un libro de trabajo y una hoja de cálculo asociados. Sin una referencia explícita, las celdas se refieren a ActiveSheet
por defecto. Por lo tanto, este código fallará (producirá resultados incorrectos) si una hoja de cálculo que no sea Sheet1
es el ActiveSheet
actual.
La forma más fácil de corregir esto es usar una instrucción With
siguiente manera:
With ThisWorkbook.Worksheets("Sheet1")
.Range(.Cells(1, 2), .Cells(2, 3)).Copy
End With
Alternativamente, puede usar una variable de la hoja de trabajo. (Probablemente este sea el método preferido si su código necesita hacer referencia a varias Hojas de trabajo, como copiar datos de una hoja a otra).
Dim ws1 As Worksheet
Set ws1 = ThisWorkbook.Worksheets("Sheet1")
ws1.Range(ws1.Cells(1, 2), ws1.Cells(2, 3)).Copy
Otro problema frecuente es hacer referencia a la colección de hojas de trabajo sin calificar el libro de trabajo. Por ejemplo:
Worksheets("Sheet1").Copy
La hoja de trabajo Sheet1
no está completamente calificada y carece de un libro de trabajo. Esto podría fallar si se hace referencia a varios libros en el código. En su lugar, utilice uno de los siguientes:
ThisWorkbook.Worksheets("Sheet1") '<--ThisWorkbook refers to the workbook containing
'the running VBA code
Workbooks("Book1").Worksheets("Sheet1") '<--Where Book1 is the workbook containing Sheet1
Sin embargo, evite usar lo siguiente:
ActiveWorkbook.Worksheets("Sheet1") '<--Valid, but if another workbook is activated
'the reference will be changed
De manera similar, para los objetos de range
, si no están calificados explícitamente, el range
se referirá a la hoja actualmente activa:
Range("a1")
Es lo mismo que:
ActiveSheet.Range("a1")
Eliminar filas o columnas en un bucle
Si desea eliminar filas (o columnas) en un bucle, siempre debe hacerlo desde el final del rango y retroceder en cada paso. En caso de utilizar el código:
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
Te perderás algunas filas. Por ejemplo, si el código elimina la fila 3, entonces la fila 4 se convierte en la fila 3. Sin embargo, la variable i
cambiará a 4. Entonces, en este caso, el código perderá una fila y marcará otra, que no estaba en el rango anterior.
El código correcto sería
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
y ThisWorkbook
veces se usan indistintamente por los nuevos usuarios de VBA sin entender completamente a qué se refiere cada objeto, esto puede causar un comportamiento no deseado en tiempo de ejecución. Ambos objetos pertenecen al objeto de aplicación.
El objeto ActiveWorkbook
refiere al libro de trabajo que se encuentra actualmente en la vista superior del objeto de aplicación de Excel en el momento de la ejecución. (por ejemplo, el libro de trabajo que puede ver e interactuar en el momento en que se hace referencia a este objeto)
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
El objeto ThisWorkbook
refiere al libro de trabajo al que pertenece el código en el momento en que se está ejecutando.
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
Interfaz de documento único frente a interfaces de documento múltiples
Tenga en cuenta que Microsoft Excel 2013 (y superior) utiliza la Interfaz de documento único (SDI) y que Excel 2010 (y más abajo) utiliza Interfaces de documentos múltiples (MDI).
Esto implica que para Excel 2013 (SDI), cada libro en una sola instancia de Excel contiene su propia interfaz de usuario de cinta:
A la inversa, para Excel 2010, cada libro en una sola instancia de Excel utilizó una IU de cinta común (MDI):
Esto plantea algunos problemas importantes si desea migrar un código VBA (2010 <-> 2013) que interactúa con la cinta de opciones.
Se debe crear un procedimiento para actualizar los controles de la IU de la cinta en el mismo estado en todos los libros de trabajo para Excel 2013 y superior.
Tenga en cuenta que :
- Todos los métodos, eventos y propiedades de la ventana de nivel de aplicación de Excel no se verán afectados. (
Application.ActiveWindow
,Application.Windows
...) - En Excel 2013 y superior (SDI), todos los métodos, eventos y propiedades de la ventana de nivel de libro de trabajo ahora operan en la ventana de nivel superior. Es posible recuperar el identificador de esta ventana de nivel superior con
Application.Hwnd
Para obtener más detalles, consulte la fuente de este ejemplo: MSDN .
Esto también causa algunos problemas con las formas de usuario sin modelo. Vea aquí para una solución.