Faire rapparaitre un onglet caché dans les fichiers d'un dossier (VBA)

Faire rapparaitre un onglet caché dans les fichiers d'un dossier (VBA) - VB/VBA/VBS - Programmation

Marsh Posté le 05-01-2015 à 16:15:51    

Bonjour,
 
Tout d'abord je vous souhaite une bonne année 2015 et vous remercie pour l'aide que vous apportez.
 
Pour un de mes besoins, j'ai trouvé et adapaté une macro permettant d'ouvrir plusieurs fichiers contenus dans un dossier. C'est à dire que la macro ouvre tous les fichiers contenus dans le dossier actif.
 
Ce que je souhaiterais, c'est qu'un onglet ("Données" ) présent dans chaque fichier et caché préalablement via macro rapparaisse. Je vais joindre le code ci-dessous pour plus de clareté. A savoir qu'à ce jour, la macro ne fait apparaitre l'onglet("données" ) que sur un fichier sur les deux (meme chose avec trois ou un plus grand nombre de fichier).
 
Pourriez vous me corriger afin que la macro fasse apparaitre l'onglet macro sur tous les fichiers (mis à part le fichier "Résultats sondage.xls" ) et non un seul ?
 

Code :
  1. Sub Ouvre_Fichier2()
  2. Dim Wk As Object
  3. Dim rep As Object
  4. Dim Chemin As String
  5. Chemin = ThisWorkbook.Path
  6. Set rep = CreateObject("Scripting.FileSystemObject" ).GetFolder(Chemin)
  7. For Each Wk In rep.Files
  8.     If Wk.Name <> "Résultats sondage.xls" Then Workbooks.Open Filename:=Wk
  9. Next
  10. For Each Wk In Workbooks 'si je mets rep.files à la place de workbooks, le probleme est le meme
  11.     If Wk.Name <> "Résultats sondage.xls" Then Worksheets("Données" ).Visible = True
  12. Next
  13. End Sub


 
Le probleme se situe aux lignes de code 15 et 16
 
En vous remerciant.
 
Yannick


Message édité par yanounou91 le 05-01-2015 à 20:32:45
Reply

Marsh Posté le 05-01-2015 à 16:15:51   

Reply

Marsh Posté le 05-01-2015 à 16:46:24    

 
           Bonjour,
 
           il manque la référence au classeur devant la feuille en ligne n°16 …
 

Reply

Marsh Posté le 05-01-2015 à 17:50:45    

Bonjour Marc L,
 
Merci pour la réponse. Que faut il entendre par référence au classeur devant la feuille ?
 
Dans le sens où je ne veux pas lui indiquer un classeur particulier mais je voudrais que rapparaisse l'onglet ("Données" ) présents dans chaque classeurs. Et ce pour chaque classeur, sans avoir à le nommer.
 
Sur les lignes 10 et 11, VBA fait bien l'action d'ouvrir tous les classeurs sans lui en spécifier les noms.
 
Cordialement.

Reply

Marsh Posté le 05-01-2015 à 20:35:14    

Et ce qui est etrange c'est que le code ne me renvoie pas d'erreur. Mais seulement il ne va faire l'action de faire rapparaitre l'onglet caché ("Données" ) que pour un des fichiers. Et ce, que j'en mette deux, cinq ou dix.  
 
 
Il y a le classeur ("Résultats sondage.xls" ) d'où j'actionne la macro. C'est la feuille active je pense. En tout cas je ne veux pas que le code fasse quoi que se soit sur ce classeur. Et de toute facon il n'y a pas d'onglet ("Données" ) dans cette feuille. Ensuite il y a un certain nombre de classeurs dont chacun comprend un onglet caché nommé ("Données" ) que je veux faire rapparaître avec la Macro.
 
Entre temps, je médite sur votre remarque.
 
Yannick


Message édité par yanounou91 le 05-01-2015 à 20:40:46
Reply

Marsh Posté le 06-01-2015 à 08:26:45    

 
           Ce n'est pas étrange du tout et l'absence d'erreur est tout à fait normale !       C'est le B-A-BA d'Excel : sa hiérarchie objet …
           Et sans respecter cela, à quoi bon d'entreprendre de coder la moindre ligne !
           Hiérarchie Excel : application / classeur / feuille / cellule / méthode ou propriété …
 
           Et puis c'est même indiqué noir sur blanc dans l'aide VBA intégrée, même pas besoin de parcourir le net !
 
           Dans le code, placer le curseur texte sur Worksheets puis appuyer sur la touchehttp://www.developpez.net/forums/images/smilies/f1.gif !
           Lire l'aide de la propriété comme celle de la collection …
 
           Sinon, rien qu'en traduisant en français la ligne de code n°16, alors ?
 

Reply

Marsh Posté le 06-01-2015 à 14:29:38    

Bonjour,
 
Merci pour votre réponse.  
Le soucis est que chez moi l'aide ne fonctionne pas, VBA me dit que ce n'est pas installé dans ma version de VBA 2007. Et je n'ai plus le CD d'installation ...
 
En revanche, au boulot, je peux le faire. Quand je clique sur F1 (en etant sur worksheets), cela me propose une multitudes de choses. En cherchant, je trouve que la propriété worksheets ne renvoie qu'un seul élément.
 
Cela veut dire que malgré mon "FOR .. EACH" je ne peux requeter sur l'ensemble des feuilles. Donc je ne dois pas appliquer mon "FOR .. EACH" à worksheets.
 
Je n'ai pas trouvé l'aide sur la collection mais est ce que mon raisonnement est juste ?
 
Cordialement.
 
 
Yannick

Reply

Marsh Posté le 06-01-2015 à 17:34:47    

 
            Donc en lisant bien l'aide de la propriété Worksheets même au boulot, c'est clairement indiqué !
            Sinon l'aide est disponible aussi sur un site Microsoft …
 
            Quelle est donc la traduction de la ligne n°16 en langage courant en français ?
            A ne pas confondre avec ce qu'elle est censée réaliser …
 
            Car tout le problème est là, VBA ne se trompant jamais, interprétant la sémantique écrite au travers d'une procédure,
            s'il n'y a pas de message d'erreur et si le résultat n'est pas celui escompté, le problème se situe entre la chaise et le clavier !
            La formulation est donc fausse et ce, dans 99,99% des cas, d'où l'importance de la signification de cette ligne n°16 …
 
            Et cela c'est vraiment le B-A-BA en programmation : vérifier la sémantique, comparer avec l'aide, …
            Un amateur éclairé met dix secondes maximum pour trouver l'erreur, un grand débutant ne doit pas dépasser cinq minutes.
 
            Et pour rappel :

Marc L a écrit :

il manque la référence au classeur devant la feuille en ligne n°16 …

            Dans la traduction de cette ligne n°16, la feuille en question fait référence à quel classeur ?
 
            Et dans le but recherché, quel est le classeur visé ?
 
            Ce sont là les questions que le développeur doit se poser avant d'entamer sa première ligne de code …
 

Reply

Marsh Posté le 06-01-2015 à 18:31:13    

Bonsoir,
 
Je me doute bien que le soucis vient de moi. Je me sens de plus en plus nul ... mais je ne renonce pas.
 
La traduction de ma ligne 16 me semble etre :
 
Si le nom objet Wk (Wk etant un objet du dossier courant, donc un classeur) est différent de "Résultats sondage.xls" ensuite onglet ("Données" ) visible égale vrai.
 
Je vais continuer à chercher en rentrant. car quand je mets des éléments devant "Worksheets" pour tenter de lui donner une référence, je n'ai que des erreurs pour le moment. Il faut qu'il agisse sur toutes les classeurs mais sans lui donner un nom précis car leur nombre peut varier.
 
Merci pour votre aide malgré mon manque de maitrise
 
Yannick

Reply

Marsh Posté le 06-01-2015 à 19:03:28    

 
            Presque mais pas tout à fait cela !
 
            Traduction littérale de la ligne n°16 :
 
            Si le nom de l'objet Wk est différent de "Résultats …" alors la feuille "Données" du classeur actif devient visible.
 
            C'est écrit noir sur blanc dans l'aide quand rien ne référence Worksheets ! Rappel aussi vers la hiérarchie objet d'Excel …
            Et quel est donc le classeur actif ? Le dernier classeur ouvert !
 
            Donc retour à la solution :

Marc L a écrit :

il manque la référence au classeur devant la feuille en ligne n°16 …

            Quel référence de classeur faut-il donc faire précéder la feuille ?
 
 
            Maintenant c'est un peu idiot d'effectuer deux boucles sur la même condition, la deuxième est vraiment inutile !
            Une fois le classeur ouvert dans la première, rendre visible sa feuille et de plus, c'est le classeur actif ‼
 

Reply

Marsh Posté le 06-01-2015 à 23:44:37    

Bonsoir,
 
J'ai toujours une erreur et pourtant j'ai essayé de référencer de multiples manière mon éléments Worsheets pour lui appliquer son classeur ...
 
Je sais aussi que vous avez justement indiqué de ne pas faire la deuxième boucle, mais avant de faire cela je voudrais comprendre et reussir à la faire fonctionner.
 
Voici mon code modifié apres avoir lu les aides et tenter d'appliquer vos conseils :
 

Code :
  1. Sub Ouvre_sondages()
  2. Dim Wk As Object
  3. Dim rep As Object
  4. Dim Chemin As String
  5. Chemin = ThisWorkbook.Path
  6. Set rep = CreateObject("Scripting.FileSystemObject" ).GetFolder(Chemin)
  7. For Each Wk In rep.Files
  8.     If Wk.Name <> "Résultats sondage.xls" Then Workbooks.Open Filename:=Wk
  9. ActiveWindow.DisplayWorkbookTabs = True
  10. Next
  11.    
  12. Dim Wk1 As Workbook
  13. For Each Wk1 In Application.Workbooks
  14. For Each Worksheet In Wk1.Worksheets
  15. If Worksheet.Name <> "Résultats sondage.xls" Then Wk1.Worksheets("Données" ).Visible = True
  16. Next
  17. Next
  18. End Sub


 
Il y a toujours (ligne code 19), pourriez vous me dire ce qui cloche dans ma référence au classeur pour la Worksheets ?
 
Le probleme vient peut etre du fait que je ne peux nommer le classeur car je ne connais pas forcément leurs noms et surtout leurs nombres.
 
Merci.
 
 
Yannick

Reply

Marsh Posté le 06-01-2015 à 23:44:37   

Reply

Marsh Posté le 07-01-2015 à 09:22:22    

 
           Là c'est l'horreur en ligne n°19 : confusion entre un objet feuille de calculs et le nom d'un classeur !  :pt1cable:
 
           If Worksheet.Name <> "Résultats sondage.xls"
 
           Enfin la feuille "Données" est bien référencée par un objet classeur, c'était bien la solution  
           mais la boucle sur les feuilles de calculs est inutile !
           
           Et attention de ne pas nommer une variable comme un élément de langage existant déjà (Worksheet) !
 
           
           

Reply

Marsh Posté le 07-01-2015 à 23:15:50    

Bonsoir,
 
Ma ligne 16 est toujours fausse ... Mais je pense avoir bien suivi (en partie) vos conseils en épurant le code de la boucle inutile sur les feuilles et en supprimant la confusion entre nom classeur et objet feuille.
 
Mais VBA m'indique que mon indice ne fait pas partie de la sélection ... et pourtant la feuille (l'onglet) "Données" existe bien dans tous les classeurs (sauf le "Résultats sondage.xls" normalement exclu du test de la boucle).
 
Pourriez vous me dire ce qui ne va pas dans la référence au classeur ? Est ce que le fait que l'onglet "Données" ait été masqué par une macro initialement peut provoquer un autre probleme ?
 

Code :
  1. Sub Ouvre_Fichier2()
  2.     Dim Wk As Object
  3.     Dim rep As Object
  4.     Dim Chemin As String
  5.     Chemin = ThisWorkbook.Path
  6.     Set rep = CreateObject("Scripting.FileSystemObject" ).GetFolder(Chemin)
  7.     For Each Wk In rep.Files
  8.         If Wk.Name <> "Résultats sondage.xls" Then Workbooks.Open Filename:=Wk
  9.     Next
  10.   Dim Wk1 As Workbook
  11.   For Each Wk1 In Application.Workbooks
  12.   If Wk1.Name <> "Résultats sondage.xls" Then Wk1.Sheets("Données" ).Visible = True 'meme chose avec Worksheets au lieu de Sheets
  13.   Next
  14.   End Sub


 
En vous remerciant (de nouveau).
 
Yannick

Reply

Marsh Posté le 08-01-2015 à 08:44:01    

 
           Ligne n°16 : If Wk1.Name <> "Résultats sondage.xls" Then Wk1.Sheets("Données" ).Visible = True
 
           Cette ligne me semble tout à fait correcte … Vu le message d'erreur (correspondant à l'erreur #9 ?),
           le classeur pointé par la variable objet Wk1 n'a pas de feuille de calculs nommée Données … (attention à l'orthographe)
 
           Sinon modifier la ligne n°15 : Debug.Print Wk1.Name permettant d'afficher dans la fenêtre Exécution du VBE (Ctrl G).
           Donc lors du message d'erreur, le dernier nom de classeur affiché dans cette fenêtre n'a pas de feuille de calculs Données
 
           Encore une fois, les lignes n°10 à 18 sont inutiles, remonter juste l'affichage de la feuille au sein du test de la première boucle …
 
           ________________________________________________________________________________________________________
           Hebdo du jour : je suis Charlie
 

Reply

Marsh Posté le 08-01-2015 à 13:53:58    

Bonjour,
 
Merci pour votre réponse.
 
Mon message d'hier a été posté car effectivement j'avais une erreur d'execution 9 (et pourtant pas de soucis d'orthographe ...). Sachant que chez moi j'ai VBA 2007.
 
En revanche en utilisant le meme code (avec ou sans rajouter Debug.Print Wk1.Name ) au boulot cela fonctionne ... A savoir que j'ai VBA 2010 sur le poste.
 
Je vais maintenant tester en enlevant les lignes 10 à 18 inutiles.
 
Mais pourriez vous m'expliquer pourquoi ce code (correcte comme vous l'avez dit) fonctionne sur VBA 2010 et pas sur VBA 2007 ?
 
En vous remerciant.
 
Yannick

Reply

Marsh Posté le 08-01-2015 à 15:54:24    


Bonjour,
 
Me revoici.
 
Déjà, je viens de lire sur le net et comprendre l'utilité de Debug, je regarderai chez moi pourquoi avec les memes fichier cela peut bloquer sur mon VBA 2007.
 
Sinon, en voulant enlever les lignes inutiles du code 10 à 18, je me heurte à la difficulté d'exécuter deux action apres ma condition IF. Voici le code :
 

Code :
  1. Sub Ouvre_Fichier2()
  2. Dim Wk As Object
  3. Dim rep As Object
  4. Dim Chemin As String
  5. Dim Wk1 As Workbook
  6. Chemin = ThisWorkbook.Path
  7. Set rep = CreateObject("Scripting.FileSystemObject" ).GetFolder(Chemin)
  8. For Each Wk In rep.Files
  9.     If Wk.Name <> "Résultats sondage.xls" Then Workbooks.Open Filename:=Wk: Wk1.Sheets("Données" ).Visible = True 'j'ai aussi utiliser Wk au lieu de Wk1 pour voir mais meme erreur.
  10.    
  11. Next


 
J'ai un probleme de variable non définie sur la ligne 13.
 
Pourriez vous me dire si c'est mes ":" qui posent probleme. J'ai lu sur le net que cela peut permettre d'enchainer une deuxième action dans une condition.
Merci
 
 
yannick

Reply

Marsh Posté le 08-01-2015 à 16:24:39    

 
           Les deux points ne gênent pas …
           Le message d'erreur est pourtant clair : variable non définie, donc l'erreur concerne une variable !
 
           Évidemment en lisant la ligne de code n°13, il y a deux variables différentes, dont l'une est en trop ‼
           Wk1 n'existant pas …
 
           Et comme je l'ai pourtant déjà indiqué, une fois un classeur ouvert, c'est le classeur actif, donc pas besoin de variable ‼
 
           Qui plus est la variable objet Wk ne pointe pas du tout sur un classeur ouvert ‼ Un peu de rigueur …
 
           _______________________________________________________________________________________________
           Tous unis, tous Charlie


Message édité par Marc L le 13-01-2015 à 12:11:50
Reply

Marsh Posté le 08-01-2015 à 22:21:47    

Merci à vous ....
 
La fonction debug.print m'a permis de voir que chez moi (VBA 2007) le classeur "Personal.xlsb" est pris dans la boucle. Alors qu'au boulot (poste avec VBA 2010), la boucle ne testait pas le classeur "Personal.xlsb" et ne posait donc pas de problème d'indice (exécution 9). En fait je pense meme que ce n'est pas la version de VAB qui est en cause mais n'ayant pas réussi à supprimer ce classeur, je l'ai inclu dans la boucle au cas où.
 
Je me rends vraiment compte de mon manque de rigueur mais finalement voici le code final :
 

Code :
  1. Sub Ouvre_Fichier2()
  2. Dim Wk As Object
  3. Dim rep As Object
  4. Dim Chemin As String
  5. Chemin = ThisWorkbook.Path
  6. Set rep = CreateObject("Scripting.FileSystemObject" ).GetFolder(Chemin)
  7. For Each Wk In rep.Files
  8.     If Wk.Name <> "Résultats sondage.xls" And Wk.Name <> "PERSONAL.XLSB" _
  9.     Then Workbooks.Open Filename:=Wk: Sheets("Données" ).Visible = True
  10. Next
  11. End Sub


 
Je vais tenter pour finir de copier les éléments de l'onglet ("Données" ) de tous les classeurs et en copier les valeurs dans une feuille du classeur "Résultat sondage.xls". Le but etant de créer une base de données de tous les sondages.
 
 
 
Merci

Reply

Marsh Posté le 08-01-2015 à 23:12:22    

 
           Bien, cela avance ! Et maintenant avec une bonne expérience de débogage …
 
           A mon avis, il faudrait mieux mettre le test dans un bloc If … Then … End If
           car une fois la feuille de calculs affichée, autant copier ses données à la volée …
 
 

Reply

Marsh Posté le 09-01-2015 à 01:04:27    

Bonsoir,

 

Quand vous dites intégrer le test dans un bloc IF then end if, cela veut dire le bloc If + la boucle ?

 

Le IF then end IF revient à se dire : si condition vrai alors action sinon autre action. C'est bien l'idée?

 

J'ai testé quelques codes qui ne fonctionnent pas du tout mais à mon avis un peu de sommeil me fera du bien.

 

Yannick


Message édité par yanounou91 le 09-01-2015 à 22:17:59
Reply

Marsh Posté le 09-01-2015 à 10:22:03    

 
           Oui, hors boucle, juste pour intégrer la copie des données …
 

Reply

Marsh Posté le 09-01-2015 à 22:20:47    

J'ai un peu de mal à imaginer en français la condition à ajouter autour de celle déjà présente pour copier les données. La condition deja présente doit être une action du nouveau bloc If ?
 
Cordialement.
 
yannick

Reply

Marsh Posté le 10-01-2015 à 02:47:56    

Bonsoir,
 
N'ayant pas réussi à concevoir le bloc IF Then dans ma condition, j'ai pensé refaire une autre condition avec un test.
 
Dans ce teste, j'ai repris la structure de la première en essayant d'appliquer vos conseils mais VBA me renvoie une erreur.
 
VBA me renvoie "propriété non gérée par l'objet". Grâce au Debug.print, je vois que VBA Bute dès le premier fichier dont il faut consolider la plage de l'onglet "Données".
 
Le soucis est aux lignes 26 à 27 ... Pourriez vous me montrer la voie ?
 
 
 

Code :
  1. Sub Ouvre_Fichier2()
  2. Dim Wk As Object
  3. Dim rep As Object
  4. Dim Chemin As String
  5. Chemin = ThisWorkbook.Path
  6. Set rep = CreateObject("Scripting.FileSystemObject" ).GetFolder(Chemin)
  7. For Each Wk In rep.Files
  8. 'Debug.Print Wk.Name
  9.     If Wk.Name <> "Résultats sondage.xls" And Wk.Name <> "PERSONAL.XLSB" _
  10.     Then Workbooks.Open Filename:=Wk: Sheets("Données" ).Visible = True
  11. Next
  12.  
  13.   For Each Wk In rep.Files
  14.   Debug.Print Wk.Name
  15.   If Wk.Name <> "Résultats sondage.xls" And Wk.Name <> "PERSONAL.XLSB" Then _
  16.   Wk.Sheets("Données" ).Range(Cells(2, 1), Cells(18, 9)).Copy Destination:=Workbooks _
  17.   ("Résultats sondage.xls" ).Sheets("Conso données" ).Range("A2" ).End(xlDown)
  18.  
  19.   Next
  20. EnD Sub


 
Merci.
 
Yannick

Reply

Marsh Posté le 10-01-2015 à 14:08:49    

 
          Je ne comprends pas ! Dans tes précédentes discussions il y a bien des blocs If … Then … End If !
          Et puis rien qu'en lisant l'aide VBA intégrée concernant cette instruction ! …
 
          L'erreur est en ligne n°23 : en dehors du fait de l'idiotie d'une seconde boucle tout à fait inutile,
          comparer torchons & serviettes ne peut effectivement rien donner de bon !
          Que représente Wk ? Pas un classeur ouvert en tout cas ‼ D'où l'erreur en ligne 26 …
 

Code :
  1. Sub Demo()
  2.       Dim Rg As Range
  3.       Set Rg = Workbooks("Résultats sondage.xls" ).Worksheets("Conso données" ).Range("A2" )
  4.     DOSSIER$ = ThisWorkbook.Path & ""
  5.     FICHIER$ = Dir(DOSSIER & "*.xls" )
  6.     Do While (FICHIER > "" And FICHIER <> "Résultats sondage.xls" )
  7.         With Workbooks.Open(DOSSIER & FICHIER).Worksheets("Données" )
  8.             .Visible = True
  9.             .Range("A2:I18" ).Copy Rg.End(xlDown)(2)
  10.         End With
  11.         FICHIER = Dir
  12.     Loop
  13.     Set Rg = Nothing
  14. End Sub


           Les variables Rg & DOSSIER servent juste à la lisibilité du code …
 
           ___________________________________________________________________________________________________
           Nous sommes Charlie


Message édité par Marc L le 13-01-2015 à 12:14:17
Reply

Marsh Posté le 10-01-2015 à 16:23:12    

Bonjour,
 
Avant de tester votre solution qui enlève mon test inutile, j'essaie tout de même de réparer mon code comme posté hier pour bien comprendre. Et suivre les conseils de votre message du (08-01-2015 à 23:12:22).
 
 
J'ai retiré la deuxième boucle inutile, en revanche je sais que ce n'est pas parfait car je n'ai pas utilisé le "End If" que je n'arrive pas à placer ...
 
Le code suivant fonctionne, mais sur les deux feuilles utilisées comme base pour copier la plage de l'onglet ("Données" ), l'une d'entre elles est copiée deux fois (au lieu d'une) sur l'onglet ("Conso_données" ) ...
 
Auriez vous une piste ? Sachant que je semble proche du but et qu'ensuite je testerai si tout va bien en ajoutant plus feuilles sources avec un onglet ("Données" ).  
 

Code :
  1. Sub Ouvre_Fichier2()
  2. Dim Wk As Object
  3. Dim rep As Object
  4. Dim Chemin As String
  5. Range("A2:I10000" ).Select
  6. Selection.ClearContents
  7. Chemin = ThisWorkbook.Path
  8. Set rep = CreateObject("Scripting.FileSystemObject" ).GetFolder(Chemin)
  9. For Each Wk In rep.Files
  10.     If Wk.Name <> "Résultats sondage.xls" And Wk.Name <> "PERSONAL.XLSB" _
  11.     Then Workbooks.Open Filename:=Wk: Sheets("Données" ).Visible = True
  12.    
  13.      If Wk.Name <> "Résultats sondage.xls" And Wk.Name <> "PERSONAL.XLSB" Then _
  14.   Sheets("Données" ).Range("A2:I18" ).Copy
  15.  
  16.   Workbooks("Résultats sondage.xls" ).Activate
  17. ActiveWorkbook.Sheets("Conso_données" ).Range("A10000" ).End(xlUp).Offset(1, 0).Select
  18.   ActiveSheet.Paste
  19. Next
  20. End Sub


 
Cordialement
 
Yannick


Message édité par yanounou91 le 10-01-2015 à 19:21:56
Reply

Marsh Posté le 10-01-2015 à 19:22:58    

Merci pour l'aide en tout cas. Le fait d'y aller par étape me permet de progresser un peu.

Reply

Marsh Posté le 10-01-2015 à 20:23:00    

 
           Lire l'aide VBA de l'instruction If … Then … End If comme les codes de tes précédents sujets, c'est pas compliqué ‼
 
           La grosse erreur se situe principalement dans les lignes n°27 à 31 s'exécutant sans contrôle !
           Rappel : un bon code n'utilise pas d'Activate ni de Select !
 

Code :
  1. Sub Ouvre_Fichier2revu()
  2.     Dim Rg As Range, Wk As Object
  3.     Range("A2:I10000" ).ClearContents
  4.     With Workbooks("Résultats sondage.xls" ).Worksheets("Conso_données" )
  5.         Set Rg = .Cells(.Rows.Count, 1)
  6.     End With
  7.    
  8.     For Each Wk In CreateObject("Scripting.FileSystemObject" ).GetFolder(ThisWorkbook.Path).Files
  9.         If Wk.Name <> "Résultats sondage.xls" And Wk.Name <> "PERSONAL.XLSB" Then
  10.             Workbooks.Open Wk
  11.            
  12.             With Worksheets("Données" )
  13.                 .Visible = True
  14.                 .Range("A2:I18" ).Copy Rg.End(xlUp).Offset(1)
  15.             End With
  16.         End If
  17.     Next
  18.    
  19.     Set Rg = Nothing
  20. End Sub

 

Reply

Marsh Posté le 11-01-2015 à 01:31:28    

Merci pour le code qui fonctionne à merveille.
 
J'ai lu l'aide et apparemment VBA n'acceptait pas de "End If" dans ma condition car il manquait une expression dans ma condition. J'ai écris deux conditions IF à la suite, alors qu'il fallait en mettre qu'une mais autour d'une expression (ici sous forme de with). Et du coup on peut écrire End if.
 
Je pensais qu'un "If then End If" ne s'écrivait qu'avec un Else if ou un else en son sein (pour que VBA accepte le end if).
 
La grosse erreur dont vous avez parlé correspond au fait qu'il n'y ait pas de "end if" ? Ce qui fait que les plages sont copiées parfois deux fois ?
 
Une derniere chose, le     Set Rg = Nothing sert donc à libérer de la mémoire pour l'execution du code d'apres ce que j'ai compris en lisant le net.
 
Question idiote (je préviens ^^) : On décharge la mémoire encombrée par les variables et objet en fin de procédure, le gain est pour libérer le presse papier en vue d'une autre utilisation d'excel ?
 
Yannick

Reply

Marsh Posté le 11-01-2015 à 09:54:40    

 

yanounou91 a écrit :

alors qu'il fallait en mettre qu'une mais autour d'une expression (ici sous forme de with).

            Ben non, ici il y a déjà une instruction en ligne n°11 précédent le bloc With en ligne n°13 ! …
            Rien qu'en consultant les codes que tu as déjà publié sur ce forum ! Copier/Coller n'est pas coder …
 

yanounou91 a écrit :

La grosse erreur dont vous avez parlé correspond au fait qu'il n'y ait pas de "end if" ?
Ce qui fait que les plages sont copiées parfois deux fois ?

            Ce n'est pas un problème de End If mais de l'exécution systématique des lignes n°27 à 31 !
 

yanounou91 a écrit :

On décharge la mémoire encombrée par les variables et objet en fin de procédure, le gain est pour libérer le presse papier en vue d'une autre utilisation d'excel ?

            Aucun rapport avec le presse-papiers, c'est juste pour libérer les ressources liées au pointage d'un objet …
            Là comme la copie directe est utilisée, le presse-papiers ne devrait pas être encombré, à vérifier tout de même …
 
 
           ________________________________________________________________________________________________________
           Nous sommes Charlie
 

Reply

Marsh Posté le 11-01-2015 à 11:15:05    

Merci pour les réponses.
 
Pour l'exécution automatique des lignes 27 à 31, je pense avoir compris. Comme la copie de l'onglet "Données" n'etait pas dans le cadre de la variable Wk et son test, cela provoquait une double exécution.  
 
S'agissant du bloc If Then, ce qui m'a perturbé pour le "End If" c'est que je n'avais pas de Else ou Else If dans mon expression. En tout cas je n'avais pas pensé à mettre un bloc With pour permettre le End If (j'aurais du m'inspirer effectivement de mon autre discussion).
 
Et il est vrai que je récupère souvent des codes en essayant de les adapter. Ou alors quand je les écris directement, mis à part pour des actions très simples sans boucle, je le fais via l'enregistreur.
Ici contrairement à d'habitude, le travail n'etait pas centré que sur un classeur. Ce qui rend les choses difficiles, mais passionnantes.
 
Il faut que je fasse plus souvent de VBA pour m'habituer à la syntaxe.
Et ma difficulté est aussi de comprendre l'aide Microsoft, j'ai vraiment du mal. A 90%, je comprends beaucoup mieux ce qui est expliqué sur les forums que sur le site d'aide Microsoft.
 
En master 1, on avait un cours d'informatique où on a passé pas mal d'heures à faire des choses rarement intéressantes. J'avais milité pour du VBA qui me semblait utile pour  notre formation (Contrôle de gestion/Finances). Car nous étions apprentis et je voyais qu'on utilisait beaucoup Excel en entreprise. Mais mes camarades ne m'ont pas suivi préférant avoir des cours tranquilles en Info et se concentrer sur le contrôle de gestion. Bref, maintenant je dois me faire la main comme on dit.
 
En tout cas merci pour l'aide. Je vais finir le code cette semaine puis avec quelques ajouts simples (a priori) et le posterai. Au cas où cela peut aider quelqu'un.
 
Yannick

Message cité 1 fois
Message édité par yanounou91 le 11-01-2015 à 11:18:06
Reply

Marsh Posté le 11-01-2015 à 12:13:17    

yanounou91 a écrit :

En tout cas je n'avais pas pensé à mettre un bloc With pour permettre le End If

            Le bloc With n'a aucun rapport, il sert juste à optimiser le code, évitant la répétition de la référence de la feuille de calculs :

Code :
  1.         If Wk.Name <> "Résultats sondage.xls" And Wk.Name <> "PERSONAL.XLSB" Then
  2.             Workbooks.Open Wk
  3.             Worksheets("Données" ).Visible = True
  4.             Worksheets("Données" ).Range("A2:I18" ).Copy Rg.End(xlUp).Offset(1)
  5.         End If


yanounou91 a écrit :

Mais mes camarades ne m'ont pas suivi préférant avoir des cours tranquilles en Info et se concentrer sur le contrôle de gestion.

            C'est sûr pour automatiser mieux vaut avoir des bases en VBA …
            Mais par expérience, les codes les plus efficaces sont ceux s'appuyant sur les formules de calculs d'Excel !
            Ne pas oublier que le VBA n'est pas du compilé mais de l'interprété : par exemple une boucle VBA  
            est bien plus longue à s'exécuter qu'une formule de calculs appliquée à une plage de cellules …
 
            ________________________________________________________________________________________________________
            Tous unis, tous Charlie
 

Reply

Marsh Posté le 11-01-2015 à 22:20:56    

Oui c'est vrai.
 
Mais sij'ai bien compris, on fait des boucles pour pouvoir tester plusieurs onglets ou plusieurs classeurs par exemple. Ou des actions sur des objets dont on ne connait pas forcément le nombre et/ou le nom. Ici les formules excel et l'enregistreur ne peuvent pas m'aider je pense.  
 
J'ai eu une présentation de VBA lors d'une formation d'une journée. Mais la logique du code, l'algorithme... je ne les ais pas, surtout que je ne suis pas ingénieur de formation. Je n'ai que ma logique (...) et une utilisation correcte d'Excel mais pas du tout en tant qu'expert. Mais bon, à moi de me former sur le tas.

Reply

Marsh Posté le 13-01-2015 à 23:20:29    


Bonsoir,
 
Je place le code terminé. La fin n'est surement pas parfaite mais tout fonctionne.
 
Merci à Marc L pour l'aide :
 
Ce code fonctionne à minima sur VBA 2003 à 2010 : Ce code ouvre les fichiers (nombre X) du dossier actif, affiche une feuille données caché structurée à l'identique, consolide les données, les copies dans une feuille, applique un calcul à la derniere colonne de la bdd puis mets à jours des TCD.
 

Code :
  1. Sub Sondage_résultats()
  2.    
  3.    
  4.     Dim Rg As Range, Wk As Object
  5.    
  6.     Workbooks("Resultats sondage.xls" ).Worksheets("Conso_données" ).Range("A2:J65000" ).ClearContents 'effacer la base de données avant une nlle consolidation
  7.        
  8.         'ouvrir les questionnaires du dossier actif, ouvrir l'onglet données de chacun de ces classeurs et les copier
  9.         With Workbooks("Resultats sondage.xls" ).Worksheets("Conso_données" )
  10.             Set Rg = .Cells(.Rows.Count, 1)
  11.         End With
  12.      
  13.         For Each Wk In CreateObject("Scripting.FileSystemObject" ).GetFolder(ThisWorkbook.Path).Files
  14.             If Wk.Name <> "Resultats sondage ICS.xls" And Wk.Name <> "PERSONAL.XLSB" Then
  15.                 Workbooks.Open Wk
  16.              
  17.                 With Worksheets("Données" )
  18.                     .Visible = True
  19.                     .Range("A2:I18" ).Copy Rg.End(xlUp).Offset(1)
  20.                 End With
  21.             End If
  22.         Next
  23.      
  24.      
  25.        'copier ces données dans l'onglet conso du fichier résultats sondage
  26.        With Workbooks("Resultats sondage.xls" ).Sheets("Conso_données" )
  27.    
  28.     LastLig = .Cells(.Rows.Count, 1).End(xlUp).Row
  29.     Tb = .Range("I1:J" & LastLig)
  30.    
  31.     For i = 2 To LastLig
  32.      
  33.         Tb(i, 2) = "=IF(ISERROR(RC[-1]/5),"""",RC[-1]/5)" 'faire un calcul pour avoir une note sur 5 des notes en colonne I en vue de faire des pourcentages dans les TCD
  34.      Next i
  35.     .Range("I1:J" & LastLig) = Tb
  36. End With
  37.      
  38.      
  39.      
  40.         'fermer sans enregistrement tous les classeurs ouverts sauf le fichier résultats sondages
  41.         For Each Wk In Workbooks
  42.             If Wk.Name <> ThisWorkbook.Name Then
  43.             Wk.Close savechanges:=False
  44.             End If
  45.         Next Wk
  46.        
  47.         Set Rg = Nothing
  48. 'mise à jour des TCD (j'ai pas utilisé refresh all de peur que ce ne fonctionne pas sur VBA 2003
  49. Dim wks As Worksheet
  50. Dim pt As PivotTable
  51. For Each ws In ActiveWorkbook.Worksheets
  52.     For Each pt In ws.PivotTables
  53.         pt.RefreshTable
  54. Next
  55. Next
  56. Sheets("Resultat Global" ).Activate
  57. Range("D5" ).Select
  58. End Sub


 
Yannick

Reply

Marsh Posté le 14-01-2015 à 00:16:59    

 
           L'usage est de regrouper les déclarations de variables en début de procédure …
           Pour ne pas oublier d'en déclarer, il est conseillé de placer en tête de module Option Explicit
 
           1) Quel est le nom du classeur contenant le code, celui actif quand la procédure est lancée (via un bouton ?) ?
 
           2) Dans la feuille "Conso_données" les données à effacer sont-elles en bloc (sans ligne ou colonne vide) ?
               Est-ce toutes les données de la feuille à effacer ?
               Plus tard dans la procédure, les données sont-elles par bloc ?
 
           3) Pour les lignes n°26 à 36, cas typique de boucle inutile s'il est juste question de coder une formule de calculs commune
               à une plage de cellules, un complément d'information permettrait de simplifier …
               Juste la colonne J à modifier, la colonne I reste intacte ?
 
           4) Lignes n°41 à 45 : les classeurs devraient être fermés au fur & à mesure après la ligne n°19 …
 

Reply

Marsh Posté le 14-01-2015 à 09:00:16    

Option explicit permet d'obliger la declaration des variables. Mais du coup le code ne fonctionnera pas si j'en déclare pas ? Ici, c'est aussi parce que j'ai fait la fin du code apres le début, mais effectivement les mettre au debut permettra une meilleure présentation.
 
1) Le nom du classeur contenant le code est le "résultats sondage.xls", c'est effectivement celui qui est actif via le lancement via le bouton (dans une des feuille de ce meme classeur).
 
2) les données sont en bloc effectivement. Aucun vide n'est permis car la macro demande une reponse à chaque question pour valider le questionnaire. les onglets "Donnees" (des fichiers questionnaires) sont copiés à la suite dans l'onglet "Conso_données" du fichier "Résultats sondage".
 
3) Oui la colonne I reste intacte. Cette façon de faire date d'une ancienne macro que j'avais faite. J'avais besoin de calculer un solde entre un debit et un credit. J'avais réalisé un code qui fonctionne mais le soucis etait que j'avais minimum 50 000 lignes à traiter. la macro durait 10 mn car il y avait un calcul de solde ligne par ligne. Une bonne âme m'a donné cette technique pour aller vite, que j'ai adapté ici. mais il est vrai que dans cette macro, le nombre de ligne est faible (1 000 ligne max a priori).
 
4) Effectivement cela serait mieux mais le code deviendrai très complexe. Et meme si vous m'avez aidé, ou que souvent j'adapte des choses trouvées, j'essaie (sauf obligation) de prendre des codes que je peux comprendre. Le but etant de pouvoir l'utilisé de nouveau, de ne pas prendre quelque chose sans rien comprendre du tout et de m'améliorer ^^. Et etant donné qu'il n'y a pas non plus 1000 questionnaire (une trentaines, mais je pense que meme avec 100 classeurs cela fonctionnerait ainsi.
 
Mais si vous le pouvez, je suis curieux d'avoir des pistes pour optimiser tout cela en vue. Mais je garderai les deux versions car à mon niveau il faut un niveau d'optimisation mais pas toujours à 100% non plus. Qu'en pensez vous ?
 
Yannick

Reply

Marsh Posté le 14-01-2015 à 11:58:47    

 
           Plus de classeurs sont ouverts moins il y a de mémoire disponible augmentant ainsi les risques de ralentissement et de crash ‼
           Une fois les données d'un dossier copiées, mieux vaut le fermer avant d'en ouvrir un autre.
 
           J'ai conservé Scripting.FileSystemObject même si je préfère la fonction VBA Dir souvent bien plus rapide …
 
           Coller par exemple le code suivant dans le module du classeur (ThisWorkbook)
           ainsi toute référence d'un classeur omise fait de facto référence au classeur contenant le code !
           Cela ne pose pas de souci dans un module normal car c'est aussi le classeur actif au lancement de la procédure …
 
           Astuce avant de copier le code : effectuer un double clic ci-dessous dans la fenêtre du code …
 

Code :
  1. Sub SondageRésultats()
  2.     Dim Pt As PivotTable, Rg As Range, Wk As Object, Ws As Worksheet
  3.     Application.ScreenUpdating = False
  4.  
  5.     With Worksheets("Conso_données" )
  6.         With .Cells(1).CurrentRegion:  .Rows("2:" & .Rows.Count).ClearContents:  End With
  7.         Set Rg = .Cells(.Rows.Count, 1)
  8.  
  9.         For Each Wk In CreateObject("Scripting.FileSystemObject" ).GetFolder(ThisWorkbook.Path).Files
  10.             If Wk.Name <> "Resultats sondage ICS.xls" And Wk.Name <> "PERSONAL.XLSB" Then
  11.                 With Workbooks.Open(Wk)
  12.                     With .Worksheets("Données" )
  13.                         .Visible = True
  14.                         .Range("A2:I18" ).Copy Rg.End(xlUp).Offset(1)
  15.                     End With
  16.  
  17.                     .Close False
  18.                 End With
  19.             End If
  20.         Next
  21.  
  22.         .[J2].Resize(Rg.End(xlUp).Row - 1).FormulaR1C1 = "=IF(ISERROR(RC[-1]/5),"""",RC[-1]/5)"
  23.         Set Rg = Nothing
  24.     End With
  25.  
  26.     For Each Ws In Worksheets
  27.         For Each Pt In Ws.PivotTables:  Pt.RefreshTable:  Next
  28.     Next
  29.  
  30.     Worksheets("Resultat Global" ).Activate
  31. End Sub


__________________________________________________________________________________________________________
           Tous unis, tous Charlie


Message édité par Marc L le 14-01-2015 à 14:27:02
Reply

Marsh Posté le 14-01-2015 à 12:06:21    

 
           Rendre visible la feuille ne doit pas être nécessaire pour copier les données !
 
           A tester :
 

Code :
  1. Sub SondageRésultats()
  2.     Dim Pt As PivotTable, Rg As Range, Wk As Object, Ws As Worksheet
  3.     Application.ScreenUpdating = False
  4.  
  5.     With Worksheets("Conso_données" )
  6.         With .Cells(1).CurrentRegion:  .Rows("2:" & .Rows.Count).ClearContents:  End With
  7.         Set Rg = .Cells(.Rows.Count, 1)
  8.  
  9.         For Each Wk In CreateObject("Scripting.FileSystemObject" ).GetFolder(ThisWorkbook.Path).Files
  10.             If Wk.Name <> "Resultats sondage ICS.xls" And Wk.Name <> "PERSONAL.XLSB" Then
  11.                 With Workbooks.Open(Wk)
  12.                     .Worksheets("Données" ).[A2:I18].Copy Rg.End(xlUp).Offset(1)
  13.                     .Close False
  14.                 End With
  15.             End If
  16.         Next
  17.  
  18.         .[J2].Resize(Rg.End(xlUp).Row - 1).FormulaR1C1 = "=IF(ISERROR(RC[-1]/5),"""",RC[-1]/5)"
  19.         Set Rg = Nothing
  20.     End With
  21.  
  22.     For Each Ws In Worksheets
  23.         For Each Pt In Ws.PivotTables:  Pt.RefreshTable:  Next
  24.     Next
  25.  
  26.     Worksheets("Resultat Global" ).Activate
  27. End Sub

Reply

Marsh Posté le 14-01-2015 à 13:05:33    

Merci beaucoup je vais tester cela ce soir.
 
Je rechercherai aussi les significations des rezise et de nothing (Set Rg= Nothing), meme si la traduction directe en francais donne déjà une idée.
 
Cdt.
 
Yannick

Reply

Marsh Posté le 14-01-2015 à 14:22:21    

 
           La ligne n°18 du dernier code peut aussi s'écrire ainsi :
 
           .Range("J2:J" &  Rg.End(xlUp).Row).FormulaR1C1 = "=IF(ISERROR(RC[-1]/5),"""",RC[-1]/5)"
 
           _______________________________________________________________________________________
           Tous unis, tous Charlie
 

Reply

Marsh Posté le 15-01-2015 à 00:39:48    


 
Je n'ai pas trop compris l'utilisation de l'expression "Nothing" dans le code et j'ai encore du mal avec les explications de Microsoft.
 
Sinon, vous avez proposé d'inscrire les derniers codes fournis dans vos posts dans la feuille "This workbook". Tout fonctionne parfaitement, merci beaucoup.
 
En revanche, dans les cours VBA pour débutant on nous indique toujours d'ouvrir un module pour écrire un code. Quel est le meilleur emplacement ?
 
Cordialement.
 
 
Yannick

Reply

Marsh Posté le 15-01-2015 à 09:48:13    

 
           Normalement lors de la fin d'une procédure toutes ses variables locales non statiques sont effacées.
           Mais en ce qui concerne une variable objet, mieux vaut libérer ainsi les ressources allouées au pointage de cet objet …
 
           Pour le choix d'un module normal ou d'un module de classe du classeur ou d'une feuille,
           je n'indiquerais pas de meilleur emplacement car c'est un choix personnel, une habitude, une facilité même …
           C'est comme pour le café, certains le préfèrent fort, d'autres allongé, sucré ou pas …
 
           Lorsqu'il s'agit d'exploiter un évènement du classeur ou d'une feuille, il n'y a pas le choix,
           le code doit se situer dans le module de classe correspondant au classeur ou à la feuille !
           Et si dans ce code une fonction ou procédure est appelée, par simplicité autant qu'elle se trouve dans le même module …
 
           L'avantage d'un module normal serait la réutilisation d'un code générique dans d'autres classeurs, suffit de l'exporter
           d'un classeur source pour le sauvegarder sur le disque dur et lors de la création d'un nouveau classeur,
           importer ce module éviterait de réécrire des procédures similaires …
 
           Lorsqu'un projet comporte des milliers de lignes, il est plus simple pour s'y retrouver
           de séparer par thème les procédures dans plusieurs modules …
 
           De mon côté, c'est souvent du sur-mesure. L'avantage de coder directement dans un module de classe d'un classeur ou
           d'une feuille permet en cas d'omission de toute référence à un classeur ou à une feuille de faire de facto référence
           à ce classeur ou à cette feuille, simplifiant et sécurisant ainsi le code, même si un évènement change le classeur ou la feuille active !
 
           Par exemple l'instruction Range, sans être précédée par une référence à une feuille de calculs, dans un module normal,
           fait donc référence à la feuille active, ce qui s'avère problématique lorsqu'une autre feuille devient active …
           Tandis que cette même instruction dans le module d'une feuille de calculs fait de facto référence à cette feuille
           quelle que soit la feuille active !
 
           Autre point à prendre en compte : lors de la copie d'une feuille de calculs vers un nouveau classeur par exemple,
           le module de classe de cette feuille y étant rattaché se retrouve aussi dans la destination, tout dépend du contexte donc …
 
           Récemment sur un autre forum, un intervenant était fier de présenter une solution d'environ 200 lignes
           dont le demandeur signalait sa difficulté à s'y retrouver dans ce code pour l'adapter à son besoin - simple - et parfois
           un fonctionnement aléatoire dans son environnement multi-feuilles.
           Un autre intervenant et moi-même avons chacun proposé une solution tenant en un maximum de 30 lignes de code
           bien plus efficace, sûre et plus facile pour le demandeur à appréhender.
 
           Mais le primo intervenant nous a fustigé (du domaine de la cour de récréation en élémentaire !),
           qu'on avait rien compris à son code, que le sien était modulaire (pourtant une vraie usine à gaz !)
           et qu'il lui était ainsi plus facile pour l'utiliser dans divers classeurs …
           J'ai l'impression qu'il était resté au moins vingt ans en arrière même s'il semble plus jeune de vingt ans !
           Tout dépend donc de l'expérience de chacun et de la souplesse d'esprit, c'est comme les goûts, les couleurs …
 
           Pour éviter souci et perte de temps, ne pas oublier la hiérarchie objet d'Excel :
           Application (Excel) / Workbook / Worksheet / Range / méthode ou propriété …
 
           Le Générateur de macros est un outil pratique pour voir quels objets, méthodes et propriétés sont utilisés lors de manipulation.
           Mais ensuite il faut nettoyer le code afin qu'il devienne plus efficient
           car travailler directement sur les objets est bien plus efficace et sûr, voir l'exemple en lien dans ce post …  
 

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed