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!
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
:
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:
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.
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
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.