Como evitar o uso de Select no Excel VBA

May 23 2012

Já ouvi muito sobre a repulsa compreensível de usar o .SelectExcel VBA, mas não tenho certeza de como evitá-lo. Estou descobrindo que meu código seria mais reutilizável se eu pudesse usar variáveis ​​em vez de Selectfunções. No entanto, não tenho certeza de como me referir a coisas (como o ActiveCell, etc.) se não estiver usando Select.

Eu encontrei este artigo sobre intervalos e este exemplo sobre os benefícios de não usar o select , mas não consigo encontrar nada sobre como .

Respostas

578 chrisneilsen May 23 2012 at 17:23

Alguns exemplos de como evitar selecionar

Use Dim'd variáveis

Dim rng as Range

Seta variável para o intervalo necessário. Existem muitas maneiras de se referir a um intervalo de uma única célula:

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

Ou um intervalo de várias células:

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)

Você pode usar o atalho para o Evaluatemétodo, mas isso é menos eficiente e geralmente deve ser evitado no código de produção.

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

Todos os exemplos acima referem-se a células na planilha ativa . A menos que você queira trabalhar apenas com a planilha ativa, é melhor Dim uma Worksheetvariável também:

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

Se você não quer trabalhar com o ActiveSheet, para maior clareza, é melhor ser explícito. Mas tome cuidado, pois alguns Worksheetmétodos alteram a planilha ativa.

Set rng = ActiveSheet.Range("A1")

Novamente, isso se refere à pasta de trabalho ativa . A menos que você queira trabalhar especificamente apenas com ActiveWorkbookou ThisWorkbook, é melhor Dim uma Workbookvariável também.

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

Se você não quer trabalhar com o ActiveWorkbook, para maior clareza, é melhor ser explícito. Mas tome cuidado, pois muitos WorkBookmétodos mudam o livro ativo.

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

Você também pode usar o ThisWorkbookobjeto para se referir ao livro que contém o código em execução.

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

Um código comum (ruim) é abrir um livro, obter alguns dados e fechar novamente

Isto é mau:

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

E seria melhor assim:

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

Passe intervalos para seus Subs e Functions como variáveis ​​de intervalo:

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

Você também deve aplicar métodos (como Finde Copy) às variáveis:

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

Se você estiver fazendo um loop em um intervalo de células, geralmente é melhor (mais rápido) copiar os valores do intervalo para uma matriz variante primeiro e fazer um loop sobre isso:

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 é uma pequena amostra do que é possível.

217 SiddharthRout May 23 2012 at 17:33

Duas razões principais .Select, .Activate, Selection, Activecell, Activesheet, Activeworkbook, etc, devem ser evitados

  1. Isso retarda o seu código.
  2. Geralmente é a principal causa de erros de tempo de execução.

Como podemos evitar isso?

1) Trabalhar diretamente com os objetos relevantes

Considere este código

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

Este código também pode ser escrito como

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

2) Se necessário, declare suas variáveis. O mesmo código acima pode ser escrito 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

Acrescentarei um pequeno ponto de ênfase a todas as excelentes respostas dadas anteriormente:

Provavelmente, a maior coisa que você pode fazer para evitar o uso de Select é , tanto quanto possível, usar intervalos nomeados (combinados com nomes de variáveis ​​significativos) em seu código VBA . Este ponto foi mencionado acima, mas foi um pouco encoberto; no entanto, ele merece atenção especial.

Aqui estão algumas razões adicionais para fazer uso liberal de intervalos nomeados, embora eu tenha certeza de que poderia pensar em mais.

Intervalos nomeados tornam seu código mais fácil de ler e entender.

Exemplo:

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

É bastante óbvio o que os intervalos nomeados Monthse MonthlySalescontêm, e o que o procedimento está fazendo.

Por que isso é importante? Parcialmente porque é mais fácil para outras pessoas entenderem, mas mesmo se você for a única pessoa que verá ou usará seu código, você ainda deve usar intervalos nomeados e bons nomes de variáveis ​​porque você esquecerá o que pretendia fazer com ele um ano depois, você perderá 30 minutos apenas tentando descobrir o que seu código está fazendo.

Intervalos nomeados garantem que suas macros não quebrem quando (não se!) A configuração da planilha mudar.

Considere, se o exemplo acima tivesse sido escrito assim:

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á bem no início - isto é até que você ou um futuro usuário decida "caramba, acho que vou adicionar uma nova coluna com o ano na coluna A!", Ou colocar uma coluna de despesas entre os meses e colunas de vendas ou adicione um cabeçalho a cada coluna. Agora, seu código está quebrado. E como você usou nomes de variáveis ​​terríveis, levará muito mais tempo para descobrir como corrigi-lo do que deveria.

Se você tivesse usado intervalos nomeados para começar, as colunas Monthse Salespoderiam ser movidas o quanto quiser e seu código continuaria funcionando perfeitamente.

48 MattB Feb 28 2014 at 04:09

Eu vou dar uma resposta curta, já que todos os outros deram uma longa.

Você obterá .select e .activate sempre que gravar macros e reutilizá-las. Quando você seleciona uma célula ou planilha, ela apenas a torna ativa. Desse ponto em diante, sempre que você usar referências não qualificadas, Range.Valueelas usam apenas a célula e a planilha ativas. Isso também pode ser problemático se você não observar onde seu código é colocado ou se um usuário clicar na pasta de trabalho.

Portanto, você pode eliminar esses problemas referenciando diretamente suas células. Qual vai:

'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)

Ou você poderia

'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"

Existem várias combinações desses métodos, mas essa seria a ideia geral expressa o mais brevemente possível para pessoas impacientes como eu.

34 Noname Feb 24 2015 at 22:41

"... e estou descobrindo que meu código seria mais reutilizável se eu pudesse usar variáveis ​​em vez de funções Select."

Embora eu não consiga pensar em mais do que um punhado de situações isoladas em .Selectque seria uma escolha melhor do que a referência direta de células, eu levantaria em defesa Selectione apontaria que ela não deve ser descartada pelas mesmas razões que .Selectdevem ser evitadas.

Há momentos em que ter sub-rotinas de macro curtas e que economizam tempo atribuídas a combinações de teclas de atalho disponíveis com o toque de algumas teclas economiza muito tempo. Ser capaz de selecionar um grupo de células para decretar o código operacional em faz maravilhas ao lidar com dados embolsados ​​que não estão em conformidade com um formato de dados de planilha. Da mesma forma que você pode selecionar um grupo de células e aplicar uma alteração de formato, selecionar um grupo de células para executar o código de macro especial pode economizar muito tempo.

Exemplos de subestrutura baseada em seleção:

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

O código real a ser processado pode ser qualquer coisa, desde uma única linha até vários módulos. Usei esse método para iniciar rotinas de longa execução em uma seleção irregular de células contendo nomes de arquivos de pastas de trabalho externas.

Em suma, não descarte Selectiondevido à sua estreita associação com .Selecte ActiveCell. Como propriedade da planilha, ela tem muitos outros propósitos.

(Sim, eu sei que esta pergunta era sobre .Select, Selectionmas eu queria remover quaisquer equívocos que os programadores VBA novatos possam inferir.)

30 Vityata Mar 08 2016 at 17:04

Evitar Selecte Activateé o movimento que o torna um desenvolvedor VBA um pouco melhor. Em geral, Selecte Activatesão usados ​​quando uma macro é gravada, portanto a Parentplanilha ou intervalo é sempre considerado o ativo.

É assim que você pode evitar Selecte Activatenos seguintes casos:


Adicionando uma nova planilha e copiando uma célula nela:

De (código gerado com gravador de macro):

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

Para:

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

Quando você deseja copiar o intervalo entre as planilhas:

A partir de:

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

Para:

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

Usando intervalos nomeados sofisticados

Você pode acessá-los com [], o que é muito bonito, em comparação com o outro modo. Verifique você mesmo:

Dim Months As Range
Dim MonthlySales As Range

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

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

O exemplo acima ficaria assim:

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

Não copiando valores, mas tomando-os

Normalmente, se você estiver disposto select, provavelmente está copiando algo. Se você está interessado apenas nos valores, esta é uma boa opção para evitar selecionar:

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


Tente sempre consultar a planilha também

Este é provavelmente o erro mais comum no vba . Sempre que você copia intervalos, às vezes a planilha não é referenciada e, portanto, o VBA considera a planilha errada a 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

Eu realmente nunca posso usar .Selectou .Activatepara nada?

  • Um bom exemplo de quando você pode ter justificativa para usar .Activatee .Selecté quando você quer ter certeza de que uma planilha específica foi selecionada por motivos visuais. Por exemplo, que seu Excel sempre abriria com a planilha de capa selecionada primeiro, desconsiderando qual era a ActiveSheet quando o arquivo foi fechado.

Assim, algo como o código abaixo está absolutamente OK:

Private Sub Workbook_Open()
    Worksheets("Cover").Activate
End Sub
  • Outro bom exemplo é quando você precisa exportar todas as planilhas em um arquivo PDF, conforme mencionado neste caso - Como evitar instruções select / active no VBA neste exemplo?

  • Quando um comando só funciona com ActiveWindowcomo ActiveWindow.Zoom ou ActiveWindow.FreezePanes

30 FrancescoBaruchelli May 23 2012 at 13:11

Observe que a seguir estou comparando a abordagem Select (aquela que o OP deseja evitar), com a abordagem Range (e esta é a resposta à pergunta). Portanto, não pare de ler quando vir o primeiro Select.

Realmente depende do que você está tentando fazer. De qualquer forma, um exemplo simples pode ser útil. Vamos supor que você queira definir o valor da célula ativa como "foo". Usando ActiveCell, você escreveria algo assim:

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

Se você deseja usá-lo para uma célula que não é a ativa, por exemplo para "B2", você deve selecioná-lo primeiro, assim:

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

Usando Ranges, você pode escrever uma macro mais genérica que pode ser usada para definir o valor de qualquer célula que você quiser:

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

Então você pode reescrever Macro2 como:

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

E Macro1 como:

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

Sempre indique a pasta de trabalho, a planilha e a célula / intervalo.

Por exemplo:

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

Como os usuários finais sempre clicarão em botões e, assim que o foco sair da pasta de trabalho com a qual o código deseja trabalhar, as coisas darão errado.

E nunca use o índice de uma pasta de trabalho.

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

Você não sabe quais outras pastas de trabalho serão abertas quando o usuário executar seu código.

11 LFB Jun 16 2018 at 21:18

Esses métodos são bastante estigmatizados, então assumindo a liderança de Vityata e Jeeped para traçar uma linha na areia:

Chamada .Activate, .Select, Selection, ActiveSomethingmétodos / propriedades

Basicamente porque eles são chamados principalmente para manipular a entrada do usuário por meio da interface do usuário do aplicativo. Uma vez que são os métodos chamados quando o usuário manipula objetos por meio da IU, eles são os gravados pelo gravador de macro e é por isso que chamá-los é frágil ou redundante para a maioria das situações: você não precisa selecionar um objeto de modo a realizar uma ação com o Selectiondireito em seguida.

No entanto, esta definição estabelece as situações em que são necessários:

Quando chamar .Activate, .Select, .Selection, .ActiveSomethingmétodos / propriedades

Basicamente, quando você espera que o usuário final desempenhe um papel na execução.

Se você está desenvolvendo e espera que o usuário escolha as instâncias de objeto para seu código manipular, então .Selectionou .ActiveObjectsão apropriadas.

Por outro lado, .Selecte .Activatesão úteis quando você pode inferir a próxima ação do usuário e deseja que seu código oriente o usuário, possivelmente economizando algum tempo e cliques do mouse. Por exemplo, se o seu código acabou de criar uma nova instância de um gráfico ou atualizou um, o usuário pode querer fazer o check-out e você pode chamá .Activate-lo ou sua planilha para economizar o tempo de pesquisa do usuário; ou se você souber que o usuário precisará atualizar alguns valores de intervalo, poderá selecionar esse intervalo de maneira programática.

6 Eleshar Nov 20 2016 at 22:02

O uso de IMHO .selectvem de pessoas que, como eu, começaram a aprender VBA por necessidade, gravando macros e, em seguida, modificando o código sem perceber que .selecte subsequentemente selectioné apenas um intermediário desnecessário.

.select pode ser evitado, como muitos já postados, trabalhando diretamente com os objetos já existentes, o que permite várias referências indiretas como calcular i e j de uma forma complexa e depois editar a célula (i, j), etc.

Caso contrário, não há nada implicitamente errado com .selectele e você pode encontrar usos para isso facilmente, por exemplo, eu tenho uma planilha que eu preencho com a data, ativo a macro que faz alguma mágica com ela e a exporta em um formato aceitável em uma planilha separada, que , entretanto, requer algumas entradas manuais finais (imprevisíveis) em uma célula adjacente. Então, chega o momento em .selectque me poupa aquele movimento adicional do mouse e clique.

4 FinPro.Online Sep 08 2016 at 13:36

Para evitar o uso do .Selectmétodo, você pode definir uma variável igual à propriedade que deseja.

► Por exemplo, se você deseja o valor em, Cell A1pode definir uma variável igual à propriedade de valor dessa célula.

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

► Por exemplo, se você quiser o codinome da you could set a variable equal to thepropriedade 'Sheet3 Codename` dessa planilha.

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

Percebi que nenhuma dessas respostas menciona a propriedade .Offset . Isso também pode ser usado para evitar o uso da Selectação ao manipular certas células, particularmente em referência a uma célula selecionada (como o OP menciona com ActiveCell).

Aqui estão alguns exemplos.

Também assumirei que o "ActiveCell" é J4 .

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

  • Isso mudará a célula J6para um valor de 12
  • Um menos -2 teria referenciado J2

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

  • Isso copiará a célula k4para L4.
  • Observe que "0" não é necessário no parâmetro de deslocamento se não for necessário (, 2)
  • Semelhante ao exemplo anterior, um menos 1 seria i4

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

  • Isso limpará os valores em todas as células da coluna k.

Isso não quer dizer que sejam "melhores" do que as opções acima, mas apenas listar alternativas.

1 Dominique Oct 30 2020 at 22:55

Como evitar copiar e colar?

Vamos enfrentá-lo: este aparece muito ao gravar macros:

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

Embora a única coisa que a pessoa queira é:

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

Portanto, em vez de usar copiar e colar em macros VBA, aconselho a seguinte abordagem simples:

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

Trabalhando com o recurso .Parent , este exemplo mostra como definir apenas uma referência myRng permite o acesso dinâmico a todo o ambiente sem qualquer .Select, .Activate, .Activecell, .ActiveWorkbook, .ActiveSheet e assim por diante. (Não há nenhum recurso .Child genérico .)

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

A principal razão para nunca usar Select ou Activesheet é porque a maioria das pessoas terá pelo menos outro par de pastas de trabalho abertas (às vezes dezenas) quando executam sua macro, e se clicam fora de sua planilha enquanto sua macro está em execução e clicam em algum outro o livro que eles abriram, então a "Folha de atividades" muda e a pasta de trabalho de destino para um comando "Selecionar" não qualificado também muda.

Na melhor das hipóteses, sua macro irá travar; na pior, você pode acabar escrevendo valores ou alterando células na pasta de trabalho errada sem nenhuma maneira de "Desfazê-los".

Eu tenho uma regra de ouro simples que sigo: adicionar variáveis ​​chamadas "wb" e "ws" para um objeto Workbook e um objeto Worksheet e sempre usá-los para se referir ao meu livro de macros. Se eu precisar consultar mais de um livro ou mais de uma folha, adiciono mais variáveis.

Por exemplo,

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

O comando "Set wb = ThisWorkbook" é absolutamente fundamental. "ThisWorkbook" é um valor especial no Excel e significa a pasta de trabalho a partir da qual seu código VBA está sendo executado . Um atalho muito útil para definir a variável da pasta de trabalho com.

Depois de fazer isso no topo de seu Sub, usá-los não poderia ser mais simples, basta usá-los onde quer que você usaria "Seleção":

Portanto, para alterar o valor da célula "A1" em "Saída" para "Olá", em vez de:

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

Agora podemos fazer isso:

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

O que não é apenas muito mais confiável e menos provável de travar se o usuário estiver trabalhando com várias planilhas; também é muito mais curto, rápido e fácil de escrever.

Como um bônus adicional, se você sempre nomear suas variáveis ​​como "wb" e "ws", poderá copiar e colar o código de um livro para outro e geralmente funcionará com o mínimo de alterações necessárias, se houver.