Este fórum está sendo desativado

Depois de 9 anos, este fórum será desativado. Mas calma.... estamos migrando para uma comunidade no DISCORD. Junte-se a nós.

ENTRAR PARA DISCORD

Tópicos relacionados a códigos VBA, gravação de macros, etc.
#58627
Boa tarde.

Pessoal... como faço para executar a Macro "TESTE" sempre que o range "Rng_QtdeAtivos" (Seta Amarela) tiver o seu valor alterado?
O valor do range "Rng_QtdeAtivos" é dado por fórmula.
Entendo que seja pelo evento change da planilha em questão... mas só rodou a macro quando alterei o valor do range manualmente.
Alguém poderia me ajudar?
Segue planilha para verificação.
Você não está autorizado a ver ou baixar esse anexo.
#58652
Criei esta função e esta variável global no módulo:
Código: Selecionar todos
Public lngValor As Long

Public Function VerificaValor() As Boolean
    If lngValor <> CLng(Wsh_Acoes.Range("Rng_QtdeAtivos").Value2) Then
        VerificaValor = False
    Else
        VerificaValor = True
    End If
    
    lngValor = Wsh_Acoes.Range("Rng_QtdeAtivos").Value2
End Function
E no evento Change da planilha criei este código:
Código: Selecionar todos
Option Explicit

Private Sub Worksheet_Change(ByVal Target As Range)
    Dim lobTab          As ListObject
    
    With Wsh_Acoes
    
        Set lobTab = .ListObjects("TB_MovimentaçãodeAtivos")
        
        If VerificaValor Then Exit Sub
        
        If Not Application.Intersect( _
                        lobTab.ListColumns("Ativo").DataBodyRange, _
                        Target) Is Nothing Then
            Call TESTE
        End If
    End With
End Sub
Você não está autorizado a ver ou baixar esse anexo.
#58666
Show, babdallas.

Obrigado pela contribuição com a função.

Para o meu aprendizado poderia fazer um breve comentário nesse trecho do código:
Código: Selecionar todos
Public Function VerificaValor() As Boolean
    If lngValor <> CLng(Wsh_Acoes.Range("Rng_QtdeAtivos").Value2) Then
        VerificaValor = False
E nesse:
Código: Selecionar todos
 If VerificaValor Then Exit Sub
       
        If Not Application.Intersect( _
                        lobTab.ListColumns("Ativo").DataBodyRange, _
                        Target) Is Nothing Then
Aproveitando a sua colaboração poderia me ajudar na sequencia da macro que vc já conhece pois também me ajudou na elaboração dela?

O que preciso agora:

1) Que no lugar da Macro "TESTE" que ele rode a Macro "RedimensionaTabela" que vc me ajudou a fazer há um bom tempo atrás e a Macro "Atualiza_Acoes" que tentei fazer a partir de um código seu também.

2) Que seja mantido o espaço de 2 (duas) linhas entre a Tabela "TB_CarteiraAtual" e a linha que contem o intervalo "Rng_QtdeAtivos"

Mais uma vez obrigado pela grande ajuda. Segue a planilha para verificação
Você não está autorizado a ver ou baixar esse anexo.
#58704
Código: Selecionar todos
Public Function VerificaValor() As Boolean
    If lngValor <> CLng(Wsh_Acoes.Range("Rng_QtdeAtivos").Value2) Then
        VerificaValor = False
Criei uma variável pública chamada lngValor (do tipo Long). Esta variável vai receber o valor da célula Rng_QtdeAtivos. Vamos supor que o valor da célula Rng_QtdeAtivos seja igual a 4. Então lngValor tb será 4. Aí você altera um valor no campo Ativo, mas o valor da célula Rng_QtdeAtivos continua em 4. Então, este código vai comparar se lngValor (que tem valor 4) é igual ao valor da célula Rng_QtdeAtivos. Neste caso é igual, logo a função VerificaValor será True.

Agora vamos supor que o valor da célula Rng_QtdeAtivos seja igual a 4. Então lngValor tb será 4. Aí você altera um valor no campo Ativo, mas o valor da célula Rng_QtdeAtivos se altera para 3. Então, este código vai comparar se lngValor (que tem valor 4) é igual ao valor da célula Rng_QtdeAtivos. Neste caso é diferente, logo a função VerificaValor será False.

Ou seja, criei esta função para verificar se a célula Rng_QtdeAtivos foi alterada, pois a variável pública lngValor armazena o valor de Rng_QtdeAtivos no cálculo anterior.


Código: Selecionar todos
f VerificaValor Then Exit Sub
       
        If Not Application.Intersect( _
                        lobTab.ListColumns("Ativo").DataBodyRange, _
                        Target) Is Nothing Then
No código acima, se VerificaValor for True, quer dizer que o valor de Rng_QtdeAtivos não foi alterada. Sendo assim, ele sai da subrotina e não faz nada. Porém, se VerificaValor for False, então quer dizer que o valor de Rng_QtdeAtivos foi alterada.
Logo em seguida, verifico se a célula modificada (Target) foi modificada na coluna Ativo. O método Intersect do objeto verifica se a intersecção entre dois intervalos de células é verdadeira ou não. Se não houver intersecção, ela retorna um valor nulo, mas se houver, retorna o intervalo de intersecção.
Então eu comparo se o valor é nulo (is nothing). Porém eu quero o contrário, que seja não nulo. Por isso o "Not" antes da verificação, invertendo a lógica de comparação, pois quero verifica se ele não é nulo.


Em relação ao uso da subrotina RedimensionaTabela, ela possui dois parâmetros. O primeiro parâmetro é a Tabela, o que não é problema, pois a tabela é a TB_MovimentaçãodeAtivos. O segundo parâmetro é a quantidade de linhas que se deseja redimensionar. Para mim não está claro para quantas linhas você quer redimensionar a tabela após haver alteração do valor da célula Rng_QtdeAtivos.
Sugiro que você dê um exemplo prático de uma (ou mais) alteração(ões) e diga qual o resultado esperado neste redimensionamento da tabela.
#58722
Muito obrigado pelas explicações, babdallas.
Sempre são de grande validade... obrigado mesmo.
Logo em seguida, verifico se a célula modificada (Target) foi modificada na coluna Ativo. O método Intersect do objeto verifica se a intersecção entre dois intervalos de células é verdadeira ou não. Se não houver intersecção, ela retorna um valor nulo, mas se houver, retorna o intervalo de intersecção.
Então eu comparo se o valor é nulo (is nothing). Porém eu quero o contrário, que seja não nulo. Por isso o "Not" antes da verificação, invertendo a lógica de comparação, pois quero verifica se ele não é nulo.
O método intersect e a definilção do target ainda são um pouco confusos para mim mas vou estudar ais um pouco para compreender.
Em relação ao uso da subrotina RedimensionaTabela, ela possui dois parâmetros. O primeiro parâmetro é a Tabela, o que não é problema, pois a tabela é a TB_MovimentaçãodeAtivos.
Para mim ok também.
O segundo parâmetro é a quantidade de linhas que se deseja redimensionar. Para mim não está claro para quantas linhas você quer redimensionar a tabela após haver alteração do valor da célula Rng_QtdeAtivos.
Então a quantidade de linhas para a qual a tabela deve ser dimensionada é sempre um número a mais que a quantidade de ativos.

No caso do nosso exemplo... através de uma fórmula na coluna [Ativo] da Tabela "TB_CarteiraAtual" eu consigo retornar todos os ativos da "TB_MovimentaçãodeAtivos".

Repare que são 4 ativos que a fórmula retorna (= ao valor de Rng_QtdeAtivos) e a tabela "TB_CarteiraAtual"é redimensionada para 5 linhas.

Além disso são mantidas duas linhas "vazias" de espaçamento entre a "TB_CarteiraAtual" e o range "Rng_QtdeAtivos" (linhas 16 e 17 estão em branco).
Ou 3 linhas como preferir, caso considere o espaçamento entre a Tabela "TB_CarteiraAtual" e a Tabela "TB_MovimentaçãodeAtivos".

O esqueleto das Macros eu montei graças a sua ajuda em outras aplicações mas aqui não consegui aplicar.

Segue planilha com o exemplo.

Qualquer coisa estou a disposição para novo esclarecimento.

Mais uma vez obrigado pela ajuda.
Você não está autorizado a ver ou baixar esse anexo.
#58802
Eu criei uma subrotina RedimensionaTabela2. veja se atende:

]
Código: Selecionar todos
Public Sub RedimensionaTabela2(lobTabela As ListObject, lngQtdeLinhas As Long)
    With lobTabela
        If .ListRows.Count > 1 Then
            If .ListRows.Count < lngQtdeLinhas Then
                With lobTabela.DataBodyRange
                    .Rows(.Rows.Count).Resize(lngQtdeLinhas - lobTabela.ListRows.Count).EntireRow.Insert
                End With
            ElseIf .ListRows.Count > lngQtdeLinhas Then
                .DataBodyRange(1, 1).Resize(.ListRows.Count - lngQtdeLinhas).EntireRow.Delete Shift:=xlUp
            End If
        End If
        
        With lobTabela.DataBodyRange
            .Rows(1).AutoFill Destination:=Range("TB_CarteiraAtual"), _
                                Type:=xlFillValues
        End With
    End With
End Sub
Você não está autorizado a ver ou baixar esse anexo.
#58939
Bom dia.

Mais uma vez obrigado pela colaboração.
Funciona perfeitamente para o que necessito e fiz toda a leitura do funcionamento.

Poderia para meu aprendizado fazer um breve comentário para esse trecho da Macro RedimensionaTabela2:
Código: Selecionar todos
With lobTabela.DataBodyRange
            .Rows(1).AutoFill Destination:=Range("TB_CarteiraAtual"), _
                                Type:=xlFillValues
E apenas uma dúvida... houve algum motivo para mudar a estrutura da Function VerificaValor?
Passou de:
Código: Selecionar todos
Public lngValor As Long

Public Function VerificaValor() As Boolean
    If lngValor <> CLng(Wsh_Acoes.Range("Rng_QtdeAtivos").Value2) Then
        VerificaValor = False
    Else
        VerificaValor = True
    End If
   
    lngValor = Wsh_Acoes.Range("Rng_QtdeAtivos").Value2
End Function

Para:
Código: Selecionar todos
Public Function VerificaValor() As Boolean
    Dim lobTabRed       As ListObject
    
    With Wsh_Acoes
        VerificaValor = (lngValor = VBA.CLng(.Range("Rng_QtdeAtivos").Value2))
    
        lngValor = .Range("Rng_QtdeAtivos").Value2
    End With
    
    Set lobTabRed = Nothing
End Function
Testei com as duas e aparentemente não houve distinção na rotina... Vi que acrescentou apenas uma linha de código
Código: Selecionar todos
lngValor = VBA.CLng(Wsh_Acoes.Range("Rng_QtdeAtivos").Value2)
no evento Workbook_Open
#58942
O código abaixo pega a primeira linha da Tabela e "arrasta" a fórmula para todas as linhas. Tive que fazer isso, porque a formula utilizada é matricial. Quando adicionava uma linha, a fórmula perdia o caráter matricial e os resultados ficavam errados.
Código: Selecionar todos
With lobTabela.DataBodyRange
            .Rows(1).AutoFill Destination:=Range("TB_CarteiraAtual"), _
                                Type:=xlFillValues

A mudança da subrotina VerificaValor foi somente para ficar mais enxuto o código, mas as 2 funcionam perfeitamente. O valor (true ou false) da função VerificaValor será dada sempre pela comparação entre
Código: Selecionar todos
(lngValor = VBA.CLng(.Range("Rng_QtdeAtivos").Value2))
. Assim, a estrutura if que estava usando era desnecessária.

Adicionei a linha abaixo no evento Open da Workbook para que a variável lngValor (que é publica ou global) já fique com o valor da célula Rng_QtdeAtivos. Se não fizer isso, a primeira comparação entre lngValor e Rng_QtdeAtivos").Value2 sempre será falsa (pois lngValor no início seria zero na primeira vez)
Código: Selecionar todos
lngValor = VBA.CLng(Wsh_Acoes.Range("Rng_QtdeAtivos").Value2)
long long title how many chars? lets see 123 ok more? yes 60

We have created lots of YouTube videos just so you can achieve [...]

Another post test yes yes yes or no, maybe ni? :-/

The best flat phpBB theme around. Period. Fine craftmanship and [...]

Do you need a super MOD? Well here it is. chew on this

All you need is right here. Content tag, SEO, listing, Pizza and spaghetti [...]

Lasagna on me this time ok? I got plenty of cash

this should be fantastic. but what about links,images, bbcodes etc etc? [...]

Estamos migrando para uma comunidade no Discord