web-dev-qa-db-fra.com

Comment rendre les variables Excel VBA disponibles pour plusieurs macros?

J'ai une chaîne de macros qui s'appellent les unes les autres et se réfèrent aux classeurs A et B. Je veux que la première macro invite l'utilisateur à sélectionner le document A et B et ces sélections deviennent les variables du classeur A et B auxquelles je fais référence dans le diverses macros.

Comment faire des documents sélectionnés la variable référencée dans toutes les macros?

Merci d'avance!

11

Déclarez-les en dehors des sous-programmes, comme ceci:

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

Alternativement, vous pouvez passer des variables entre les sous-programmes:

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

Ou utilisez Functions pour renvoyer des valeurs:

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

Dans la deuxième méthode, dans le cadre de OtherSubRoutine, vous vous référez à eux par leurs noms de paramètres wb1 et wb2. Les variables transmises n'ont pas besoin d'utiliser les mêmes noms, juste les mêmes types de variables. Cela vous permet une certaine liberté, par exemple, vous avez une boucle sur plusieurs classeurs, et vous pouvez envoyer chaque classeur à un sous-programme pour effectuer une action sur ce classeur, sans faire tout (ou tout) de les variables publiques dans la portée.

Remarque sur les formulaires utilisateur

Personnellement, je recommanderais garderOption Explicit dans tous vos modules et formulaires (cela vous empêche d'instancier des variables avec des fautes de frappe dans leurs noms, comme lCoutn lorsque vous vouliez dire lCount etc., entre autres raisons).

Si vous utilisez Option Explicit (que vous devriez ), alors vous devez qualifier les variables de portée module pour le style et éviter toute ambiguïté, et vous doit qualifier les variables de portée utilisateur Public, car elles ne sont pas "publiques" dans le même sens. Par exemple, i n'est pas défini, bien qu'il soit Public dans le cadre de UserForm1:

enter image description here

Vous pouvez vous y référer comme UserForm1.i pour éviter l'erreur de compilation, ou puisque les formulaires sont New- capables, vous pouvez créer un objet variable pour contenir la référence à votre formulaire, et vous y référer de cette façon:

enter image description here

NB: Dans les captures d'écran ci-dessus, x est déclaré Public x as Long dans un autre standard module de code, et ne déclenchera pas l'erreur de compilation. Il peut être préférable de faire référence à cela comme Module2.x pour éviter toute ambiguïté et un éventuel ombrage si vous réutilisez des noms de variables.

26
David Zemens

Vous pouvez envisager de déclarer les variables avec une portée de niveau moudule. La variable de niveau module est disponible pour toutes les procédures de ce module, mais elle n'est pas disponible pour les procédures d'autres modules

Pour plus de détails sur Scope of variables référez-vous lien

Veuillez copier le code ci-dessous dans n'importe quel module, enregistrez le classeur, puis exécutez le code.

Voici ce que fait le code

  • L'exemple de sous-programme définit le chemin du dossier et plus tard le chemin du fichier. Veuillez les définir en conséquence avant d'exécuter le code.

  • J'ai ajouté une fonction IsWorkBookOpen pour vérifier si le classeur est déjà défini, puis définissez la variable de classeur le nom du classeur sinon ouvrez le classeur qui sera affecté à la variable de classeur en conséquence.

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

Utilisation de l'invite pour sélectionner le fichier à utiliser sous le code.

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
5
Santosh

Créez un objet "module" et déclarez-y des variables. Contrairement aux objets de classe qui doivent être instanciés à chaque fois, les objets de module sont toujours disponibles. Par conséquent, une variable publique, une fonction ou une propriété dans un "module" sera disponible pour tous les autres objets dans le projet VBA, la macro, la formule Excel ou même dans une définition de requête MS Access JET-SQL.

2
Steven