Se connecter avec
S'enregistrer | Connectez-vous

Macro pour répertorier les dossiers d'un chemin d'accès

Dernière réponse : dans Programmation

Bonjour à tous
Je souhaiterais réaliser une macro sous Excel qui fournisse une liste des dossiers présents dans un répertoire donné, pour ensuite faire afficher cette liste dans un menu déroulant pour une cellule.
Après quelques recherches, j'ai trouvé une macro qui retourne la liste voulue

  1. Function ChercherRépertoire(MyPath) As Variant
  2. Dim MaListe() As String
  3. Dim a As Integer
  4. a = 0
  5. MyName = Dir(MyPath, vbDirectory)
  6. Do While MyName <> ""
  7.  
  8. If MyName <> "." And MyName <> ".." Then
  9.  
  10. If (GetAttr(MyPath & MyName) And vbDirectory) = vbDirectory Then
  11. ReDim Preserve MaListe(a)
  12. MaListe(a) = MyName
  13. a = a + 1
  14. End If '
  15. End If
  16. MyName = Dir
  17. Loop
  18. If a = 0 Then
  19. ReDim Preserve MaListe(0)
  20. MaListe(0) = "-----Aucun Projet-----"
  21. Else
  22. End If
  23.  
  24. ChercherRépertoire = MaListe
  25. End Function
  26.  
  27. Function RépertoireExiste(Chemin As String) As Boolean
  28. On Error Resume Next
  29. RépertoireExiste = GetAttr(Chemin) And vbDirectory
  30. If RépertoireExiste = True Then
  31. Exit Function
  32. Else
  33. MkDir (Chemin)
  34. End If
  35. End Function
  36. Private Sub Userform_initialize()
  37. Dim Liste As Variant
  38. Dim Répertoire As String
  39. Répertoire = "A:\Le_repertoir_où_faire_la_recherche\"
  40. Call RépertoireExiste(Répertoire)
  41. Liste = ChercherRépertoire(Répertoire)
  42.  
  43. End Sub


Mais je ne sais pas ensuite comment exploiter cette liste.
Merci de votre aide


(Par souci d'honnêteté voila l'origine du code
http://forum.hardware.fr/hfr/Programmation/VB-VBA-VBS/vba-excel-lister-sujet_83057_1.htm
Lassé par la pub ? Créez un compte

Meilleure solution

Expert Programmation

Eh, ce gros bricolage est ce que je voulais que tu nous proposes.
Pas question pour moi de faire ton boulot. Mais dès lors que c'est le produit de ton propre effort, je veux bien t'aider à l'améliorer. Et même à en faire quelque chose de très pro ;) 

------------------------------------------

Ma bien-nommée variable folder est un objet Folder, élément de la collection Folders.
C'est donc un objet qui propose plusieurs méthodes et attributs. L'attribut par défaut est Path, c'est pourquoi tu obtients la même chose que moi en ne rien précisant. Mais je préfère être explicite.
Et si on utilisait l'attribut Name plutôt ?

  1. Sub liste_projet()
  2. Const chemin = "D:\DONNEES\"
  3. Dim FSO As Object, folder As Object
  4.  
  5. Set FSO = CreateObject("Scripting.FileSystemObject" )
  6.  
  7. For Each folder In FSO.GetFolder(chemin).SubFolders
  8. MsgBox "Le sous-dossier courant est : " & folder.Path & "." & vbCrLf & "Son petit nom est : " & folder.Name & "."
  9. Next
  10.  
  11. End Sub


Bon maintenant, associer une validation à une cellule :
  1. Range("K15" ).Select
  2. With Selection.Validation
  3. .Delete
  4. .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _
  5. xlBetween, Formula1:="a;b;c;d;e"
  6. .IgnoreBlank = True
  7. .InCellDropdown = True
  8. .InputTitle = ""
  9. .ErrorTitle = ""
  10. .InputMessage = ""
  11. .ErrorMessage = ""
  12. .ShowInput = True
  13. .ShowError = True
  14. End With
Beurk :vomi: 

Alors déjà, quand je vois un Select suivi d'un Selection, je condense ! (cherche sur ce site pourquoi... allez...)
Et je retire le With, parce que ça me perturbe quelque peu.
Et puis il ne faut pas mettre des points-virgules, mais des virgules... Merci l'enregistreur de macro :pfff: 
Tu peux essayer de relancer ta macro, tu n'obtiendras pas le résulat escompté.

Ca donne :
  1. Range("K15" ).Validation.Delete
  2. Range("K15" ).Validation.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:=xlBetween, Formula1:="a,b,c,d,e"
  3. Range("K15" ).Validation.IgnoreBlank = True
  4. Range("K15" ).Validation.InCellDropdown = True
  5. Range("K15" ).Validation.InputTitle = ""
  6. Range("K15" ).Validation.ErrorTitle = ""
  7. Range("K15" ).Validation.InputMessage = ""
  8. Range("K15" ).Validation.ErrorMessage = ""
  9. Range("K15" ).Validation.ShowInput = True
  10. Range("K15" ).Validation.ShowError = True
Ligne 1, on supprime la validation précédente avant d'en ajouter une nouvelle. C'est prudent.
Ligne 2, on ajoute donc notre liste.
Pour le reste, il semble que ce soient des valeurs par défaut. Bon.

Je vire tout ce qui n'est pas inutile :
  1. Range("K15").Validation.Delete
  2. Range("K15").Validation.Add xlValidateList, , xlBetween, Formula1:="a,b,c,d,e"

Ah bah ça fait du ménage.

Juste une petite vérif :
  1. Range("K15").Validation.Delete
  2. Range("K15").Validation.Add xlValidateList, , xlBetween, Formula1:="a,b,c,d,e,"
J'ai laissé une virgule en trop à la fin. Ca n'a pas l'air de le déranger. :whistle: 

On reprend avec la boucle sur les sous-dossiers :
  1. Const chemin = "D:\DONNEES\"
  2.  
  3. Dim FSO As Object, folder As Object
  4. Dim chaine As String
  5.  
  6. Range("K15").Validation.Delete
  7. Set FSO = CreateObject("Scripting.FileSystemObject" )
  8.  
  9. chaine = "" ' // Attention, avec VB. On n'est sûr de rien.
  10. For Each folder In FSO.GetFolder(chemin).SubFolders
  11. chaine = chaine & folder.Name & ","
  12. Next
  13.  
  14. Range("K15").Validation.Add xlValidateList, , xlBetween, Formula1:=chaine


Alors, ne t'avais-je pas dis que c'était simple :sol: 
Expert Programmation

Salut,

Mouhais, code archaïque, quand même.
Voici quelque chose de plus moderne, plus simple et plus clair :
  1. Dim FSO As Object, folder As Object
  2. Set FSO = CreateObject("Scripting.FileSystemObject")
  3.  
  4. For Each folder In FSO.GetFolder("C:\DONNEES").SubFolders
  5. MsgBox folder.Path
  6. Next


Maintenant, aide-toi : branche l'enregistreur de macro et configure à la main ta cellule. Arrête l'enregistrement et étudies-en le code. Le plus dur est de coupler ce code, et le précédent - celui que je te propose ou celui de hardware, au choix. On peut d'aider :) 

Puissant :) 
Aux vues du code enregistré, je dois créer une èspece de liste de charactères par concaténation du style "Dossier1;Dossier2"..." et placer cette chaine dans le champ approprié ("Formula1")
Le tout est de pouvoir extraire simplement les noms de dossier (avec Dir) et de créer cette concatenation. J'avoue ne pas avoir beaucoups d'idées quant à ça...
Expert Programmation

Euh, pas d'accord du tout.

Que te propose l'enregistreur de macro (attention, code moche) ?

Citation :
Le tout est de pouvoir extraire simplement les noms de dossier et de créer cette concatenation. J'avoue ne pas avoir beaucoups d'idées quant à ça...

Ça me semble pourtant très facile ! Au lieu de mettre un MsgBox comme dans mon exemple, tu réalises la concaténation :spamafote: 

Mon problème étant de ne pas savoir exactement quel objet est renvoyé par la ligne :
  1. For Each folder In FSO.GetFolder("C:\DONNEES" ).SubFolders
  2. MsgBox folder.Path

Parce qu'en enlevant le ".path" accolé au "folder", la Msgbox renvoie aussi le chemin. Et je voudrais extraire juste les noms de dossier ("MsgBox avec Dir ne renvoient rien)

Ah et e code renvoyé par l'enregistreur est:
  1. Sub enregistrement()
  2. Range("K15").Select
  3. With Selection.Validation
  4. .Delete
  5. .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _
  6. xlBetween, Formula1:="a;b;c;d;e"
  7. .IgnoreBlank = True
  8. .InCellDropdown = True
  9. .InputTitle = ""
  10. .ErrorTitle = ""
  11. .InputMessage = ""
  12. .ErrorMessage = ""
  13. .ShowInput = True
  14. .ShowError = True
  15. End With
  16. End Sub


C'est à la place de "a;b;c;d;e" que je comptais placer ma chaine...

Attention gros bricolage :) 
  1. Public Const Chemin2 = "D:\DONNEES\"
  2.  
  3. Sub liste_projet()
  4. Dim FSO As Object, folder As Object
  5. Dim chaine As String
  6. Set FSO = CreateObject("Scripting.FileSystemObject")
  7. For Each folder In FSO.GetFolder(Chemin2).SubFolders
  8. chaine = chaine + ";" & Right(folder, Len(folder) - Len(Chemin2))
  9. Next
  10. chaine = Right(chaine, Len(chaine) - 1)

End Sub
Expert Programmation

Bon alors pour aller plus loin, on va non plus se baser sur des objets aléatoires, mais au contraire, se baser sur des objets bien définis.

Dans le menu Outils/Références de l'éditeur VBA, on va ajouter Windows Script Host Object Model. Ça pointe en fait sur la bibliothèque IWshRuntimeLibrary définie dans le fichier %windir%\System32\wshom.ocx.

Maintenant, on peut utiliser de vrais objets :
  1. Option Explicit
  2.  
  3. ...
  4.  
  5. Const chemin = "D:\DONNEES\"
  6.  
  7. Dim FSO As New FileSystemObject
  8. Dim fldr As Folder
  9. Dim filelist As String
  10.  
  11. Range("K15").Validation.Delete
  12.  
  13. filelist = ""
  14. For Each fldr In FSO.GetFolder(chemin).SubFolders
  15. filelist = filelist & fldr.Name & ","
  16. Next
  17.  
  18. Range("K15").Validation.Add xlValidateList, , xlBetween, Formula1:=filelist


Enjoy!

Merci pour le petit cours :) 
Citation :
Pas question pour moi de faire ton boulot


mais tu m'as quand même vraiment bien aidé, et je t'en remercie sincèrement, ne serait-ce que pour le temps que tu as passé à écrire tout ça !
En revanche je n'ai pas vraiment saisi l’intérêt de la dernière manip...

Expert Programmation

Ce site est un forum d'entraide. :spamafote: 

Je te propose une solution, puis des éléments pour aller plus loin.

Tu te demandais "Mon problème étant de ne pas savoir exactement quel objet est renvoyé par la ligne ..."

Si tu définis ton objet explicitement, plus de problème, tu sais exactement de quoi tu parles. En plus, tu peux obtenir de l'aide de VBA directement au cours de la frappe :

1° Référence Windows Script Host Object Model
2° Déclare une variable de type Folder :
  1. Dim fldr As Folder

3° Tape sur une nouvelle ligne le nom de ta variable suivi d'un point :
  1. fldr.
Et là, une petite fenêtre s'ouvre pour te proposer toutes les méthodes et tous les attributs possibles pour ton objet. L'écriture du code en est grandement simplifier, tu ne trouves pas ?
Lassé par la pub ? Créez un compte