2013-05-04 4 views
9

У меня есть строка макросов, которые обращаются друг к другу и ссылаются на книги A и B. Я хочу, чтобы первый макрос предлагал пользователю выбрать документы A и B, а эти выборки - это переменные книги A и B, которые я называю в различных макросах.Как сделать переменные Excel VBA доступными для нескольких макросов?

Как сделать выбранные документы ссылкой на переменную во всех макросах?

Заранее благодарен!

ответ

20

Объявить их вне подпрограммах, как это:

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 

В th e second, в пределах OtherSubRoutine вы ссылаетесь на них по именам их параметров wb1 и wb2. Переданным переменным не нужно использовать одни и те же имена, одни и те же типы переменных. Это позволяет вам немного свободы, например, у вас есть цикл над несколькими книгами, и вы можете отправить каждой книге в подпрограмму, чтобы выполнить некоторые действия в этой книге, не делая все (или любые) из переменных общедоступными в области.

Замечание о пользовательских форм

Лично я бы рекомендовал держатьOption Explicit во всех ваших модулей и форм (это предотвращает вас от инстанцировании переменных опечаток в именах, как lCoutn, когда вы имели в виду lCount и т.д. ., среди других причин).

Если вы используете Option Explicit (который вы должны ), то вы должны квалифицироваться модуль-контекстные переменные стиля и, чтобы избежать двусмысленности, и вы должны квалифицироваться пользователем формы Public контекстные переменные, так как они не являются «общественность» в том же смысле. Например, i не определен, хотя это в рамках UserForm1Public:

enter image description here

Вы можете обратиться к нему как UserForm1.i, чтобы избежать ошибки компиляции, или поскольку формы New -able, вы можете создать объектная переменная содержит ссылку на форму, и ссылаться на него таким образом:

enter image description here

NB: в скриншотах выше x объявлен Public x as Long в другом стандартном модуле кода и не поднимет ошибку компиляции. Может быть предпочтительнее ссылаться на это как Module2.x, чтобы избежать неоднозначности и возможного затенения в случае повторного использования имен переменных ...

+1

+1: Можете упомянуть, что это работает для 'Public' в модулях. «Публикация» в классах, формах и рабочих листах несколько сложнее. – RBarryYoung

+0

У меня были проблемы с этим во время отладки - VBA продолжал говорить мне, что у меня были необъявленные переменные. Мне пришлось удалить Option Explicit из моих форм и модулей и определить только переменную Public в одном месте. Вероятно, очень простой, но я никогда не использовал переменную в 12 пользовательских формах и 2 модуля одновременно. – TheFontSnob

+0

@ TheFontSnob Да, как вы обнаружили, есть некоторые ограничения (@RBarryYoung намекает на это выше). Лично я бы рекомендовал * держать * 'Option Explicit' во всех ваших модулях и формах (это мешает вам создавать экземпляры переменных с опечатками в своих именах, например' lCoutn', если вы имели в виду 'lCount' и т. Д., Среди других причин). Если вы используете 'Option Explicit' (который вы ** должны **), тогда вы должны квалифицировать переменные с модульной областью для стиля, и вы ** должны ** квалифицировать переменные области с пользовательской формой, поскольку они не являются« общедоступными » «в том же смысле. –

5

Вы можете рассмотреть возможность объявления переменных с областью уровня расписания. переменная уровня модуля доступна для всех процедур в этом модуле, но он не доступен для процедур в других модулях

Для получения подробной информации о 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 

Использование Prompt для выбора использование файла ниже кода.

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

Создайте объект «module» и объявите здесь переменные. В отличие от объектов класса, которые должны быть созданы каждый раз, объекты модуля всегда доступны. Таким образом, общедоступная переменная, функция или свойство в «модуле» будут доступны для всех других объектов проекта VBA, макроса, формулы Excel или даже в рамках запроса MS Access JET-SQL.