executar automaticamente uma macro do Excel em uma mudança de célula

91

Como posso executar automaticamente uma macro do Excel sempre que um valor em uma célula específica muda?

No momento, meu código de trabalho é:

Private Sub Worksheet_Change(ByVal Target As Range)
    If Not Intersect(Target, Range("H5")) Is Nothing Then Macro
End Sub

onde "H5"é a célula particular sendo monitorada e Macroé o nome da macro.

Existe uma maneira melhor?

namin
fonte
A UDF RunMacroWhenValueChanges no FormulaDesk atende aos seus requisitos? formuladesk.com
Gareth Hayter

Respostas:

106

Seu código parece muito bom.

Tenha cuidado, entretanto, pois sua chamada para Range("H5")é um comando de atalho para Application.Range("H5"), que é equivalente a Application.ActiveSheet.Range("H5"). Isso pode ser bom, se as únicas alterações forem alterações do usuário - que é a mais comum - mas é possível que os valores das células da planilha sejam alterados quando não for a planilha ativa por meio de alterações programáticas, por exemplo, VBA.

Com isso em mente, eu utilizaria Target.Worksheet.Range("H5"):

Private Sub Worksheet_Change(ByVal Target As Range)
    If Not Intersect(Target, Target.Worksheet.Range("H5")) Is Nothing Then Macro
End Sub

Ou você pode usar Me.Range("H5"), se o manipulador de eventos estiver na página de código da planilha em questão (geralmente está):

Private Sub Worksheet_Change(ByVal Target As Range)
    If Not Intersect(Target, Me.Range("H5")) Is Nothing Then Macro
End Sub

Espero que isto ajude...

Mike Rosenblum
fonte
4
e se a célula H5for alterada de outra planilha, digamos sheet2 que a função acima não funcione. plz ajuda nisso.
dhpratik
2
Para qualquer pessoa que vier de uma pesquisa no Google, certifique-se de colar este código na planilha no vba, não em um módulo como eu fiz. veja stackoverflow.com/questions/15337008/…
hammythepig
Application.ActiveSheet.Range ("H5"). ==> target.parent.range ("H5") é ainda mais seguro
Pierre
1
@WillEdiger Sempre que você não especifica explicitamente uma referência de planilha, o Excel assume o ActiveSheete sempre que você não especifica explicitamente que é o Excel com o qual está trabalhando, o Excel assume Application.
Scott Marcus
1
Note-se que, em um módulo de código planilha (que é onde um Worksheet_Changeevento deve ser localizado), um incondicional Rangeque não o padrão para ActiveSheetmas em vez refere-se à folha que contém o código. O código nesta resposta é, portanto, efetivamente o mesmo que o código na pergunta. (Observação: em 2009, quando esta resposta foi escrita, pode ter sido diferente, mas tenho quase certeza de que não.)
YowE3K
7

Lidar com o Worksheet_Changeevento ou oWorkbook_SheetChange evento.

Os manipuladores de eventos usam um argumento "Alvo como intervalo", para que você possa verificar se o intervalo que está mudando inclui a célula na qual está interessado.

Joe
fonte
Obrigado, funciona. Eu verifico o alcance com, digamos Target.Address = Range("H5").Address,. Existe uma maneira mais fácil?
namin
Uma alternativa: Not (Intersect(Target, Range("H5")) Is Nothing) . É assim que você faria?
namin
2
O primeiro comentário ( Target.Address = Range("H5").Address) não funcionaria se sua célula fosse apenas parte do intervalo alterado. O segundo comentário ainda sofre os problemas descritos por Mike Rosenblum.
Formiga
5

Passei muito tempo pesquisando isso e aprendendo como tudo funciona, depois de realmente bagunçar os gatilhos de eventos. Como havia tantas informações espalhadas, decidi compartilhar o que descobri para funcionar em um só lugar, passo a passo da seguinte maneira:

1) Abra o VBA Editor, em VBA Project (YourWorkBookName.xlsm), abra o objeto Microsoft Excel e selecione a planilha à qual o evento de alteração se refere.

2) A visualização do código padrão é "Geral". Na lista suspensa na parte superior central, selecione "Planilha".

3) Private Sub Worksheet_SelectionChange já está lá como deveria estar, deixe como está. Copie / cole o código de Mike Rosenblum acima e altere a referência .Range para a célula para a qual você está procurando uma alteração (B3, no meu caso). Não coloque sua macro ainda, no entanto (removi a palavra "Macro" depois de "Então"):

Private Sub Worksheet_Change(ByVal Target As Range)
    If Not Intersect(Target, Me.Range("H5")) Is Nothing Then
End Sub

ou na lista suspensa no canto superior esquerdo, selecione "Alterar" e, no espaço entre Private Sub e End Sub, cole If Not Intersect(Target, Me.Range("H5")) Is Nothing Then

4) Na linha após "Então" desligue os eventos para que quando você chamar a sua macro, ela não acione eventos e tente executar esta Worksheet_Change novamente em um ciclo sem fim que trava o Excel e / ou bagunça tudo:

Application.EnableEvents = False

5) Chame sua macro

Call YourMacroName

6) Ative os eventos novamente para que a próxima mudança (e qualquer / todos os outros eventos) seja acionada:

Application.EnableEvents = True

7) Termine o bloco If e o Sub:

    End If
End Sub

Todo o código:

Private Sub Worksheet_Change(ByVal Target As Range)
    If Not Intersect(Target, Me.Range("B3")) Is Nothing Then
        Application.EnableEvents = False
        Call UpdateAndViewOnly
        Application.EnableEvents = True
    End If
End Sub

Isso ativa / desativa eventos dos Módulos, o que cria problemas e simplesmente permite que a alteração seja acionada, desativa eventos, executa sua macro e ativa os eventos novamente.

Eric Vaughn-Shobey
fonte
3

Eu prefiro assim, não usando uma célula, mas um intervalo

    Dim cell_to_test As Range, cells_changed As Range

    Set cells_changed = Target(1, 1)
    Set cell_to_test = Range( RANGE_OF_CELLS_TO_DETECT )

    If Not Intersect(cells_changed, cell_to_test) Is Nothing Then 
       Macro
    End If
Javier Torón
fonte
É o mesmo que uma célula. Você pode definir um intervalo como uma célula, intervalo de células contínuas ou mesmo células dispersas (todos separados por vírgula).
Shai Alon de
0

Tenho um celular que está vinculado ao banco de dados de ações online e é atualizado com frequência. Quero acionar uma macro sempre que o valor da célula for atualizado.

Eu acredito que isso é semelhante à alteração do valor da célula por um programa ou qualquer atualização de dados externa, mas os exemplos acima de alguma forma não funcionam para mim. Acho que o problema é porque os eventos internos do Excel não são acionados, mas é o meu palpite.

Eu fiz o seguinte,

Private Sub Worksheet_Change(ByVal Target As Range) 
  If Not Intersect(Target, Target.Worksheets("Symbols").Range("$C$3")) Is Nothing Then
   'Run Macro
End Sub
Juan Garcia
fonte
1
Não consigo fazer isso funcionar por algum motivo. Quando digo ao código para ser executado em VBA, ele abre um menu pop-up e me pergunta se desejo executar a macro em vez de executá-la automaticamente.
David Van der Vieren