Cómo evitar el uso de Seleccionar en Excel VBA

May 23 2012

He escuchado mucho sobre el comprensible aborrecimiento de usarlo .Selecten Excel VBA, pero no estoy seguro de cómo evitar usarlo. Descubro que mi código sería más reutilizable si pudiera usar variables en lugar de Selectfunciones. Sin embargo, no estoy seguro de cómo referirme a cosas (como ActiveCell, etc.) si no las estoy usando Select.

Encontré este artículo sobre rangos y este ejemplo sobre los beneficios de no usar select , pero no puedo encontrar nada sobre cómo .

Respuestas

578 chrisneilsen May 23 2012 at 17:23

Algunos ejemplos de cómo evitar seleccionar

Utilice Dim'd variables

Dim rng as Range

Setla variable al rango requerido. Hay muchas formas de hacer referencia a un rango de una sola celda:

Set rng = Range("A1")
Set rng = Cells(1, 1)
Set rng = Range("NamedRange")

O un rango de varias celdas:

Set rng = Range("A1:B10")
Set rng = Range("A1", "B10")
Set rng = Range(Cells(1, 1), Cells(10, 2))
Set rng = Range("AnotherNamedRange")
Set rng = Range("A1").Resize(10, 2)

Usted puede utilizar el acceso directo al Evaluatemétodo, pero esto es menos eficiente y por lo general se debe evitar en el código de producción.

Set rng = [A1]
Set rng = [A1:B10]

Todos los ejemplos anteriores se refieren a celdas en la hoja activa . A menos que desee trabajar específicamente solo con la hoja activa, es mejor atenuar también una Worksheetvariable:

Dim ws As Worksheet
Set ws = Worksheets("Sheet1")
Set rng = ws.Cells(1, 1)
With ws
    Set rng = .Range(.Cells(1, 1), .Cells(2, 10))
End With

Si no desea trabajar con el ActiveSheet, para mayor claridad lo mejor es ser explícita. Pero tenga cuidado, ya que algunos Worksheetmétodos cambian la hoja activa.

Set rng = ActiveSheet.Range("A1")

Nuevamente, esto se refiere al libro de trabajo activo . A menos que desee trabajar específicamente solo con ActiveWorkbooko ThisWorkbook, es mejor atenuar también una Workbookvariable.

Dim wb As Workbook
Set wb = Application.Workbooks("Book1")
Set rng = wb.Worksheets("Sheet1").Range("A1")

Si no desea trabajar con el ActiveWorkbook, para mayor claridad lo mejor es ser explícita. Pero cuidado, ya que muchos WorkBookmétodos cambian el libro activo.

Set rng = ActiveWorkbook.Worksheets("Sheet1").Range("A1")

También puede utilizar el ThisWorkbookobjeto para consultar el libro que contiene el código en ejecución.

Set rng = ThisWorkbook.Worksheets("Sheet1").Range("A1")

Un fragmento de código común (malo) es abrir un libro, obtener algunos datos y volver a cerrar

Esto es malo:

Sub foo()
    Dim v as Variant
    Workbooks("Book1.xlsx").Sheets(1).Range("A1").Clear
    Workbooks.Open("C:\Path\To\SomeClosedBook.xlsx")
    v = ActiveWorkbook.Sheets(1).Range("A1").Value
    Workbooks("SomeAlreadyOpenBook.xlsx").Activate
    ActiveWorkbook.Sheets("SomeSheet").Range("A1").Value = v
    Workbooks(2).Activate
    ActiveWorkbook.Close()
End Sub

Y sería mejor como:

Sub foo()
    Dim v as Variant
    Dim wb1 as Workbook
    Dim  wb2 as Workbook
    Set wb1 = Workbooks("SomeAlreadyOpenBook.xlsx")
    Set wb2 = Workbooks.Open("C:\Path\To\SomeClosedBook.xlsx")
    v = wb2.Sheets("SomeSheet").Range("A1").Value
    wb1.Sheets("SomeOtherSheet").Range("A1").Value = v
    wb2.Close()
End Sub

Pase rangos a sus Subs y Functions como variables de rango:

Sub ClearRange(r as Range)
    r.ClearContents
    '....
End Sub

Sub MyMacro()
    Dim rng as Range
    Set rng = ThisWorkbook.Worksheets("SomeSheet").Range("A1:B10")
    ClearRange rng
End Sub

También debe aplicar métodos (como Findy Copy) a las variables:

Dim rng1 As Range
Dim rng2 As Range
Set rng1 = ThisWorkbook.Worksheets("SomeSheet").Range("A1:A10")
Set rng2 = ThisWorkbook.Worksheets("SomeSheet").Range("B1:B10")
rng1.Copy rng2

Si está recorriendo un rango de celdas, a menudo es mejor (más rápido) copiar primero los valores del rango en una matriz variante y recorrerlo:

Dim dat As Variant
Dim rng As Range
Dim i As Long

Set rng = ThisWorkbook.Worksheets("SomeSheet").Range("A1:A10000")
dat = rng.Value  ' dat is now array (1 to 10000, 1 to 1)
for i = LBound(dat, 1) to UBound(dat, 1)
    dat(i,1) = dat(i, 1) * 10 ' Or whatever operation you need to perform
next
rng.Value = dat ' put new values back on sheet

Esta es una pequeña muestra de lo que es posible.

217 SiddharthRout May 23 2012 at 17:33

Dos razones principales por las que .Select, .Activate, Selection, Activecell, Activesheet, Activeworkbook, etc deben ser evitados

  1. Ralentiza tu código.
  2. Suele ser la principal causa de errores en tiempo de ejecución.

¿Cómo lo evitamos?

1) Trabajar directamente con los objetos relevantes

Considere este código

Sheets("Sheet1").Activate
Range("A1").Select
Selection.Value = "Blah"
Selection.NumberFormat = "@"

Este código también se puede escribir como

With Sheets("Sheet1").Range("A1")
    .Value = "Blah"
    .NumberFormat = "@"
End With

2) Si es necesario, declare sus variables. El mismo código anterior se puede escribir como

Dim ws as worksheet

Set ws = Sheets("Sheet1")

With ws.Range("A1")
    .Value = "Blah"
    .NumberFormat = "@"
End With
89 RicksupportsMonica May 28 2014 at 21:04

Un pequeño punto de énfasis que agregaré a todas las excelentes respuestas dadas anteriormente:

Probablemente, lo más importante que puede hacer para evitar usar Select es, en la medida de lo posible, usar rangos con nombre (combinados con nombres de variables significativos) en su código VBA . Este punto se mencionó anteriormente, pero se pasó por alto un poco; sin embargo, merece una atención especial.

Aquí hay un par de razones adicionales para hacer un uso liberal de rangos con nombre, aunque estoy seguro de que podría pensar en más.

Los rangos con nombre hacen que su código sea más fácil de leer y comprender.

Ejemplo:

Dim Months As Range
Dim MonthlySales As Range

Set Months = Range("Months")
' E.g, "Months" might be a named range referring to A1:A12

Set MonthlySales = Range("MonthlySales")
' E.g, "Monthly Sales" might be a named range referring to B1:B12

Dim Month As Range
For Each Month in Months
    Debug.Print MonthlySales(Month.Row)
Next Month

Es bastante obvio lo que contienen los rangos con nombre Monthsy MonthlySales, y lo que hace el procedimiento.

¿Porque es esto importante? En parte porque es más fácil para otras personas entenderlo, pero incluso si usted es la única persona que verá o usará su código, debe usar rangos con nombre y buenos nombres de variables porque olvidará lo que pretendía hacer con él. un año después, y perderá 30 minutos simplemente averiguando qué está haciendo su código.

Los rangos con nombre garantizan que sus macros no se rompan cuando (¡no si!) Cambia la configuración de la hoja de cálculo.

Considere, si el ejemplo anterior se hubiera escrito así:

Dim rng1 As Range
Dim rng2 As Range

Set rng1 = Range("A1:A12")
Set rng2 = Range("B1:B12")

Dim rng3 As Range
For Each rng3 in rng1
    Debug.Print rng2(rng3.Row)
Next rng3

Este código funcionará bien al principio, es decir, hasta que usted o un futuro usuario decida "¡vaya, creo que voy a agregar una nueva columna con el año en Columna A!", O poner una columna de gastos entre los meses y columnas de ventas, o agregue un encabezado a cada columna. Ahora, tu código está roto. Y debido a que usó nombres de variables terribles, le llevará mucho más tiempo averiguar cómo solucionarlo de lo que debería tomar.

Si hubiera usado rangos con nombre para empezar, las columnas Monthsy Salespodrían moverse todo lo que quiera, y su código continuaría funcionando bien.

48 MattB Feb 28 2014 at 04:09

Voy a dar la respuesta corta ya que todos los demás dieron la larga.

Obtendrá .select y .activate cada vez que grabe macros y las reutilice. Cuando selecciona una celda u hoja, simplemente la activa. A partir de ese momento, siempre que use referencias no calificadas, como Range.Valuesi solo usaran la celda y la hoja activas. Esto también puede ser problemático si no observa dónde se coloca su código o si un usuario hace clic en el libro de trabajo.

Por lo tanto, puede eliminar estos problemas haciendo referencia directamente a sus celdas. Que va:

'create and set a range
Dim Rng As Excel.Range
Set Rng = Workbooks("Book1").Worksheets("Sheet1").Range("A1")
'OR
Set Rng = Workbooks(1).Worksheets(1).Cells(1, 1)

O podrías

'Just deal with the cell directly rather than creating a range
'I want to put the string "Hello" in Range A1 of sheet 1
Workbooks("Book1").Worksheets("Sheet1").Range("A1").value = "Hello"
'OR
Workbooks(1).Worksheets(1).Cells(1, 1).value = "Hello"

Hay varias combinaciones de estos métodos, pero esa sería la idea general expresada lo más pronto posible para personas impacientes como yo.

34 Noname Feb 24 2015 at 22:41

"... y estoy descubriendo que mi código sería más reutilizable si pudiera usar variables en lugar de funciones de selección".

Si bien no puedo pensar en más que en un puñado aislado de situaciones en las .Selectque sería una mejor opción que la referencia directa de celda, me levantaría en defensa Selectiony señalaría que no debe descartarse por las mismas razones que .Selectdeben evitarse.

Hay ocasiones en las que tener subrutinas macro breves que ahorran tiempo asignadas a combinaciones de teclas de acceso rápido disponibles con solo tocar un par de teclas ahorra mucho tiempo. Ser capaz de seleccionar un grupo de celdas para promulgar el código operativo funciona de maravilla cuando se trata de datos embolsados ​​que no se ajustan a un formato de datos de toda la hoja de trabajo. De la misma manera que puede seleccionar un grupo de celdas y aplicar un cambio de formato, seleccionar un grupo de celdas para ejecutar un código de macro especial puede ser un gran ahorro de tiempo.

Ejemplos de submarco basado en selección:

Public Sub Run_on_Selected()
    Dim rng As Range, rSEL As Range
    Set rSEL = Selection    'store the current selection in case it changes
    For Each rng In rSEL
        Debug.Print rng.Address(0, 0)
        'cell-by-cell operational code here
    Next rng
    Set rSEL = Nothing
End Sub

Public Sub Run_on_Selected_Visible()
    'this is better for selected ranges on filtered data or containing hidden rows/columns
    Dim rng As Range, rSEL As Range
    Set rSEL = Selection    'store the current selection in case it changes
    For Each rng In rSEL.SpecialCells(xlCellTypeVisible)
        Debug.Print rng.Address(0, 0)
        'cell-by-cell operational code here
    Next rng
    Set rSEL = Nothing
End Sub

Public Sub Run_on_Discontiguous_Area()
    'this is better for selected ranges of discontiguous areas
    Dim ara As Range, rng As Range, rSEL As Range
    Set rSEL = Selection    'store the current selection in case it changes
    For Each ara In rSEL.Areas
        Debug.Print ara.Address(0, 0)
        'cell group operational code here
        For Each rng In ara.Areas
            Debug.Print rng.Address(0, 0)
            'cell-by-cell operational code here
        Next rng
    Next ara
    Set rSEL = Nothing
End Sub

El código real a procesar podría ser cualquier cosa, desde una sola línea hasta varios módulos. He utilizado este método para iniciar rutinas de larga duración en una selección irregular de celdas que contienen los nombres de archivo de libros de trabajo externos.

En resumen, no descarte Selectionpor su estrecha asociación con .Selecty ActiveCell. Como propiedad de la hoja de trabajo, tiene muchos otros propósitos.

(Sí, sé que esta pregunta se trataba .Select, no, Selectionpero quería eliminar cualquier concepto erróneo que pudieran inferir los codificadores novatos de VBA).

30 Vityata Mar 08 2016 at 17:04

Evitar Selecty Activatees el movimiento que te hace un poco mejor desarrollador de VBA. En general, Selecty Activatese utilizan cuando se registra una macro, por lo que la Parenthoja de trabajo o el rango siempre se considera el activo.

Así es como puede evitar Selecty Activateen los siguientes casos:


Agregar una nueva hoja de trabajo y copiar una celda en ella:

Desde (código generado con la grabadora de macros):

Sub Makro2()
    Range("B2").Select
    Sheets.Add After:=ActiveSheet
    Sheets("Tabelle1").Select
    Sheets("Tabelle1").Name = "NewName"
    ActiveCell.FormulaR1C1 = "12"
    Range("B2").Select
    Selection.Copy
    Range("B3").Select
    ActiveSheet.Paste
    Application.CutCopyMode = False
End Sub

A:

Sub TestMe()
    Dim ws As Worksheet
    Set ws = Worksheets.Add
    With ws
        .Name = "NewName"
        .Range("B2") = 12
        .Range("B2").Copy Destination:=.Range("B3")
    End With
End Sub

Cuando desee copiar el rango entre hojas de trabajo:

Desde:

Sheets("Source").Select
Columns("A:D").Select
Selection.Copy
Sheets("Target").Select
Columns("A:D").Select
ActiveSheet.Paste

A:

Worksheets("Source").Columns("A:D").Copy Destination:=Worksheets("Target").Range("a1")

Usando rangos con nombres elegantes

Puede acceder a ellos con [], que es realmente hermoso, en comparación con la otra forma. Compruebe usted mismo:

Dim Months As Range
Dim MonthlySales As Range

Set Months = Range("Months")    
Set MonthlySales = Range("MonthlySales")

Set Months =[Months]
Set MonthlySales = [MonthlySales]

El ejemplo de arriba se vería así:

Worksheets("Source").Columns("A:D").Copy Destination:=Worksheets("Target").[A1]

No copiando valores, sino tomándolos

Por lo general, si está dispuesto a hacerlo select, lo más probable es que esté copiando algo. Si solo está interesado en los valores, esta es una buena opción para evitar seleccionar:

Range("B1:B6").Value = Range("A1:A6").Value


Intente siempre hacer referencia a la hoja de trabajo también

Este es probablemente el error más común en vba . Siempre que copia rangos, a veces no se hace referencia a la hoja de trabajo y, por lo tanto, VBA considera la hoja incorrecta como ActiveWorksheet.

'This will work only if the 2. Worksheet is selected!
Public Sub TestMe()
    Dim rng As Range
    Set rng = Worksheets(2).Range(Cells(1, 1), Cells(2, 2)).Copy
End Sub

'This works always!
Public Sub TestMe2()
    Dim rng As Range
    With Worksheets(2)
        .Range(.Cells(1, 1), .Cells(2, 2)).Copy
    End With
End Sub

¿Realmente nunca puedo usar .Selectni .Activatepara nada?

  • Un buen ejemplo de cuándo podría estar justificado el uso .Activatey .Selectes cuándo desea asegurarse de que se seleccione una hoja de trabajo específica por razones visuales. Por ejemplo, que su Excel siempre se abriría con la hoja de trabajo de portada seleccionada primero, sin tener en cuenta cuál era la hoja activa cuando se cerró el archivo.

Por lo tanto, algo como el siguiente código está absolutamente bien:

Private Sub Workbook_Open()
    Worksheets("Cover").Activate
End Sub
  • Otro buen ejemplo es cuando necesita exportar todas las hojas en un archivo PDF, como se menciona en este caso: ¿Cómo evitar declaraciones de selección / activas en VBA en este ejemplo?

  • Cuando un comando sólo funciona con ActiveWindowigual ActiveWindow.Zoom o ActiveWindow.FreezePanes

30 FrancescoBaruchelli May 23 2012 at 13:11

Tenga en cuenta que a continuación estoy comparando el enfoque de selección (el que el OP quiere evitar) con el enfoque de rango (y esta es la respuesta a la pregunta). Así que no dejes de leer cuando veas la primera selección.

Realmente depende de lo que intente hacer. De todos modos, un simple ejemplo podría ser útil. Supongamos que desea establecer el valor de la celda activa en "foo". Usando ActiveCell escribirías algo como esto:

Sub Macro1()
    ActiveCell.Value = "foo"
End Sub

Si desea usarlo para una celda que no es la activa, por ejemplo para "B2", debe seleccionarlo primero, así:

Sub Macro2()
    Range("B2").Select
    Macro1
End Sub

Usando Rangos, puede escribir una macro más genérica que se puede usar para establecer el valor de cualquier celda que desee en lo que desee:

Sub SetValue(cellAddress As String, aVal As Variant)
    Range(cellAddress).Value = aVal
End Sub

Entonces puedes reescribir Macro2 como:

Sub Macro2()
    SetCellValue "B2", "foo"
End Sub

Y Macro1 como:

Sub Macro1()
    SetValue ActiveCell.Address, "foo"
End Sub
18 user1644564 Aug 25 2014 at 16:54

Indique siempre el libro de trabajo, la hoja de trabajo y la celda / rango.

Por ejemplo:

Thisworkbook.Worksheets("fred").cells(1,1)
Workbooks("bob").Worksheets("fred").cells(1,1)

Debido a que los usuarios finales siempre solo harán clic en los botones y tan pronto como el foco se mueva fuera del libro de trabajo, el código quiere trabajar, las cosas salen completamente mal.

Y nunca use el índice de un libro de trabajo.

Workbooks(1).Worksheets("fred").cells(1,1)

No sabe qué otros libros de trabajo estarán abiertos cuando el usuario ejecute su código.

11 LFB Jun 16 2018 at 21:18

Estos métodos están bastante estigmatizados, por lo que tomar la iniciativa de Vityata y Jeeped con el fin de trazar una línea en la arena:

Call .Activate, .Select, Selection, ActiveSomethingmétodos / propiedades

Básicamente porque se llaman principalmente para manejar la entrada del usuario a través de la interfaz de usuario de la aplicación. Dado que son los métodos a los que se llama cuando el usuario maneja objetos a través de la interfaz de usuario, son los que registra el grabador de macros, y es por eso que llamarlos es frágil o redundante en la mayoría de las situaciones: no es necesario seleccionar un objeto para realizar una acción Selectioninmediatamente después.

Sin embargo, esta definición resuelve situaciones en las que se solicitan:

Cuando llamar .Activate, .Select, .Selection, .ActiveSomethingmétodos / propiedades

Básicamente cuando esperas que el usuario final juegue un papel en la ejecución.

Si está desarrollando y espera que el usuario elija las instancias de objeto para que las maneje su código, entonces .Selectiono .ActiveObjectson apropiadas.

Por otro lado, .Selecty .Activateson útiles cuando puede inferir la siguiente acción del usuario y desea que su código guíe al usuario, posiblemente ahorrándole algo de tiempo y clics del mouse. Por ejemplo, si su código acaba de crear una nueva instancia de un gráfico o la actualizó, el usuario podría querer revisarlo y usted podría llamarlo .Activateo su hoja para ahorrarle tiempo al buscarlo; o si sabe que el usuario necesitará actualizar algunos valores de rango, puede seleccionar ese rango mediante programación.

6 Eleshar Nov 20 2016 at 22:02

En mi humilde opinión, el uso de .selectproviene de personas que, como yo, comenzaron a aprender VBA por necesidad a través de la grabación de macros y luego modificaron el código sin darse cuenta de que .selecty, posteriormente, selectionson solo intermediarios innecesarios.

.select se puede evitar, como muchos ya se han publicado, trabajando directamente con los objetos ya existentes, lo que permite varias referencias indirectas como calcular i y j de una manera compleja y luego editar la celda (i, j), etc.

De lo contrario, no hay nada implícitamente incorrecto en .selectsí mismo y puede encontrar usos para esto fácilmente, por ejemplo, tengo una hoja de cálculo que completo con la fecha, activo la macro que hace algo de magia con ella y la exporta en un formato aceptable en una hoja separada, que , sin embargo, requiere algunas entradas manuales finales (impredecibles) en una celda adyacente. Así que aquí llega el momento en .selectque eso me ahorra ese movimiento adicional del mouse y el clic.

4 FinPro.Online Sep 08 2016 at 13:36

Para evitar usar el .Selectmétodo, puede establecer una variable igual a la propiedad que desee.

► Por ejemplo, si desea el valor Cell A1, puede establecer una variable igual a la propiedad del valor de esa celda.

  • Ejemplo valOne = Range("A1").Value

► Por ejemplo, si desea el nombre en clave de la you could set a variable equal to thepropiedad 'Sheet3 Codename` de esa hoja de trabajo.

  • Ejemplo valTwo = Sheets("Sheet3").Codename
3 PGSystemTester Aug 17 2018 at 03:07

Noté que ninguna de estas respuestas menciona la propiedad .Offset . Esto también se puede usar para evitar el uso de la Selectacción al manipular ciertas celdas, particularmente en referencia a una celda seleccionada (como el OP menciona con ActiveCell).

Aqui hay un par de ejemplos.

También asumiré que "ActiveCell" es J4 .

ActiveCell.Offset(2, 0).Value = 12

  • Esto cambiará la celda J6a un valor de 12
  • Un menos -2 habría hecho referencia a J2

ActiveCell.Offset(0,1).Copy ActiveCell.Offset(,2)

  • Esto copia la celda en la k4que L4.
  • Tenga en cuenta que "0" no es necesario en el parámetro de compensación si no es necesario (, 2)
  • Similar al ejemplo anterior, un menos 1 sería i4

ActiveCell.Offset(, -1).EntireColumn.ClearContents

  • Esto borrará los valores en todas las celdas de la columna k.

Esto no quiere decir que sean "mejores" que las opciones anteriores, sino simplemente enumerar alternativas.

1 Dominique Oct 30 2020 at 22:55

¿Cómo evitar copiar y pegar?

Seamos realistas: este aparece mucho al grabar macros:

Range("X1").Select
Selection.Copy
Range("Y9).Select
Selection.Paste

Si bien lo único que quiere la persona es:

Range("Y9").Value = Range("X1").Value

Por lo tanto, en lugar de usar copiar y pegar en macros VBA, recomendaría el siguiente enfoque simple:

Destination_Range.Value = Source_Range.Value
barneyos Oct 30 2019 at 16:45

Trabajando con la función .Parent , este ejemplo muestra cómo configurar solo una referencia myRng permite el acceso dinámico a todo el entorno sin ningún .Select, .Activate, .Activecell, .ActiveWorkbook, .ActiveSheet, etc. (No hay ninguna característica genérica .Child ).

Sub ShowParents()
    Dim myRng As Range
    Set myRng = ActiveCell
    Debug.Print myRng.Address                    ' An address of the selected cell
    Debug.Print myRng.Parent.name                ' The name of sheet, where MyRng is in
    Debug.Print myRng.Parent.Parent.name         ' The name of workbook, where MyRng is in
    Debug.Print myRng.Parent.Parent.Parent.name  ' The name of application, where MyRng is in

    ' You may use this feature to set reference to these objects
    Dim mySh  As Worksheet
    Dim myWbk As Workbook
    Dim myApp As Application

    Set mySh = myRng.Parent
    Set myWbk = myRng.Parent.Parent
    Set myApp = myRng.Parent.Parent.Parent
    Debug.Print mySh.name, mySh.Cells(10, 1).Value
    Debug.Print myWbk.name, myWbk.Sheets.Count
    Debug.Print myApp.name, myApp.Workbooks.Count

    ' You may use dynamically addressing
    With myRng
        .Copy

        ' Pastes in D1 on sheet 2 in the same workbook, where the copied cell is
        .Parent.Parent.Sheets(2).Range("D1").PasteSpecial xlValues

        ' Or myWbk.Sheets(2).Range("D1").PasteSpecial xlValues

        ' We may dynamically call active application too
        .Parent.Parent.Parent.CutCopyMode = False

        ' Or myApp.CutCopyMode = False
    End With
End Sub
GeoffGriswald Mar 02 2020 at 20:04

La razón principal para no usar nunca Seleccionar o Hoja activa es porque la mayoría de las personas tendrán al menos otro par de libros abiertos (a veces docenas) cuando ejecuten su macro, y si hacen clic fuera de su hoja mientras su macro se está ejecutando y hacen clic en algún otro libro que tienen abierto, luego la "Hoja activa" cambia, y el libro de trabajo de destino para un comando "Seleccionar" no calificado también cambia.

En el mejor de los casos, su macro se bloqueará, en el peor de los casos, podría terminar escribiendo valores o cambiando celdas en el libro de trabajo incorrecto sin posibilidad de "Deshacer".

Tengo una regla de oro simple que sigo: agregue variables llamadas "wb" y "ws" para un objeto de libro de trabajo y un objeto de hoja de trabajo y siempre las use para hacer referencia a mi libro de macros. Si necesito hacer referencia a más de un libro, o más de una hoja, agrego más variables.

Por ejemplo,

Dim wb as Workbook
Dim ws as Worksheet
Set wb = ThisWorkBook
Set ws = wb.sheets("Output")

El comando "Establecer wb = ThisWorkbook" es absolutamente clave. "ThisWorkbook" es un valor especial en Excel, y significa el libro desde el que se está ejecutando su código VBA . Un atajo muy útil para configurar la variable de su libro de trabajo.

Una vez que haya hecho eso en la parte superior de su Sub, usarlos no podría ser más simple, solo utilícelos donde quiera que use "Selección":

Entonces, para cambiar el valor de la celda "A1" en "Salida" a "Hola", en lugar de:

Sheets("Output").Activate
ActiveSheet.Range("A1").Select
Selection.Value = "Hello"

Ahora podemos hacer esto:

ws.Range("A1").Value = "Hello"

Lo cual no solo es mucho más confiable y tiene menos probabilidades de fallar si el usuario está trabajando con varias hojas de cálculo; también es mucho más corto, rápido y fácil de escribir.

Como beneficio adicional, si siempre nombra sus variables "wb" y "ws", puede copiar y pegar código de un libro a otro y, por lo general, funcionará con los cambios mínimos necesarios, si los hubiera.