如何在VBA中声明全局变量?

157

我写了以下代码:

Function find_results_idle()

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

我收到了以下错误信息:

"Sub或Function中的属性无效"

你知道我做错了什么吗?

我尝试使用Global代替Public,但是出现了同样的问题。

我尝试将函数本身声明为`Public`,但这也没有用。

我需要怎么做才能创建全局变量呢?

9个回答

202
你需要在函数外部声明变量:

你需要在函数外部声明变量:

Public iRaw As Integer
Public iColumn As Integer

Function find_results_idle()
    iRaw = 1
    iColumn = 1

2
当我尝试将数组声明为公共时,它会显示:数组和用户定义的数据类型不能声明为公共。 - kapilddit
4
在第一个Function/Sub之上,而不仅是在外部:_"模块级变量可以通过在模块顶部使用Dim或Private语句进行声明,在第一个过程定义的上方。"_(来自Visual Basic for Applications中变量的作用域 - Nickolay

136

这是有关于作用域的问题。

如果你只希望变量在函数生命周期内存在,可以在函数或子程序中使用 Dim(缩写为Dimension),声明变量:

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

全局变量(正如SLaks所指出的)是在函数之外使用Public关键字声明的。 这个变量将在您运行应用程序的生命周期内可用。 在Excel的情况下,这意味着只要特定的Excel工作簿打开,变量就会可用。

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.

你还可以使用Private关键字声明仅在特定模块(或类)内部可访问的变量。

如果您正在构建一个大型应用程序,并且感觉需要使用全局变量,我建议创建一个专门用于全局变量的单独模块。这将帮助您在一个地方跟踪它们。


4
7年后仍然有用。但是关于对象变量和数据变量是否有额外的细微差别?我遇到了一个与作用域对象变量相关的问题,促使我提出了一个新问题。如果您有时间看一下,将不胜感激。https://dev59.com/KKTja4cB1Zd3GeqPJOvQ - Egalth
我尝试了所有关于“作用域”的其他建议,但都没有起作用。唯一有效的方法是专门为全局变量创建一个新模块,它可以正常工作! - Fandango68

39

要使用全局变量,在VBA项目UI中插入新模块,并使用 Global 声明变量。

Global iRaw As Integer
Global iColumn As Integer

4
在声明变量时,使用 Public 关键字和使用 Global 关键字有什么区别? - Przemyslaw Remin
“Public”和“Global”的功能几乎相同.. “Global”来自较早版本的VB。 - Nickolay

25

这个问题实际上是关于范围的,就像那个人所说的那样。

简而言之,请考虑这个“模块”:

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). 

要了解更多关于变量声明的内容,可以参考这个MSDN 参考,对于变量超出作用域的情况,可以查看这个Stack Overflow 问题

另外还有两点需要注意:

  1. 在使用工作簿级变量时一定要组织好代码,以避免混淆。建议使用函数(带有正确的数据类型)或通过传递参数ByRef来实现。
  2. 如果您希望变量在调用之间保留其值,可以使用Static语句。

你确定全局变量可以在不同的工作簿中使用吗?对我来说行不通。 - Seb
好的观点!我注意到我没有为获取那些信息添加参考资料...也没有再次找到它。最好编辑答案... :/ 哦,谢谢Seb。 - FCastro

15
如果这个函数在一个模块/类中,你可以在函数外部编写它们,这样它就具有全局作用域。全局作用域意味着该变量可以被同一模块/类中的另一个函数访问(如果使用声明语句dim,请使用public,如果要使变量可以被所有模块中的所有函数访问):
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

3
您可以使用 -
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

它已在Office 2010上进行了测试


3

我认为最好的方法是将属性分配给工作簿

只要工作簿保持打开状态,它的范围就有效。

Public WhenOpened As Date

Private Sub Workbook_Open()
   ThisWorkbook.WhenOpened = Now()
End Sub

2

在General Declaration中创建一个公共整数。

然后在您的函数中,每次可以增加其值。 请参见示例(将电子邮件的附件保存为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

1
一个创建公共/全局变量的好方法是将表单视为类对象,并声明属性并使用Public Property Get [variable]来访问属性/方法。此外,您可能需要引用或传递实例化的表单模块的引用。如果调用已关闭的表单/报表的方法,则会出现错误。
示例:将Me.Form.Module.Parent传递到不在表单内部的子程序/函数中。
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

在另一个模块中,您将能够访问以下内容:
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

如果您像我一样使用晚绑定,请在尝试进行任何处理之前始终检查Null值和空对象。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接