Notifications
Clear all

Private Sub Worksheet_Calculate

15 Posts
5 Usuários
0 Reactions
3,617 Visualizações
(@ramzero)
Posts: 127
Estimable Member
Topic starter
 

Fala pessoal

Tenho uma planilha com Private Sub Worksheet_Calculate

E portanto, qualquer coisa que é alterada na planilha o código é acionado e roda

Porém, preciso inserir mais dados nela, e esses novos dados se alteram, rodando o código acima sem eu querer naquele momento

Gostaria que o código rodasse, somente se alguma coisa fosse alterada de A1 até G1

É possível isso?

Obrigado

 
Postado : 14/03/2018 11:23 am
(@klarc28)
Posts: 971
Prominent Member
 
Option Explicit

Private Sub Worksheet_Change(ByVal Target As Range)
    Dim KeyCells As Range

    ' The variable KeyCells contains the cells that will
    ' cause an alert when they are changed.
    Set KeyCells = Range("A1:G1")
    
    If Not Application.Intersect(KeyCells, Range(Target.Address)) _
           Is Nothing Then

        ' Display a message when one of the designated cells has been
        ' changed.
        ' Place your code here.
        MsgBox "Cell " & Target.Address & " has changed."
       
    End If
End Sub

 
Postado : 14/03/2018 11:31 am
(@ramzero)
Posts: 127
Estimable Member
Topic starter
 

Fala Klarc28

Tentei aqui mas não rodou não

As células que sofrem alterações (A1:G1) recebem uma fórmula RTD e a fórmula em si não se altera, mas o valor que ela gera sim

Tentei digitar manualmente alguma coisa nessas células e dei enter, aí funcionou, ou seja, a ideia é essa, só que precisa funcionar somente quando a fórmula altera os dados

Tem alguma outra saída?

Obrigado

 
Postado : 15/03/2018 3:30 pm
EdsonBR
(@edsonbr)
Posts: 1057
Noble Member
 

Nunca usei essa função RTD e não tenho como testá-la mas pelo que li a respeito, nem Worksheet_Change nem Worksheet_Calculate disparam quando algum valor retorna.

Parece-me que uma das saídas é usar o velho gatilho de eventos OnData que faz parte dos "Excel 5.0 Events" que parece responder a alterações provenientes de DDE. Ele está oculto, mas ainda funciona.

Outra saída seria usar uma fórmula em outro intervalo se referindo ao intervalo A1:G1, por exemplo fazer M1:S1 = A1:G1 e aí sim usar os eventos normais.

Há também uma terceira possibilidade com o método SetLinkOnData do objeto Workbook. Teria que explorar.

Alguns links que podem ser úteis:

worksheet change and DDE
RTD value changes not triggering worksheet change event
Excel 5.0 Events
Start a macro when an event occurs

 
Postado : 15/03/2018 5:33 pm
(@ramzero)
Posts: 127
Estimable Member
Topic starter
 

Fala EdsonBR, beleza?

O Worksheet_Calculate funciona, ele faz rodar quando chegam novos dados, inclusive é o que atualmente está funcionando aqui

Porém precisei colocar novas fórmulas DDE/RTD na planilha em outras células diferentes (H1:O1), e agora ele dispara toda hora que chega novos dados, tanto em (A1:G1) quanto em (H1:O1), gerando erroneamente uma atualização na planilha replicando o que já tinha em (A1:G1)

Só que preciso que rode o código somente quando chegar novos dados no DDE/RTD que estão de (A1:G1)

Li a respeito do Application.OnData, mas creio que ele não vai sanar este problema pois ele acionará simplesmente quando chegar novos dados, na planilha inteira, como já está acontecendo agora

Como seria a ideia da fórmula em outro intervalo, não entendi, poderia me explicar melhor? Talvez seja a mais simples e assertiva

Obrigado

 
Postado : 16/03/2018 5:22 am
(@klarc28)
Posts: 971
Prominent Member
 

Pensei na seguinte solução:

Que tal selecionar automaticamente uma célula a cada 30 segundos para acionar o evento SelectionChange, como se você tivesse apertado TAB?

Confira o anexo:

 
Postado : 18/03/2018 6:02 pm
(@ramzero)
Posts: 127
Estimable Member
Topic starter
 

Fala Klarc28

A ideia não é ruim, porém não dá certo nesse caso, porque eu não sei exatamente quando é que chegarão novos dados, e quando chegam, tem que ser processados imediatamente, não podendo esperar tempo nenhum, e mesmo que coloque 1 segundo, dentro deste tempo pode não ter chegado dado nenhum novo, daí causa dubiedade nos resultados, porque vai rodar novamente o código.

Será que tem como separar por planilha?

Exemplo:

Na Plan2 coloco as fórmulas DDE antigas (aquelas que precisam que rodem os códigos quando são atualizadas)

Na Plan 3 coloco as fórmulas DDE novas (aquelas que mesmo atualizando, não devem fazer rodar o código)

E na Plan 1 os resultados

De forma que só rodariam os códigos se houvesse atualização na Plan 2

Tem como fazer assim?

Obrigado

 
Postado : 19/03/2018 4:41 am
Basole
(@basole)
Posts: 487
Reputable Member
 

Acho que o ideal seria analisar e testar em sua planilha para te passar uma solução correta.

De qualquer forma segue minha sugestão para testes.

Click em se a resposta foi util!

 
Postado : 19/03/2018 7:35 am
(@vitorhsh)
Posts: 0
Trusted Member
 

Veja se ajuda

Private Sub Worksheet_Change(ByVal Target As Range)
Application.ScreenUpdating = False
If Target.Address = "$A$1:$G$5" Then
Sua rotina Neste caso ta salvando a plan
ActiveWorkbook.Save
Exit Sub

End If
Application.ScreenUpdating = True

End Sub

 
Postado : 19/03/2018 7:46 am
EdsonBR
(@edsonbr)
Posts: 1057
Noble Member
 

Fala EdsonBR, beleza?
O Worksheet_Calculate funciona, ele faz rodar quando chegam novos dados, inclusive é o que atualmente está funcionando aqui

Ah, se a RTD dispara o Calculate então fica mais claro o que vc precisa.

O principal problema a contornar é que infelizmente o evento Worksheet_Calculate não dispõe de um argumento Target tal como o Worksheet_Change possui, então temos que lançar mão de algum artifício para descobrirmos se um determinado intervalo sofreu ou não alteração.

Vamos tomar seu intervalo A1:G1 da Plan1 como exemplo.
Há pelo menos três maneiras de contornar isso:

Primeiro método:

  • Crie uma nova planilha, que pode ser oculta, digamos "PlanOculta" e numa célula qualquer insira a fórmula matricial =Plan1!A1:G1 ou num intervalo do mesmo tamanho que A1:G1 faça referência a cada célula de Plan1!A1 até Plan1!G1.[/*:m:u01tsslt]
  • No módulo de eventos da PlanOculta, agora sim use o evento Worksheet_Calculate() normalmente para seu propósito, pois ele só será disparado se alguma célula em Plan1!A1:G1 for alterada.[/*:m:u01tsslt][/list:u:u01tsslt]
  • Segundo método:

    • Quando sua pasta de trabalho for aberta, guardar o valor das células A1:G1 da Plan1 numa variável Global usando o evento Workbook_Open do módulo EstaPasta_de_trabalho.[/*:m:u01tsslt]
    • No evento Calculate da Plan1, testar se os valores do intervalo A1:G1 ainda são os mesmos dos iniciais em ValAnterior. Se não forem é porque alterações ocorreram e vc pode inserir o código para tratamento dos valores.[/*:m:u01tsslt]
    • Alimentar ValAnterior com os novos valores para detectar próximas alterações.
    • Exemplo:
      No módulo do Workbook (EstaPasta_de_Trabalho)

      Option Explicit
      Public ValAnterior As Variant
      Private Sub Workbook_Open()
        ValAnterior = Plan1.Range("A1:G1").Value
      End Sub
      

      No módulo da Plan1:

      Option Explicit
      Private Sub Worksheet_Calculate()
        Dim i As Byte
        For i = 1 To 7
          With Me.Range("A1:G1")
            If .Cells(i) <> EstaPasta_de_trabalho.ValAnterior(1, i) Then
              MsgBox "Ocorreram mudanças em A1:G1, célula:" & vbCrLf & _
                      .Cells(i).Address(False, False)
              EstaPasta_de_trabalho.ValAnterior(1, i) = .Cells(i)
            End If
          End With
        Next i
      End Sub
      

      [/*:m:u01tsslt][/list:u:u01tsslt]

      Terceiro Método:

      • Através da criação de uma classe criando armadilhas de evento para a Plan1 focada no intervalo A1:G1 (por ser mais trabalhosa, deixemos como uma opção a mais, caso esteja interessado).[/*:m:u01tsslt][/list:u:u01tsslt]
      •  
Postado : 19/03/2018 10:00 am
(@ramzero)
Posts: 127
Estimable Member
Topic starter
 

Fala EdsonBR

Creio que o seu primeiro método seja o melhor aplicável para mim, porém preciso de mais detalhes pra entender como fazer

Vamos lá, o que eu fiz?

-Na nova PlanOculta coloco =Plan1!A1 em A1, =Plan1!B1 em B1 e sucessivamente até o G1

-No VBA clico com o direito na PlanOculta -> Inserir Módulo

-Nesse novo módulo digito:

Private Sub Worksheet_Calculate()

End Sub

Até aqui tá certo?

Agora empaquei

Devo mudar o nome da Private Sub Worksheet_Calculate() da Plan1? E no módulo que inseri da PlanOculta, devo dar um Call pra chamar a rotina que há em Plan1
Precisa fazer mais alguma coisa?

Obrigado

 
Postado : 20/03/2018 11:45 am
EdsonBR
(@edsonbr)
Posts: 1057
Noble Member
 

Na nova PlanOculta coloco =Plan1!A1 em A1, =Plan1!B1 em B1 e sucessivamente até o G1 ==> OK

-No VBA clico com o direito na PlanOculta -> Inserir Módulo ==> Clica com o direito na guia (orelha) e escolhe Exibir Código

-Nesse novo módulo digito: ==> Digita ou escolhe Worksheet na combobox logo acima à esquerda e Calculate na da direita

Private Sub Worksheet_Calculate()

End Sub

Até aqui tá certo? ==> SIM

Agora empaquei

Devo mudar o nome da Private Sub Worksheet_Calculate() da Plan1? E no módulo que inseri da PlanOculta, devo dar um Call pra chamar a rotina que há em Plan1
Precisa fazer mais alguma coisa?
==> Na realidade, vc não vai mais precisar do código la na Plan1, pois quem estará monitorando e agindo será esse na PlanOculta (ela será somente "escrava" da Plan1). Então é só deletar todo o código de lá e mover pra PlanOculta.
Logicamente que, se em seu código da PlanOculta precisar buscar ou alterar algum dado da Plan1, deverá qualificar o intervalo antes, ou seja, ao invés de Range("A1"), usar Worksheets("Plan1").Range("A1"), ok?

 
Postado : 20/03/2018 1:14 pm
(@ramzero)
Posts: 127
Estimable Member
Topic starter
 

EdsonBr

Tentei aqui mas deixando a Worksheet_Calculate na Plan1 mesmo, e inserindo os outros DDEs na Plan2, que seria o mesmo raciocínio que você me passou, mas não funcionou

Ou seja, mesmo os novos DDEs estando na PlanOculta a Worksheet_Calculate da Plan1, roda o código

Obrigado

 
Postado : 21/03/2018 1:04 pm
EdsonBR
(@edsonbr)
Posts: 1057
Noble Member
 

...mesmo os novos DDEs estando na PlanOculta...

Como assim? Na PlanOculta era só para ter as fórmulas =Plan1!A1 até =Plan1!G1 e nada mais.

 
Postado : 21/03/2018 1:26 pm
(@ramzero)
Posts: 127
Estimable Member
Topic starter
 

EdsonBr

O que fiz foi seguir sua linha de raciocínio, mas ao invés de ter as fórmulas =Plan1!A1 até =Plan1!G1 na PlanOculta

Decidi por deixar as DDEs antigas (que devem rodar o código) na Plan1 e colocar as DDEs novas (que não devem rodar o código) na PlanOculta

Penso que dá no mesmo, não é?

Mesmo assim o código rodou, mesmo quando atualizou as antigas quanto as novas

Ou a Plan1 vale mais que a Plan2 que vale mais que a Plan3, etc.......?

Obrigado

 
Postado : 21/03/2018 1:36 pm