Fonction VBA/Excel : récupérer les données d'un classeur

Fonction VBA/Excel : récupérer les données d'un classeur - VB/VBA/VBS - Programmation

Marsh Posté le 25-07-2013 à 10:54:50    

Hello
J'ai un code qui fonctionne en procédure, mais pas en Fonction.
L'idée est la suivante :  
 

Code :
  1. Function Bidule(NomFichier)
  2.     ouverture du fichier NomFichier
  3.     récupération dans une variable Toto de la somme d'une colonne
  4.     fermeture du fichier
  5.     Bidule = Toto
  6. End Function


 
Problème : la fonction n'affiche que #VALEUR! , sauf si j'ouvre en parallèle le fameux fichier.
Je voudrais au contraire que ce soit transparent et invisible pour l'utilisateur.
 
Est ce une limitation des fonctions VBA ?
 
 :jap:


---------------
Is it a bird? Is it a plane? No it s F22Raptor !  -  I love flying because football, baseball, rugby, and golf only take one ball
Reply

Marsh Posté le 25-07-2013 à 10:54:50   

Reply

Marsh Posté le 25-07-2013 à 15:21:28    

 
           Bonjour,
 
           peut-on voir la procédure ? …
 


Message édité par Marc L le 25-07-2013 à 15:22:28
Reply

Marsh Posté le 25-07-2013 à 18:29:35    

en simplifiant le code, ça donne ceci :
Si j'ai fichier.xls ouvert, ça marche, mais sinon j'obitiens #VALEUR!  
 
 
 
 
Function Portefeuille(NumColonne As Integer)
 
    Dim Repertoire As String
    Dim Fichier As String
    Dim CalculTotal As Currency
 
    Repertoire = "C:\Repertoire\"
    Fichier = "fichier.xls"
     
    'Ouverture du fichier
    Application.DisplayAlerts = False
    Workbooks.Open Filename:=Repertoire & Fichier
     
    CalculTotal = Application.Sum(Rows(NumColonne))
 
    ActiveWorkbook.Close SaveChanges:=False
    Application.DisplayAlerts = True
    '______________
     
    Portefeuille = CalculTotal
 
End Function


Message édité par F22Raptor le 25-07-2013 à 18:31:30

---------------
Is it a bird? Is it a plane? No it s F22Raptor !  -  I love flying because football, baseball, rugby, and golf only take one ball
Reply

Marsh Posté le 25-07-2013 à 18:46:26    

 
           Au fait t'es sûr de ta ligne n° … Ah zut, t'as pas utilisé l'icône pour le code ‼
 
           Bref, j'ai déjà un doute sur la justesse du calcul …
 
           En fait tu aurais pu déjà trouver la solution en le faisant manuellement car cela fait partie des fonctions de base d'une feuille de calcul !
 
           Deux classeurs ouverts, la formule commence à être saisie =SOMME( puis tu changes de classeur et
           tu sélectionnes la colonne ou seulement une partie de la colonne, tu reviens dans le classeur et tu clôtures la formule
           par la parenthèse fermante et tu valides …
           T'as plus qu'à reluquer la formule comme une p'tite pépée se trémoussant sur la piste de danse d'un night club !
 
           Matière à réflexion, non ?!   Toujours commencer par les bases, soit en manuel soit via l'Enregistreur de macros puis après on peaufine,
           sauf si vraiment on est un cador, mais là c'est une autre histoire …
 
           

Reply

Marsh Posté le 25-07-2013 à 21:43:07    

Marc L a écrit :

 
           Au fait t'es sûr de ta ligne n° … Ah zut, t'as pas utilisé l'icône pour le code ‼
 
           Bref, j'ai déjà un doute sur la justesse du calcul …
 
           En fait tu aurais pu déjà trouver la solution en le faisant manuellement car cela fait partie des fonctions de base d'une feuille de calcul !
 
           Deux classeurs ouverts, la formule commence à être saisie =SOMME( puis tu changes de classeur et
           tu sélectionnes la colonne ou seulement une partie de la colonne, tu reviens dans le classeur et tu clôtures la formule
           par la parenthèse fermante et tu valides …
           T'as plus qu'à reluquer la formule comme une p'tite pépée se trémoussant sur la piste de danse d'un night club !
 
           Matière à réflexion, non ?!   Toujours commencer par les bases, soit en manuel soit via l'Enregistreur de macros puis après on peaufine,
           sauf si vraiment on est un cador, mais là c'est une autre histoire …
 
           


Ta méthode marche en Procédure, de même que la mienne.
Mais ici on a une fonction : dans une cellule tu tapes =MACHIN(argument)  et ça te ramène une valeur.
Et j'ai l'impression que l'ouverture de feuille fonctionne moyennement en "Function"


---------------
Is it a bird? Is it a plane? No it s F22Raptor !  -  I love flying because football, baseball, rugby, and golf only take one ball
Reply

Marsh Posté le 26-07-2013 à 12:20:37    

 
           Heu, quand les messages se suivent, pas la peine de citer le message précédent ! …  :sarcastic:  
 
           Ah là c'est une fonction personnalisée (appelée depuis une cellule) et non pas une simple fonction VBA !
           Effectivement il y a une limitation comme ne pas pouvoir toucher aux cellules, juste renvoyer une valeur à l'appelante …
 
           J'ai essayé par la méthode de l'instance cachée récupérant bien la somme mais tiltant Excel lors du retour !
 
 
           Je ne vois plus que la connexion ADO (ActiveX Data Objects) mais disposant aussi de contraintes :
 
           ◙  une référence doit être activée mais ce n'est pas la même selon la version des fichiers à accéder si < à 2007 ou >= à 2007 …
 
           ◙  Limitations lors de la transposition interne d'un tableau mais possibilité de contourner via une procédure VBA
              (voir Comment faire pour transférer des données d'un jeu d'enregistrements ADO vers Excel avec l'Automation).
 
           ◙  Pas la possibilité d'utiliser un objet colonne, il faut indiquer précisément l'adresse des cellules à récupérer
               mais s'arrête dès la première cellule vide rencontrée …
               Dans ma fonction à suivre, si seulement la première cellule est indiquée, elle comble automatiquement l'adresse de fin de colonne.
 
           ◙  Apparemment il ne faudrait pas de $ dans l'adresse de la plage des cellules
               car il sert à séparer le nom de la feuille de calcul et la plage de cellules; ma fonction le gère aussi.
 
           ◙  La fonction personnalisée doit être définie comme  Volatile  afin qu'elle se mette à jour en cas de changement dans la source,
               mais elle est recalculée chaque fois qu'un calcul est effectué dans une cellule quelconque de la feuille de calcul,
               donc plus de cellules utilisent cette fonction personnalisée plus le temps de calcul s'allonge …
 
               #VALEUR!  peut aussi apparaître dans une cellule utilisant cette fonction
               mais tout rentre dans l'ordre au prochain calcul dans la feuille …  Rien qu'en supprimant une cellule vide !  :pt1cable:  
 
 
           Autre article à consulter :   Méthodes de transferts de données vers Excel à partir de Visual Basic
 
 
           Dans l'environnement VBA, il faut activer une référence via le menu Outils.
 
           Pour accéder aux .xlsx et autres fichiers à partir d'Excel 2007, je n'ai pas la référence exacte, ma version sur un portable
           itinérant n'étant pas encore rentrée et, qui plus est, je ne serais pas disponible pendant une bonne semaine.
 
           Au cas où :   Microsoft Download Center, 2007 Office System Driver : Data Connectivity Components
 
           J'ai coché la référence Microsoft ActiveX Data Objects 6.1 Library pour accéder à un fichier .xls …
 

Code :
  1. Function Actions(Rg As Range) As Currency
  2.     Application.Volatile
  3.     F$ = "D:\Tests\Test2 .xls"
  4.     D$ = Dir$(F):  If D <> Right$(F, Len(D)) Then Exit Function
  5.    
  6.     If Rg.Count = 1 Then _
  7.          Plage$ = "Feuil1$" & Range(Rg, Cells(Rows.Count, Rg.Column)).Address(False, False) _
  8.      Else Plage = "Feuil1$" & Rg.Address(False, False)
  9.    
  10.     Set Cnx = New ADODB.Connection
  11. '   version 2003 & antérieure :
  12.     Cnx.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & F & _
  13.              ";Extended Properties=""Excel 8.0;HDR=No;"";"
  14. '   à partir version 2007 :
  15. '    Cnx.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & F & _
  16.              ";Extended Properties=""Excel 12.0;HDR=No;"";"
  17.    
  18.     Set Rst = Cnx.Execute("SELECT * FROM [" & Plage & "]" )
  19.     Actions = Application.Sum(Application.Index(Rst.GetRows, 0))
  20.     Rst.Close
  21.     Cnx.Close
  22.     Set Rst = Nothing
  23.     Set Cnx = Nothing
  24. End Function
  25.    
  26.    
  27. Private Sub TestADO()
  28.     Debug.Print Actions([G11])
  29. End Sub


           Exemple de formule dans une cellule :   =Actions(G11)
 
 
           Si tu ne t'en sors pas, je te laisse te documenter de ton côté …
 
           Et si tu trouves une autre méthode, merci ne nous la faire partager !
 
 
           _______________________________________________________________________________________
           Comme la vitesse de la lumière est supérieure à celle du son, certains ont l'air brillant avant d'avoir l'air con !


Message édité par Marc L le 26-07-2013 à 13:12:58
Reply

Marsh Posté le 26-07-2013 à 13:56:28    

Merci pour cette réponse très complète !  
Je vais tester ça, mais c'est vrai que ça devient lourd à gérer, surtout que la fonction doit être chargée sur d'autres PC, donc d'autres config (et éventuellement d'autres versions d'Excel).
 
:jap:


---------------
Is it a bird? Is it a plane? No it s F22Raptor !  -  I love flying because football, baseball, rugby, and golf only take one ball
Reply

Marsh Posté le 26-07-2013 à 14:28:51    

 
           En revenant aux bases, simplement tu nommes une cellule par exemple Colonne7 puis tu la caches
           et elle se met à jour à l'ouverture du classeur :
 

Code :
  1. Private Sub Workbook_Open()
  2.     [Colonne7].Formula = "=SUM('D:\Tests\[Test2 .xls]Data'!G:G)"
  3.       [Colonne7].Value = [Colonne7].Value
  4. End Sub


           Ensuite dans les formules tu utilises ce nom :   =Colonne7
 
           Si t'en as plusieurs de ce genre, tu peux alors leur dédier une feuille du classeur et la cacher,
           ce qui n'empêche pas d'utiliser leurs noms …
 

Reply

Marsh Posté le 26-07-2013 à 20:56:45    

 
           Je viens de tester sans souci sur Excel 2007 l'accès à un fichier .xls (donc antérieur à 2007) avec ma procédure ADO telle quelle !
 
           Donc si tu n'as pas besoin de dépasser la limite des 65536 lignes par 256 colonnes,
           tu peux alors enregistrer le fichier source en .xls vu la compatibilité ascendante des versions ultérieures …
 
           Maintenant, ma préférence reste sur des cellules dédiées, tout dépend en fait du contexte …


Message édité par Marc L le 27-07-2013 à 10:58:56
Reply

Marsh Posté le 23-09-2013 à 09:19:17    

 
           Bonjour,
 
           suite à un problème récent de la même veine, je complète ce sujet en clarifiant la connexion ADO (ActiveX Data Objects)
           étant quelque peu fautif et pourrait aussi servir de sujet référence pour des questions similaires …
 
           Deux méthodes possibles de déclaration de variable objet : la liaison anticipée et la liaison tardive.
 
           La liaison anticipée (Early Binding), avant toute intervention sur un objet au moyen d'une variable objet,
           associe le type exact de l'objet en question à la variable objet s'y référant via l'instruction Dim
           encore faut-il ajouter une librairie aux Références du projet (via le menu Outils) …
 
           Avantages :  exécution un peu plus rapide car pas d'ambiguïté vis à vis d'une variable objet générique,
           le pré-compilateur sachant d'avance à quoi s'attendre, tout est prêt au moment de l'exécution;
           conservation de l'IntelliSense au cours de la rédaction du code (Complément automatique des instructions des Options Éditeur),
           dès le point tapé contre le nom d'un objet, la liste de ses méthodes & propriétés associées s'affichant automatiquement …
                       
           Mais si le nom exact de la librairie à activer est inconnu, impossible donc de déclarer la variable objet en liaison anticipée !
           Qui plus est selon la version d'Excel ou du système d'exploitation, les librairies peuvent changer, nuisant ainsi à la portabilité du projet.
           Dans ces cas, la liaison tardive (Late Binding) s'impose de facto …
 
           Mea Culpa F22Raptor car dans mon code du 26/7 j'ai réussi à effectuer un pont entre ces deux méthodes
           avec une liaison tardive tout en ayant l'obligation d'activer la référence d'une librairie !  :pt1cable:  
           Certainement par trop pressé, cela arrive quand on veut boucler la semaine en menant plusieurs fronts à la fois …
 
           Conservant la problématique de ce sujet, les codes à suivre sont en liaison anticipée car la référence à activer
           reste la même en version 2003 comme en 2007 d'Excel.             La liaison tardive va aussi être abordée …
 
       ◙  Premier cas :  connexion ADO pour accéder à un fichier fermé  .xls  (format antérieur à la version 2007)
                                indifféremment en version 2003 ou 2007 d'Excel (version remaniée du 26/7) :

Code :
  1. '   Référence à cocher :   Microsoft ActiveX Data Objects 6.1 Library
  2.    
  3. Function Actions(Rg As Range) As Currency
  4.          Dim Cnx As New ADODB.Connection, Rst As New ADODB.Recordset
  5.          Application.Volatile
  6.    
  7.          F$ = "D:\Tests\Test2 .xls":  If Dir(F) = "" Then Exit Function
  8.          D$ = IIf(Rg.Count > 1, Rg, Range(Rg, Cells(Rows.Count, Rg.Column))).Address(0, 0)
  9.    
  10.          Cnx.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & F & _
  11.                   ";Extended Properties=""Excel 8.0;HDR=No;"";"
  12.    
  13.          Set Rst = Cnx.Execute("SELECT * FROM [Feuil1$" & D & "]" )
  14.          Actions = Application.Sum(Application.Index(Rst.GetRows, 0))
  15.          Rst.Close:  Set Rst = Nothing
  16.          Cnx.Close:  Set Cnx = Nothing
  17. End Function
  18.    
  19.    
  20. Private Sub TestADO()
  21.     Debug.Print Actions([G11])
  22. End Sub

           En ligne n°13, Feuil1 représente le nom de la feuille de calcul du classeur fermé, le $ le séparant de la plage de cellules …
 
       ◙  Voici comment passer en liaison tardive quelle que soit la version d'Excel, en cas de souci par exemple pour activer la référence :
 
           →  Insérer avant la ligne n°10 cette ligne :  Set Cnx = CreateObject("ADODB.Connection" )
 
           →  Supprimer la ligne n°4  Dim  puis les lignes n°1 & 2 …
 
 
       ◙  Second cas :  connexion ADO pour accéder à un classeur fermé  .xlsx  à partir d'Excel 2007 :

Code :
  1. '   Référence à cocher :   Microsoft ActiveX Data Objects 6.1 Library
  2.    
  3. Function Actions(Rg As Range) As Currency
  4.          Dim Cnx As New ADODB.Connection, Rst As New ADODB.Recordset
  5.          Application.Volatile
  6.    
  7.          F$ = "D:\Tests\Test2 .xlsx":  If Dir(F) = "" Then Exit Function
  8.          D$ = IIf(Rg.Count > 1, Rg, Range(Rg, Cells(Rows.Count, Rg.Column))).Address(0, 0)
  9.    
  10.          Cnx.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & F & _
  11.                   ";Extended Properties=""Excel 12.0;HDR=No;"";"
  12.    
  13.          Set Rst = Cnx.Execute("SELECT * FROM [Feuil1$" & D & "]" )
  14.          Actions = Application.Sum(Application.Index(Rst.GetRows, 0))
  15.          Rst.Close:  Set Rst = Nothing
  16.          Cnx.Close:  Set Cnx = Nothing
  17. End Function
  18.    
  19.    
  20. Private Sub TestADO()
  21.     Debug.Print Actions([G11])
  22. End Sub

           Seule la commande de connexion change par rapport au cas précédent (lignes n°10-11) …
 
           Je ne sais pourquoi fin juillet j'ai essuyé un échec lors de mon test en liaison anticipée sur Excel 2007,
           je croyais ne pas utiliser la bonne référence mais, comme déjà évoqué, je n'avais guère le temps …
 
           Bonus :  cette connexion fonctionne aussi avec les classeurs  .xls  antérieurs à Excel 2007,
                        la préférer donc sous Excel 2007, une seule connexion quel que soit le type de classeur !
 
 
       ◙  Astuce :  par défaut, Excel 2003 ne peut ouvrir les classeurs  .xlsx  de la version 2007.
 
                        C'est devenu possible grâce au Pack de compatibilité Microsoft Office 2007 !
 
                        Et pour le second cas ci-dessus de la connexion ADO, c'est aussi possible grâce
                        au Pilote d'Office System 2007 des composants de connectivité des données !
                        (lien déjà donné fin juillet mais cette fois-ci en version française)
 
                        Excel 2003, ainsi mis à jour, un message prévient de la conversion en cours lors de l'ouverture d'un classeur  .xlsx   …
                        Il n'y a pas de message lors de la connexion ADO avec un tel classeur,
                        elle est juste quelque peu ralentie le temps de la conversion mais cela fonctionne !
 
                        Toutefois certainement dans les limites du nombre de lignes et de colonnes d'une feuille d'un classeur d'Excel 2003 …


Message édité par Marc L le 23-09-2013 à 09:55:29
Reply

Sujets relatifs:

Leave a Replay

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