Jak zadeklarować zmienną globalną w VBA?

136

Napisałem następujący kod:

Function find_results_idle()

    Public iRaw As Integer
    Public iColumn As Integer
    iRaw = 1
    iColumn = 1

I otrzymuję komunikat o błędzie:

„nieprawidłowy atrybut w podrzędnym lub funkcji”

Czy wiesz, co zrobiłem źle?

Próbowałem użyć Globalzamiast Public, ale mam ten sam problem.

Próbowałem zadeklarować samą funkcję jako `Publiczną, ale to też nie pomogło.

Co muszę zrobić, aby utworzyć zmienną globalną?

Nimrod
źródło

Odpowiedzi:

181

Musisz zadeklarować zmienne poza funkcją:

Public iRaw As Integer
Public iColumn As Integer

Function find_results_idle()
    iRaw = 1
    iColumn = 1
SLaks
źródło
Kiedy próbuję zadeklarować tablicę jako publiczną, mówi: tablica i typy danych zdefiniowane przez użytkownika nie mogą być deklarowane jako publiczne.
kapilddit
Powyżej pierwszego znakuFunction / Sub, nie tylko na zewnątrz: „Zmienne na poziomie modułu można zadeklarować za pomocą instrukcji Dim lub Private u góry modułu nad pierwszą definicją procedury”. (z zakresu zmiennych w Visual Basic for Applications )
Nickolay
122

To jest kwestia zakresu .

Jeśli chcesz, aby zmienne trwały przez cały okres istnienia funkcji, użyj Dim(skrót od Dimension ) wewnątrz funkcji lub sub, aby zadeklarować zmienne:

Function AddSomeNumbers() As Integer
    Dim intA As Integer
    Dim intB As Integer
    intA = 2
    intB = 3
    AddSomeNumbers = intA + intB
End Function
'intA and intB are no longer available since the function ended

Globalna zmienna (jak SLaks zauważył) jest zadeklarowana poza funkcją przy użyciu Publicsłowa kluczowego. Ta zmienna będzie dostępna przez cały okres użytkowania uruchomionej aplikacji. W przypadku programu Excel oznacza to, że zmienne będą dostępne tak długo, jak długo dany skoroszyt programu Excel będzie otwarty.

Public intA As Integer
Private intB As Integer

Function AddSomeNumbers() As Integer
    intA = 2
    intB = 3
    AddSomeNumbers = intA + intB
End Function
'intA and intB are still both available.  However, because intA is public,  '
'it can also be referenced from code in other modules. Because intB is private,'
'it will be hidden from other modules.

Możesz także mieć zmienne, które są dostępne tylko w ramach określonego modułu (lub klasy), deklarując je za pomocą Privatesłowa kluczowego.

Jeśli budujesz dużą aplikację i czujesz potrzebę użycia zmiennych globalnych, polecam utworzenie osobnego modułu tylko dla zmiennych globalnych. To powinno pomóc Ci śledzić je w jednym miejscu.

Ben McCormack
źródło
4
+1 Nadal przydatne 7 lat później. Ale czy jest jakiś dodatkowy niuans dotyczący zmiennych obiektowych w porównaniu ze zmiennymi danych? Napotkałem problem związany z określaniem zakresu zmiennych obiektów, który spowodował nowe pytanie. Bardzo cenne, jeśli masz czas na spojrzenie. stackoverflow.com/q/46058096/5457466
Egalth
2
Zwięzłe wyjaśnienie deklaracji zmiennych w VBA.
PhillipOReilly
Wypróbowałem wszystkie inne sugestie dotyczące „zakresu” i żadna nie zadziałała. Jedyną rzeczą, która działała, był nowy moduł specjalnie dla zmiennych globalnych i działa!
Fandango68
18

Pytanie tak naprawdę dotyczy zakresu, jak ujął to drugi facet.

Krótko mówiąc, rozważmy ten „moduł”:

Public Var1 As variant     'Var1 can be used in all
                           'modules, class modules and userforms of 
                           'thisworkbook and will preserve any values
                           'assigned to it until either the workbook
                           'is closed or the project is reset.

Dim Var2 As Variant        'Var2 and Var3 can be used anywhere on the
Private Var3 As Variant    ''current module and will preserve any values
                           ''they're assigned until either the workbook
                           ''is closed or the project is reset.

Sub MySub()                'Var4 can only be used within the procedure MySub
    Dim Var4 as Variant    ''and will only store values until the procedure 
End Sub                    ''ends.

Sub MyOtherSub()           'You can even declare another Var4 within a
    Dim Var4 as Variant    ''different procedure without generating an
End Sub                    ''error (only possible confusion). 

Więcej informacji na temat deklaracji zmiennych i innych pytań dotyczących przepełnienia stosu można znaleźć w tym dokumencie MSDN, aby uzyskać więcej informacji na temat tego, jak zmienne wykraczają poza zakres.

Dwie inne szybkie rzeczy:

  1. Zachowaj porządek podczas używania zmiennych na poziomie skoroszytu, aby kod nie był mylący. Preferuj funkcje (z odpowiednimi typami danych) lub przekazuj argumenty ByRef .
  2. Jeśli chcesz, aby zmienna zachowała swoją wartość między wywołaniami, możesz użyć instrukcji Static .
FCastro
źródło
Czy na pewno zmienna globalna może być używana w różnych skoroszytach? Nie działa dla mnie
Seb
Słuszna uwaga! Zauważyłem, że nie dodałem odniesienia do miejsca, w którym uzyskałem te informacje ... Nie znalazłem tego ponownie. Lepiej zredagować odpowiedź ...: / Aha, dzięki Seb.
FCastro
14

Jeśli ta funkcja znajduje się w module / klasie, możesz po prostu napisać je poza funkcją, więc tak jest Global Scope. Globalny zakres oznacza, że ​​zmienna może być dostępna przez inną funkcję w tym samym module / klasie (jeśli używasz dimjako deklaracji, użyj, publicjeśli chcesz, aby zmienne były dostępne dla wszystkich funkcji we wszystkich modułach):

Dim iRaw As Integer
Dim iColumn As Integer

Function find_results_idle()
    iRaw = 1
    iColumn = 1
End Function

Function this_can_access_global()
    iRaw = 2
    iColumn = 2
End Function
Zai
źródło
1

Utwórz publiczną liczbę całkowitą w deklaracji ogólnej.

Wtedy w swojej funkcji możesz za każdym razem zwiększać jej wartość. Zobacz przykład (funkcja zapisywania załączników wiadomości e-mail jako CSV).

Public Numerator As Integer

Public Sub saveAttachtoDisk(itm As Outlook.MailItem)
Dim objAtt As Outlook.Attachment
Dim saveFolder As String
Dim FileName As String

saveFolder = "c:\temp\"

     For Each objAtt In itm.Attachments
            FileName = objAtt.DisplayName & "_" & Numerator & "_" & Format(Now, "yyyy-mm-dd H-mm-ss") & ".CSV"
                      objAtt.SaveAsFile saveFolder & "\" & FileName
                      Numerator = Numerator + 1

          Set objAtt = Nothing
     Next
End Sub
Dan Bidner
źródło
1

Możesz również użyć -

Private Const SrlNumber As Integer = 910

Private Sub Workbook_Open()
    If SrlNumber > 900 Then
        MsgBox "This serial number is valid"
    Else
        MsgBox "This serial number is not valid"
    End If
End Sub

Jest testowany w pakiecie Office 2010

IshaniNet
źródło
0

Dobrym sposobem tworzenia zmiennych publicznych / globalnych jest traktowanie Form jak obiektu klasy i deklarowanie właściwości oraz użycie właściwości Public Property Get [zmienna] w celu uzyskania dostępu do właściwości / metody. Może być również konieczne odniesienie lub przekazanie odwołania do utworzonego modułu Form. Otrzymasz błędy, jeśli wywołasz metody do zamkniętych formularzy / raportów.
Przykład: przekaż Me.Form.Module.Parent do podrzędnej / funkcji poza formularzem.

Option Compare Database 
Option Explicit
''***********************************''
' Name: Date: Created Date Author: Name 
' Current Version: 1.0
' Called by: 
''***********************************''
' Notes: Explain Who what when why... 
' This code Example requires properties to be filled in 
''***********************************''
' Global Variables
Public GlobalData As Variant
''***********************************''
' Private Variables
Private ObjectReference As Object
Private ExampleVariable As Variant
Private ExampleData As Variant
''***********************************''
' Public properties
Public Property Get ObjectVariable() As Object
   Set ObjectVariable = ObjectReference
End Property 
Public Property Get Variable1() As Variant 
  'Recommend using variants to avoid data errors
  Variable1 = ExampleVariable
End property
''***********************************''
' Public Functions that return values
Public Function DataReturn (Input As Variant) As Variant
   DataReturn = ExampleData + Input
End Function 
''***********************************''
' Public Sub Routines
Public Sub GlobalMethod() 
   'call local Functions/Subs outside of form
   Me.Form.Refresh
End Sub
''***********************************''
' Private Functions/Subs used not visible outside 
''***********************************''
End Code

Więc w drugim module będziesz miał dostęp do:

Public Sub Method1(objForm as Object)
   'read/write data value
   objForm.GlobalData
   'Get object reference (need to add Public Property Set to change reference object)
   objForm.ObjectVariable
   'read only (needs Public property Let to change value)
   objForm.Variable1
   'Gets result of function with input
   objForm.DataReturn([Input])
   'runs sub/function from outside of normal scope
   objForm.GlobalMethod
End Sub

Jeśli używasz późnego wiązania, tak jak ja, zawsze sprawdzaj wartości Null i obiekty, które są Nothing, zanim spróbujesz wykonać jakiekolwiek przetwarzanie.

Podwójny procesor E.
źródło