No meu código, tenho uma combobox em um userform. O usuário seleciona uma opção do menu suspenso e o userform define o valor selecionado para uma variável global "monthYearEntered".
Então eu tenho uma sub-rotina que usa a variável global. No entanto, o valor da variável global não está sendo transferido para a sub-rotina. Eu sei porque eu fiz uma MsgBox da variável de dentro do userform e depois novamente na sub-rotina. Eu obtenho o valor certo no formulário, mas não na rotina.
Pesquisei um pouco e vi algumas soluções potenciais, mas nenhuma delas funcionou para mim. Em alguns códigos anteriores, fiz uma solução alternativa definindo cell para o valor e, em seguida, referenciando a cell para definir a variável na subrotina. Gostaria de evitar isso, pois é apenas um Band-Aid.
CÓDIGO DO FORMULÁRIO DE USUÁRIO
Private Sub CBN_OK_Click()
If YearMonthField = "" Then
MsgBox "Value cannot be blank. Please enter correct value."
Exit Sub
Else
monthYearEntered = YearMonthField.Value
MsgBox monthYearEntered
Me.Hide
Application.Run "DeleteMonth"
End If
End Sub
MÓDULO
Option Explicit
Dim monthYearEntered As String
Private Sub RangetoDelete()
Application.DisplayAlerts = False
Dim ws As Worksheet
Dim tableSalesCombined As ListObject
Dim cell, rng As Range
Set ws = ThisWorkbook.Worksheets("Sales Data Combined")
Set tableSalesCombined = ws.ListObjects("Table_SalesCombined")
Set rng = ws.Columns("I:I")
DeleteMonthForm.Show 'show user form
'monthYearEntered.ClearContents
Application.Run "Protect"
Application.DisplayAlerts = True
End Sub
Private Sub DeleteMonth()
Application.DisplayAlerts = False
Dim ws As Worksheet
Dim tableSalesCombined As ListObject
'Dim monthYearValue
Dim cell, rng As Range
Set ws = ThisWorkbook.Worksheets("Sales Data Combined")
Set tableSalesCombined = ws.ListObjects("Table_SalesCombined")
Set rng = ws.Columns("I:I")
ws.Unprotect Password:=PassW
'look for value entered by user (monthYearValue)
Set cell = rng.Find(What:=monthYearEntered, LookIn:=xlFormulas, LookAt:=xlWhole, MatchCase:=False)
MsgBox monthYearEntered
If cell Is Nothing Then
MsgBox monthYearEntered & "not found in Combined Sales Data. Please confirm value and try again."
Exit Sub
End If
With tableSalesCombined
.Range.AutoFilter Field:=9, Criteria1:=monthYearEntered
If Not .DataBodyRange Is Nothing Then
'.DataBodyRange.SpecialCells(xlCellTypeVisible).Delete
End If
'.Range.AutoFilter
End With
tableSalesCombined.AutoFilter.ShowAllData
'monthYearEntered.ClearContents
Application.Run "Protect"
Application.DisplayAlerts = True
End Sub
Escrever
Dim monthYearEntered As String
no topo de um módulo declara a variávelmonthYearEntered
como global, mas seu escopo é limitado ao módulo onde a definição está. Isso significa que, fora do módulo, a variável é desconhecida.Se você quiser que a variável seja acessível fora do módulo, você precisa declará-la usando a
Global
palavra-chave, não aDim
palavra-chave .Como você declarou a variável com
Dim
, a declaraçãomonthYearEntered = YearMonthField.Value
no formulário não pode escrever na variável - ela é simplesmente desconhecida lá. Há 2 possibilidades, mas no final das contas o resultado é o mesmo:Você tem uma variável
monthYearEntered
declarada no formulário. Esta é uma nova variável e não tem nada a ver com a variável que você declarou no módulo.Você não tem uma variável declarada no formulário:
Option Explicit
no formulário. Quando a rotina Click atinge a declaração de atribuição, o tempo de execução do VBA verá que, neste momento,monthYearEntered
é desconhecido para criá-lo em tempo real. Novamente, esta é uma variável diferente.Option Explicit
: O compilador irá reclamar.Você pode verificar isso facilmente no editor VBA: mova o cursor sobre a variável e pressione Shift+F2
Left
ouDate
, ou um objeto comoApplication
), a janela do navegador de objetos é exibida.Um exemplo: coloquei o seguinte código em um módulo1
Agora crio outro módulo e coloco o seguinte código (note que por enquanto,
Option Explicit
está desativado):' Opção Explícita Sub test2() Debug.Print "Agora em test2: ", globVar, dimVar globVar = "substituído em test2" dimVar = "substituído em test2" Debug.Print "Ainda em test2: ", globVar, dimVar End Sub
Executando
test1
, você obtém a seguinte saída:Você pode ver que
globVar
é exibido emtest2
, e o novo valor atribuído é visto também ao retornar paratest1
. No entanto, imprimirdimVar
em test2 não mostra nada: A variável é desconhecida naquele momento e criada instantaneamente. Você pode escrever nela, mas isso não é visto emtest1
pois é uma variável diferente , apenas com o mesmo nome.Se você ativar agora o
Option Explicit
no módulo2, você obterá um erro do compilador porquedimVar
is unkwown. Se você adicionar agora uma declaração paradimVar
into module2 (para se livrar desse erro do compilador), você declara uma nova variável - o resultado é o mesmo:globVar
é visível em ambos os módulos, masdimVar
do módulo1 não é.(Mesma saída de antes)
Só para completar: se você adicionar uma declaração para
globVar
no módulo2, você ocultará a declaração deglobVar
no módulo1 e terá duas variáveis diferentes.Agora você obtém
Se você quiser declarar uma variável "global" dentro de um formulário, não poderá usar a palavra-chave
Global
. O motivo é que um formulário é uma classe, e você pode ter várias instâncias de uma classe (você pode abrir um formulário mais de uma vez). Para tornar uma variável visível fora do formulário, use a palavra-chavepublic
.Código do formulário: Public formVar As String
Código do módulo usando a instância padrão do formulário:
ou usando uma instância explícita:
Note que você precisa usar
Hide
para fechar o formulário. Se você usar o comando infameUnload
, o objeto userform é destruído (removido da memória) efrm.formVar
não fica mais acessível.Resumo:
Dim
no nível do módulo declara uma variável no nível do módulo que é desconhecida em outros módulosGlobal
declara uma variável que é conhecida em todos os módulosOption Explicit
para evitar que o tempo de execução do VBA crie variáveis não declaradas dinamicamente.