IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Commentaires

  1. Avatar de Blahite
    • |
    • permalink
    Bonjour,

    Assez intéressant.
    Une raison particulière de ne pas utiliser les dictionnaires ?
    S'il y a beaucoup de paramètre cela simplifie le code et la lisibilité à première vue.
    Exemple ci-dessous (adaptation à l'arrache, il y a peut-être mieux à faire en terme de binding)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    Public Function ReplaceStrings(Source As String, ByRef dict) As String
      Dim I As Long
      Dim key As Variant
     
      ReplaceStrings = Source
    
      For Each key In dict.Keys
        ReplaceStrings = Replace(ReplaceStrings, key, dict(key), 1, -1, vbTextCompare)
      Next key
    End Function
    
    Sub Test4()
      Dim Message As String
      Dim dict As Object
      Set dict = CreateObject("Scripting.Dictionary")
      
      dict("{depart}") = "Place du Perron,+4910+Theux"
      dict("{arrivee}") = "Place Verte,+4900+Spa"""
     
      Message = "<A href=""https://www.google.fr/maps/dir/{depart}/{arrivee}"">Cliquez ici pour la navigation.</A>"
      Message = ReplaceStrings(Message, dict)
    End Sub
  2. Avatar de MarcelG
    • |
    • permalink
    Salut Pierre,

    La déclaration de variables est pour moi, et je le mentionne souvent dans les discussions, fondamentale.

    Maintenant, il s'agit aussi, à mon avis, de bien effectuer cette déclaration.
    Je reprends souvent cet exemple des dictionnaires.

    En ayant activé la référence "Scripting.Runtime"

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Dim dico as Scripting.Dictionary
    Le développeur peut ensuite bénéficier de l'IntelliSense, autrement dit des propriétés et méthodes afférant à la variable.

    Je sais qu'il y a sujet à discussion. Mais c'est mon avis.

    A plus tard.

    Marcel
  3. Avatar de MarcelG
    • |
    • permalink
    Très bien.

    Je prends note, en ayant mis à jour mon aide-mémoire (créé en 2009! ) dans sa partie "Feuilles".

    Merci et à bientôt.

    Marcel
  4. Avatar de Pierre Fauconnier
    • |
    • permalink
    Salut Marcel.

    Merci pour tes commentaires et questions. Je vais les prendre à l'envers, si tu veux bien, et d'abord répondre à ta dernière question: Pourquoi As Object et pas As Worksheet?

    Pour que la fonction puisse aussi être utilisée pour une feuille de graphique (Objet Chart) et éviter ainsi d'avoir deux fonctions, une qui traite la feuille de calcul et l'autre qui traite la feuille de graphique.

    Pour ce qui est des codes de Philippe, je ne peux pas les commenter en faisant abstraction de On Error puisque sans les On Error, les codes proposés ne sont pas fonctionnels et que perso, je ne veux pas utiliser les On Error dans ces cas.

    La dernière proposée, qui n'utilise pas de boucle et pas de gestion d'erreurs pourrait être intéressante, mais elle est limitée aux feuilles de calcul. Dès lors, chaud partisan de la systématisation dans mes codes, je préfère en utiliser une seule qui permet de tester une feuille quel que soit son type, de manière à ne pas encombrer mon module xlTools avec des fonctions presqu'identiques*, et de ne pas devoir me poser la question du type de la feuille.

    Je peux juste proposer une "fusion" de mes deux fonctions (celle qui renvoie la feuille et celle qui teste qu'elle existe), bien que je n'aime pas trop cette solution qui oblige à passer un objet même si l'on souhaite seulement tester l'existence de la feuille.

    Code vba : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Function SetSheetByName(Name As String, ByRef sh As Object, Optional wb As Workbook) As Boolean
      Dim Counter As Long
     
      Set sh = Nothing
      If wb Is Nothing Then Set wb = ActiveWorkbook
      Counter = 1
      Do While Counter <= wb.Sheets.Count And sh Is Nothing
        If StrComp(wb.Sheets(Counter).Name, Name, vbTextCompare) = 0 Then Set sh = wb.Sheets(Counter)
        Counter = Counter + 1
      Loop
      SetSheetByName = Not sh Is Nothing
    End Function

    Code vba : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    Sub testSheet()
      Dim sh As Object
     
      If SetSheetByName("Feuil1", sh) Then
        Debug.Print sh.Name
      Else
        MsgBox "La feuille n'existe pas"
      End If
    End Sub




    * En son temps, j'avais aussi créé une fonction qui permettait de rechercher une feuille selon son name ou son codename. Elle traîne toujours dans mon module Tools (jétais moins organisé à l'époque... )

    Code vba : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    Function getSheetByName(Optional Name As String, Optional CodeName As String, Optional wb As Workbook) As Object
      Dim sh As Object
      Dim Counter As Long
     
      If Name <> "" Or CodeName <> "" Then
        If wb Is Nothing Then Set wb = ActiveWorkbook
        Counter = 1
        Do While Counter <= wb.Sheets.Count And getSheetByName Is Nothing
          If Name <> "" Then
            If StrComp(wb.Sheets(Counter).Name, Name, vbTextCompare) = 0 Then Set getSheetByName = wb.Sheets(Counter)
          Else
            If StrComp(wb.Sheets(Counter).CodeName, CodeName, vbTextCompare) = 0 Then Set getSheetByName = wb.Sheets(Counter)
          End If
          Counter = Counter + 1
        Loop
      End If
    End Function

    Elle s'appelle facilement avec les arguments nommés (que j'utilise très souvent dans mes codes, par ailleurs).

    Code vba : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Sub TestSheets()
      Debug.Print getSheetByName(Name:="Feuil2").CodeName
      Debug.Print getSheetByName(CodeName:="shTest").Name
    End Sub
  5. Avatar de MarcelG
    • |
    • permalink
    Dans les solutions précédentes, beaucoup - trop à mon goût - de gestions d'erreurs. Ce dont il faut user, certes, mais à bon escient. Personnellement, j'évite tant faire se peut.
    Cela dit, pas de sortie de bloc anticipée.

    Je mets donc ce billet dans mes priorités

    Ce tout en sachant que l'on peut, sauf erreur, obtenir, comme demandé la plupart du temps, une fonction booléenne sur getSheetByName = Nothing ou non.

    Du type:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    Function ExisteFeuille(Name As String, Optional wb As Workbook) As Boolean
      
    Dim getSheetByName As Object
    Dim sh As Object
    Dim Counter As Long
    
    If wb Is Nothing Then Set wb = ActiveWorkbook
            Counter = 1
            Do While Counter <= wb.Sheets.Count And getSheetByName Is Nothing
            If StrComp(wb.Sheets(Counter).Name, Name, vbTextCompare) = 0 Then Set getSheetByName = wb.Sheets(Counter)
            Counter = Counter + 1
    Loop
    
    If getSheetByName Is Nothing Then
            ExisteFeuille = False
    Else
            ExisteFeuille = True
            Set getSheetByName = Nothing
    End If
    
    End Function
    Maintenant, je pose la question, Pierre.

    J'ai codé cette fonction en déclarant sh en Worksheet.
    La fonction reste bien effective. Une feuille étant un objet.

    Y a-t-il une raison à la déclaration initiale en Object?
    Il y a sans doute là des notions qui me sont étrangères.

    A plus tard.

    Bonne soirée.
    Mis à jour 20/11/2019 à 10h12 par MarcelG
  6. Avatar de MarcelG
    • |
    • permalink
    Salut Pierre,

    Sans flagornerie aucune.
    Intéressant

    A retenir en règle générale. Pas de Exit mais plutôt Do..While (ou Until sans doute)
    Si l'on m'y reprend (car je suis souvent tombé), une bière pour Marcel!

    Je reporte ci-dessous un extrait de mes aides-mémoires.
    (dont quelques liens de Philippe)
    Peut-être un avis? (les On Error, que tu mentionnes dans ton billet, mis à part)

    A plus tard.

    http://www.developpez.net/forums/d13...xcel-avec-vba/
    Function ExistSheet(Ws$, Optional Wb As Workbook) As Boolean
    If Wb Is Nothing Then Set Wb = ActiveWorkbook
    On Error Resume Next
    ExistSheet = IsObject(Wb.Sheets(Ws))
    End Function

    Voir les liens de Philippe Thulliez

    https://www.developpez.net/forums/d1.../#post10992616

    2 premières fonction = Philippe Thulliez

    Function IsSheetExist(SheetName As String, Optional Wkb As Workbook) As Boolean
    ' http://philippe.tulliez.be
    ' Renvoie True ou False
    ' Arguments
    ' SheetName (String) Nom de la feuille dont on teste l'existence
    ' [wkb] (Workbook) ThisWorkbook est le classeur par défaut
    Dim Sht As Worksheet
    If Wkb Is Nothing Then Set Wkb = ThisWorkbook
    On Error Resume Next
    Set Sht = Wkb.Sheets(SheetName)
    With Err
    If .Number Then .Clear Else IsSheetExist = True
    End With
    ‘--------------------------------

    http://philippe.tulliez.be/fonction-...s-un-classeur/

    Function IsSheetExist(Name As String) As Boolean
    ' Cette fonction renvoie TRUE si la feuille existe et FALSE dans le cas contraire
    ' Argument
    ' Name (String) - Nom de la feuille dont on teste l'existence
    On Error Resume Next
    IsSheetExist = Len(Sheets(Name).Name) > 0
    On Error GoTo 0
    End Function

    Function FeuilleExiste(NomFeuille) As Boolean
    Dim f As Object
    On Error Resume Next
    Set f = Sheets(NomFeuille)
    If Err = 0 Then FeuilleExiste = True
    Set f = Nothing
    End Function
    ‘--------------------------------
    http://www.mdf-xlpages.com/modules/s...q.php?faqid=40
    Function FeuilExiste(F As String) As Boolean
    On Error Resume Next
    FeuilExiste = Not Sheets(F) Is Nothing
    End Function
    ‘--------------------------------
    https://www.developpez.net/forums/d1...feuille-excel/
    Public Function WorkSheetExist(Sheetname As String) As Boolean

    On Error Resume Next
    WorkSheetExist = Sheets(Sheetname).Index
    End Function
    ‘--------------------------------
    Function sheetExists(Feuille) As Boolean ' Code Fait par Marc-L
    sheetExists = Evaluate("ISREF('" & Feuille & "'!A1)")
    End Function
    ‘‘--------------------------------
    Mis à jour 19/11/2019 à 21h01 par MarcelG
  7. Avatar de Guillaume.Chevallier
    • |
    • permalink
    Bonjour,

    Ce matin en relisant le premier billet de la série, j'ai vu tout en bas de page le lien vers le billet "VBA: De la bonne programmation d'un userform".
    Celui-ci répond effectivement à ma question sur la validation des données. La distinction entre validation technique et validation métier est bien compréhensible.

    Je vais d'abord m'attaquer à la validation technique, même si j'essaie au maximum de guider l'utilisateur avec des listes.

    Vos billets sont clairs et concis, ils sont facilement compréhensible. C'est un plaisir de vous lire.


    Guillaume.
  8. Avatar de Pierre Fauconnier
    • |
    • permalink
    Bonsoir Guillaume,

    Enchanté que ces billets vous plaisent et vous aident à développer votre solution ,)

    Qu'entendez-vous par "validation des formulaires"?

    Pour moi, il y a deux types de validation, la validation technique et la validation métier.

    Par validation technique, j'entends le fait de vérifier que si l'on attend une date comme saisie dans un contrôle, ce soit bien une date qui a été saisie. Par validation métier, j'entends le fait que si l'on attend une date comprise dans une période donnée, ce soit bien une date de cette période qui ait été saisie. Je détaille une façon de réaliser cela dans ce billet.

    Pour Access, le problème réside dans le fait que c'est une application tierce à Excel qui va éventuellement rejeter l'erreur. Comme exemples, je citerai évidemment
    • l'intégrité référentielle qui, en dernier ressort, est vérifiée par Access;
    • les macros de données qui pourraient rejeter telle ou telle valeur;
    • les contraintes de validité qui interdiraient un Null;
    • ...


    J'exclus, temporairement du moins, les erreurs dues à des problèmes de type de données, car le passage par des classes personnalisées comme montré dans les billets réduisent normalement le risque d'erreur. On pourrait toutefois gérer les erreurs à ce niveau-là, en préventif comme en curatif.

    Je pense que l'application Excel qui est développée sur base Access doit prévenir autant que possible les problèmes qui pourraient arriver côté Access. Il me semble raisonnable de penser que le développeur Excel est aussi le concepteur de la base Access, de sorte qu'il peut intégrer, soit dans sa BL soit dans sa DAL les règles qui prévalent côté Access.

    Reste que de toute façon, il faut prévoir le rejet par Access, qui se manifestera par la levée d'une exception qui devra être gérée au niveau de la DAL Excel par une valeur de retour des fonctions de la DAL. A charge pour l'appli Excel de gérer ces retours et au programmeur de prévoir que cela remonte jusqu'au userform (de la DAL vers la PL en passant, en trois tiers pur, par la BL). Normalement, les On Error, soit au niveau de la DAL pour capturer l'exception et l'écrire dans un fichier de log, soit en laissant remonter l'erreur jusqu'au userform, sont les instruments qu'il faudra mettre en place pour gérer les rejets d'Access.

    Je vais suivre votre conseil et écrire un cinquième billet ou je modéliserai les trois cas envisagés ici (rejet technique au niveau du formulaire, rejet métier au niveau Excel et rejet par Access géré par les On Error, ainsi que la gestion en préventif ou en curatif au niveau des objets). Je vais essayer d'écrire ce billet dans le début de la semaine prochaine.
  9. Avatar de Guillaume.Chevallier
    • |
    • permalink
    Bonsoir,

    ces 4 billets sont très intéressants et enrichissants. Je suis justement en train de créer une application du même type. Avec deux buts, séparer les données et l'application et que plusieurs personnes puissent travailler dessus.

    Je vais essayer d'améliorer mon application en m'inspirant de ces billets. Notamment les requêtes paramétrées et les requêtes dans access afin de ne pas écrire des requêtes sql concaténées.

    Je voulais savoir si vous gériez la validation des données provenant des formulaires. Si les données ne sont pas valides, renvoyer le formulaire rempli et indicateurs d'erreurs. (peut-être un prochain billet )

    cordialement,

    Guillaume.
  10. Avatar de Pierre Fauconnier
    • |
    • permalink
    Citation Envoyé par papyxy
    Pour mes "critères de simplicité", je pensais a Une liste modifiable, par exemple ou encore passer par un dictionnaire; sans utiliser "Find".
    Parce que l' instruction "Evaluate" est super-compliquée dans cette application, et n' est pas a la portée d' un débutant.
    La liste déroulante ne dispense pas de devoir trouver la ligne. Elle peut être appliquée pour de petites listes et pour autant que le choix soit fait par l'utilisateur, car si j'ai un millier d'articles, j'ai des doutes. De plus, la liste déroulante demande une intervention de l'utilisateur, ce qui n'est pas toujours le cas dans lequel on se trouvera pour récupérer la ligne d'une table de donnée. Si je suis par exemple sur la ligne de détails d'une facture dans une feuille de calcul qui contient un id d'article, je peux avoir besoin, par double clic par exemple, d'afficher la fiche de l'article dans un userform. Dans ce cas, il n'y aura pas de liste déroulante pour le choix de l'article et il faudra utiliser une autre technique (la mienne, un Find, ...). Reviendra alors la notion subjective de "plus simple"... A un "c'est plus simple" qui ne veut rien dire, je préfère la proposition d'une autre solution technique de manière à ce que chacun puisse évaluer, à sa propre subjectivité, les avantages et inconvénients des solutions proposées et à faire son propre choix.

    "Super-compliquée", c'est comme "simple", c'est subjectif, donc ça ne veut objectivement rien dire. Evaluate ne fait qu'évaluer une formule, en l'occurrence un EQUIV. Si on a des problèmes en Excel avec EQUIV, il vaut peut-être mieux qu'on ne se lance pas dans la programmation d'un userform de type CRUD

    La simplicité étant chose subjective, je trouve que utiliser un Dictionary n'est pas plus simple que d'utiliser un Evaluate.

    Cela étant dit, normalement, la recherche d'une ligne dans un tableau structuré devrait s'effectuer au travers d'une fonction générique qui renvoie la ligne du tableau concernée. On passe à cette fonction le tableau, le nom de la colonne et l'ID, et la fonction générique fait le travail en renvoyant soit la ListRow voulue, soit Nothing. Comme elle est générique, on l'écrit une fois, on se la garde au chaud dans un module et on la réutilise pour n'importe quel tableau sans plus trop se préoccuper de comment elle fonctionne.

    Code vba : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Function GetListRow(Table As ListObject, ColumnName As String, Value As Variant) As ListRow
      Dim Formula As String
      Dim Index As Long
     
      If TypeName(Value) = "String" Then Value = """" & Value & """" Else Value = Value * 1
      Formula = "iferror(match({value},{table}[{column}],0),0)"
      Formula = Replace(Formula, "{value}", Value)
      Formula = Replace(Formula, "{table}", Table.Name)
      Formula = Replace(Formula, "{column}", ColumnName)
      Index = Evaluate(Formula)
      If Index > 0 Then Set GetListRow = Table.ListRows(Index)
    End Function

    Ce code permet de retrouver n'importe quelle ligne de n'importe quel tableau structuré muni d'une colonne nommée comme bon vous semble et contenant des valeurs uniques qui peuvent être du texte, une valeur numérique (a priori un long) ou une date. Je pense que normalement, ça couvre les besoins. Il suffit alors de la décortiquer pour la comprendre (si on en a envie), puis de l'utiliser sans plus se tracasser de la façon dont elle travaille. Et franchement, utiliser une fonction à laquelle on passe le tableau, le nom de la colonne et la valeur cherchée, je pense que ce n'est pas compliqué. On fait cela en Excel avec RechercheV, Equiv ou Index-Equiv, les fonctions BD telles que BDLIRE, BDSOMME, ...

    On pourrait l'écrire avec moins de lignes: Formula = Replace(Replace(Replace(...))) mais c'est à mon sens moins lisible. De plus, vu que j'ai intégré ces fonctions génériques depuis longtemps dans mes développements, j'utilise une fonction générique pour remplacer rapidement plusieurs parties de chaine.

    Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    Public Function ReplaceStrings(Source As String, Parameters) As String
      Dim I As Long
     
      ReplaceStrings = Source
      For I = LBound(Parameters) To UBound(Parameters) Step 2
        ReplaceStrings = Replace(ReplaceStrings, Parameters(I), Parameters(I + 1), 1, -1, vbTextCompare)
      Next I
    End Function

    Dès lors, la fonction générique qui renvoie la ListRow devient:
    Code vba : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Function GetListRow(Table As ListObject, ColumnName As String, Value As Variant) As ListRow
      Dim Formula As String
      Dim Index As Long
     
      If TypeName(Value) = "String" Then Value = """" & Value & """" Else Value = Value * 1
      Formula = "iferror(match({value},{table}[{column}],0),0)"
      Formula = ReplaceStrings(Formula, Array("{value}", Value, "{table}", Table.Name, "{column}", ColumnName))
      Index = Evaluate(Formula)
      If Index > 0 Then Set GetListRow = Table.ListRows(Index)
    End Function

    Voici un exemple qui utilise cette fonction. Avec ma définition de la simplicité, je trouve que c'est simple à utiliser
    Code vba : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Sub TestListRow()
      Dim r As ListRow
     
      Set r = GetListRow(Range("tableau2").ListObject, "id", "U")
      If Not r Is Nothing Then
       MsgBox r.Range.Address
      Else
        MsgBox "L'enregistrement n'a pas été trouvé"
      End If
    End Sub

    Si demain je dois pointer vers un tableau nommé t_Vehicules contenant la colonne Immatriculation et chercher la ligne du véhicule immatriculé 1-ABC-123 (plaque belge ), j'utilise GetListRow comme ceci: Set r = getlistrow(range("t_Vehicules").ListObject,"Immatriculation","1-ABC-123"). La fonction générique, qui constitue en fait une "couche d'abstraction", est alors utilisée comme une fonction "native" du langage, et me permet de faire abstraction de Evaluate et de la façon dont elle fonctionne pour me renvoyer la valeur qui m'intéresse.


    En systématisant son approche et en se créant des codes génériques, on crée un code que je qualifierai personnellement et de façon subjective de plus simple à écrire, plus lisible, pérenne, évolutif, facilement testable, bref, plus professionnel
    Mis à jour 18/10/2019 à 10h27 par Pierre Fauconnier
  11. Avatar de WuKoDLaK
    • |
    • permalink
    [supprimé et édité dans le fil du forum par commodité]
    Mis à jour 28/09/2019 à 17h13 par WuKoDLaK
  12. Avatar de Pierre Fauconnier
    • |
    • permalink
    Citation Envoyé par 78chris
    [...]
    Créer une requête vide nommée Pays et dans la barre de formule de PowerQuery taper
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    = Table.FirstValue(Excel.CurrentWorkbook(){[Name="Pays"]}[Content])
    Filtrer la requête issue du tableau t_Ventes avec une des valeurs et dans la barre de Formule remplacer cette valeur (y compris les "") par le nom de variable Pays[...]
    Pour compléter ma réponse précédente, dans le cas où je voudrais filtrer uniquement sur un pays (et non comme, dans ma solution initiale, sur un critère quel qu'il soit), je préfèrerais alors utiliser une table ne contenant qu'une donnée plutôt qu'une plage nommée. Il suffirait alors de monter la table dans Power Query puis de fusionner avec la table principale en inner join... Ca éviterait la manipulation que tu décris sur le filtre dans Power Query car je peux alors utiliser les outils PQ prévus pour, et ça permettrait de renseigner éventuellement plusieurs pays dans la table de critères. Tant qu'à faire, qui peut le plus peut le moins.

  13. Avatar de Pierre Fauconnier
    • |
    • permalink
    Salut Chris

    Merci d'être passé par ici!


    Citation Envoyé par 78chris
    [...]

    On garde le même dynamisme en évitant une colonne...
    Oui, mais on retrouve alors la notion de la "zone de critères" du filtre élaboré. Cela dit, je l'ai dans mon exemple simplement déplacée au sein même du tableau...

    L'astuce de la plage nommée est intéressante, mais elle fige la notion du critère à un pays donné. L'idée de la colonne formulée renvoyant VRAI ou FAUX permet de formuler n'importe quel critère, comme l'illustre l'étape où le critère porte sur la zone et le montant et non plus seulement sur le pays.

    Dans les faits, je suis néanmoins d'accord avec toi pour dire que l'extraction est rarement faite "à la volée"...
  14. Avatar de 78chris
    • |
    • permalink
    Bonjour

    Bonne idée ce billet. Pour compléter :

    On peut aussi utiliser une cellule nommée Pays contenant Belgique ou Benelux ou... (avec si on le souhaite une liste déroulante des pays) et récupérer le contenu de cette cellule comme variable.
    Cette variable est utilisée pour filtrer dans PowerQuery

    Créer une requête vide nommée Pays et dans la barre de formule de PowerQuery taper
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    = Table.FirstValue(Excel.CurrentWorkbook(){[Name="Pays"]}[Content])
    Filtrer la requête issue du tableau t_Ventes avec une des valeurs et dans la barre de Formule remplacer cette valeur (y compris les "") par le nom de variable Pays

    On garde le même dynamisme en évitant une colonne...
  15. Avatar de TSAFACK-M
    • |
    • permalink
    Salut.

    Merci pour ce Billet, c'est assez instructif.

    Je pense que même si Excel n'est à la base pas conçu pour faire ce type de travail, cela reste malgré tout une meilleure approche lorsqu'on veut réaliser des Applications CRUD. D'ailleurs, pour ceux qui ont déjà conçu une Application VBA en utilisant Excel comme base de donnée savent combien cela peut être chiant car si l'Application plante, bonjour les dégâts avec la perte des données ou bien si un fichier Excel est utilisé comme Base Dorsale, les actions y sont limités...

    Personnellement, je conçois toutes mes applications CRUD en utilisant Excel comme un pilote pour manipuler la Base de donnée que ce soit Access ou SQLServer; cela est très pratique et plus professionnel. De la sorte, je peux faire des mises à jour du code dans une copie du fichier sans impacter le travail des utilisateurs puisque le fichier contenant le code est bien séparé de la base de donnée. Et pour améliorer les choses, je peux créer un Ruban avec du XML pour customiser complètement l'espace de travail des utilisateurs.

    Les possibilités sont infinies avec cette approche conceptuelle de la programmation interactive en VBA.

    Cordialement
  16. Avatar de Pierre Fauconnier
    • |
    • permalink
    Bonjour François,


    Citation Envoyé par François DORIN
    [...]Une boucle for est faite pour faire une itération, et l'itérateur ne devrait pas être modifié par le code de la boucle (certains langages interdisent d'ailleurs cela). S'il faut vraiment le faire, je préfère largement l'utilisation d'un while[...]
    je ne peux qu'être d'accord avec toi. J'avais d'ailleurs en tête d'écrire un billet sur le sujet, car effectivement, lorsque je rencontre une boucle For Next, je m'attends à ce qu'elle itère sur chaque élément, alors que la boucle DO WHILE m'indique qu'il y a une condition de sortie.

    Merci pour ton avis, toujours pertinent...
  17. Avatar de François DORIN
    • |
    • permalink
    Effectivement, c'est une astuce... à éviter ! Du point de vue maintenance j'entends.

    Quand on a ce genre de code, il faut penser à celui qui va le relire après. Les instructions portent une sémantique. S'en éloigner vient perturber grandement la lecture d'un programme. Une boucle for est faite pour faire une itération, et l'itérateur ne devrait pas être modifié par le code de la boucle (certains langages interdisent d'ailleurs cela). S'il faut vraiment le faire, je préfère largement l'utilisation d'un while.

    Ici, c'est pareil, c'est un switch transformé en une cascade de if. Ben on fait des if !
  18. Avatar de papyxy
    • |
    • permalink
    Citation Envoyé par Pierre Fauconnier
    Bonjour.

    t_Contacts fait référence à un tableau structuré (table de données, liste de données...)...

    Pour le "il y a plus simple"... N'ayant pas ta grille de critère pour déterminer ce qui est simple de ce qui l'est moins, "il y a plus simple" ne veut rien dire pour moi. Il y a effectivement d'autres techniques, mais chacun verra la simplicité là où il a envie de la voir Personnellement, je n'aime pas les "Find" et les trouve plus compliqués à manipuler et moins souples que les formules utilisées par Evaluate...
    Pour mes "critères de simplicité", je pensais a Une liste modifiable, par exemple ou encore passer par un dictionnaire; sans utiliser "Find".
    Parce que l' instruction "Evaluate" est super-compliquée dans cette application, et n' est pas a la portée d' un débutant.
  19. Avatar de Pierre Fauconnier
    • |
    • permalink
    Bonjour.

    Citation Envoyé par papyxy
    [...]
    le terme "t_Contacts" est déclaré nulle part.[...]
    t_Contacts fait référence à un tableau structuré (table de données, liste de données...)... La première image du billet illustre cela

    Pour le "il y a plus simple"... N'ayant pas ta grille de critère pour déterminer ce qui est simple de ce qui l'est moins, "il y a plus simple" ne veut rien dire pour moi. Il y a effectivement d'autres techniques, mais chacun verra la simplicité là où il a envie de la voir Personnellement, je n'aime pas les "Find" et les trouve plus compliqués à manipuler et moins souples que les formules utilisées par Evaluate...
    Mis à jour 18/10/2019 à 10h23 par Pierre Fauconnier
  20. Avatar de papyxy
    • |
    • permalink
    Bonjour
    ces 2 instructions me laissent perplexe :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
      Row = Evaluate("match(" & ID & ",t_Contacts[ID],0)")
     
        Set getRow = Range("t_Contacts").ListObject.ListRows(Row)
    le terme "t_Contacts" est déclaré nulle part.
    Quant a trouver la ligne concernée: il y-a plus simple.
Page 7 sur 10 PremièrePremière ... 345678910 DernièreDernière