如何使Excel VBA变量可用于多个宏?

时间:2013-05-04 12:23:06

标签: excel vba excel-vba

我有一串互相调用并引用工作簿A和B的宏。我希望第一个宏提示用户选择文档A和B,这些选择将成为我引用的工作簿A和B变量在各种宏中。

如何在所有宏中将所选文档作为引用变量?

提前致谢!

3 个答案:

答案 0 :(得分:24)

在子程序之外声明它们,如下所示:

Public wbA as Workbook
Public wbB as Workbook
Sub MySubRoutine()
    Set wbA = Workbooks.Open("C:\file.xlsx")
    Set wbB = Workbooks.Open("C:\file2.xlsx")
    OtherSubRoutine
End Sub
Sub OtherSubRoutine()
    MsgBox wbA.Name, vbInformation
End Sub

或者,您可以在子例程之间传递变量:

Sub MySubRoutine()
Dim wbA as Workbook
Dim wbB as Workbook
    Set wbA = Workbooks.Open("C:\file.xlsx")
    Set wbB = Workbooks.Open("C:\file2.xlsx")
    OtherSubRoutine wbA, wbB
End Sub
Sub OtherSubRoutine(wb1 as Workbook, wb2 as Workbook)
    MsgBox wb1.Name, vbInformation
    MsgBox wb2.Name, vbInformation
End Sub

或使用Functions 返回值

Sub MySubroutine()
    Dim i as Long
    i = MyFunction()
    MsgBox i
End Sub
Function MyFunction()
    'Lots of code that does something
    Dim x As Integer, y as Double
    For x = 1 to 1000
        'Lots of code that does something
    Next
    MyFunction = y
End Function

在第二种方法中,在OtherSubRoutine范围内,您可以通过参数名称wb1wb2来引用它们。传递的变量不需要使用相同的名称,只需要使用相同的变量类型。这允许你有一些自由,例如你有几个工作簿的循环,并且你可以将每个工作簿发送到子程序以在该工作簿上执行某些操作,而不需要创建所有(或任何)变量公开范围。

关于用户表单的说明

我个人建议在所有模块和表单中保留 Option Explicit(这可以防止您在名称中使用拼写错误实例化变量,例如lCoutn时{ {1}}等,以及其他原因)。

如果你正在使用lCount应该),那么你应该对模式范围的变量进行限定以避免歧义,并且必须限定用户形式的Option Explicit范围变量,因为它们在同一意义上不是“公共的”。例如,Public未定义,但在i范围内Public

enter image description here

您可以将其称为UserForm1以避免编译错误,或者因为表单是UserForm1.i - 能够,您可以创建一个变量对象来包含对表单的引用,并引用它方式:

enter image description here

注意:在上面的屏幕截图中,New在另一个标准代码模块中声明为x,并且不会引发编译错误。最好将其称为Public x as Long,以避免在重复使用变量名时出现歧义和可能的阴影......

答案 1 :(得分:5)

您可以考虑使用moudule级别范围声明变量。 模块级变量可用于该模块中的所有过程,但不适用于其他模块中的过程

有关Scope of variables的详细信息,请参阅此link

请将以下代码复制到任何模块中,保存工作簿,然后运行代码。

这是代码的作用

  • 示例子程序设置文件夹路径&以后的文件路径。在运行代码之前,请相应地设置它们。

  • 我添加了一个函数IsWorkBookOpen来检查工作簿是否已经设置工作簿变量工作簿名称 否则打开将相应分配给工作簿变量的工作簿。

Dim wbA As Workbook
Dim wbB As Workbook

Sub MySubRoutine()
    Dim folderPath As String, fileNm1 As String, fileNm2 As String, filePath1 As String, filePath2 As String

    folderPath = ThisWorkbook.Path & "\"
    fileNm1 = "file1.xlsx"
    fileNm2 = "file2.xlsx"

    filePath1 = folderPath & fileNm1
    filePath2 = folderPath & fileNm2

    If IsWorkBookOpen(filePath1) Then
        Set wbA = Workbooks(fileNm1)
    Else
        Set wbA = Workbooks.Open(filePath1)
    End If


    If IsWorkBookOpen(filePath2) Then
        Set wbB = Workbooks.Open(fileNm2)
    Else
        Set wbB = Workbooks.Open(filePath2)
    End If


    ' your code here
End Sub

Function IsWorkBookOpen(FileName As String)
    Dim ff As Long, ErrNo As Long

    On Error Resume Next
    ff = FreeFile()
    Open FileName For Input Lock Read As #ff
    Close ff
    ErrNo = Err
    On Error GoTo 0

    Select Case ErrNo
    Case 0: IsWorkBookOpen = False
    Case 70: IsWorkBookOpen = True
    Case Else: Error ErrNo
    End Select
End Function

使用提示选择文件使用以下代码。

Dim wbA As Workbook
Dim wbB As Workbook

Sub MySubRoutine()
    Dim folderPath As String, fileNm1 As String, fileNm2 As String, filePath1 As String, filePath2 As String

    Dim filePath As String
    cmdBrowse_Click filePath, 1

    filePath1 = filePath

    'reset the variable
    filePath = vbNullString

    cmdBrowse_Click filePath, 2
    filePath2 = filePath

   fileNm1 = GetFileName(filePath1, "\")
   fileNm2 = GetFileName(filePath2, "\")

    If IsWorkBookOpen(filePath1) Then
        Set wbA = Workbooks(fileNm1)
    Else
        Set wbA = Workbooks.Open(filePath1)
    End If


    If IsWorkBookOpen(filePath2) Then
        Set wbB = Workbooks.Open(fileNm2)
    Else
        Set wbB = Workbooks.Open(filePath2)
    End If


    ' your code here
End Sub

Function IsWorkBookOpen(FileName As String)
    Dim ff As Long, ErrNo As Long

    On Error Resume Next
    ff = FreeFile()
    Open FileName For Input Lock Read As #ff
    Close ff
    ErrNo = Err
    On Error GoTo 0

    Select Case ErrNo
    Case 0: IsWorkBookOpen = False
    Case 70: IsWorkBookOpen = True
    Case Else: Error ErrNo
    End Select
End Function

Private Sub cmdBrowse_Click(ByRef filePath As String, num As Integer)

    Dim fd As FileDialog
    Set fd = Application.FileDialog(msoFileDialogFilePicker)
    fd.AllowMultiSelect = False
    fd.Title = "Select workbook " & num
    fd.InitialView = msoFileDialogViewSmallIcons

    Dim FileChosen As Integer

    FileChosen = fd.Show

    fd.Filters.Clear
    fd.Filters.Add "Excel macros", "*.xlsx"


    fd.FilterIndex = 1



    If FileChosen <> -1 Then
        MsgBox "You chose cancel"
        filePath = ""
    Else
        filePath = fd.SelectedItems(1)
    End If

End Sub

Function GetFileName(fullName As String, pathSeparator As String) As String

    Dim i As Integer
    Dim iFNLenght As Integer
    iFNLenght = Len(fullName)

    For i = iFNLenght To 1 Step -1
        If Mid(fullName, i, 1) = pathSeparator Then Exit For
    Next

    GetFileName = Right(fullName, iFNLenght - i)

End Function

答案 2 :(得分:2)

创建一个“模块”对象并在那里声明变量。与每次必须实例化的类对象不同,模块对象始终可用。因此,“模块”中的公共变量,函数或属性将可用于VBA项目,宏,Excel公式中的所有其他对象,甚至是MS Access JET-SQL查询定义中的所有其他对象。