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

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Macros et VBA Excel Discussion :

VBA, remplir un tableau structuré (ListObject)


Sujet :

Macros et VBA Excel

  1. #1
    Membre Expert
    Avatar de tototiti2008
    Homme Profil pro
    Formateur/développeur
    Inscrit en
    Octobre 2008
    Messages
    1 414
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Formateur/développeur

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 414
    Billets dans le blog
    3
    Par défaut VBA, remplir un tableau structuré (ListObject)
    Bonjour,

    J'ai décidé de faire quelques tests sur le remplissage d'un tableau structuré en VBA
    Les soucis souvent observés : une grande lenteur si on utilise l'objet ListObject, ListRow ou ListColumn dans le code
    Je vous fait un résumé de mes tests parce que je pense que ça peut servir à d'autres

    L'idée est de remplir un tableau avec 2 colonnes à partir de la cellule A1
    Les 2 colonnes s'appellent a et b
    la colonne a devra contenir des nombres entiers de 1 à 10 000 (10 0000 lignes de tableau donc)
    la colonne b devra contenir une formule simple : la lettre "z" collée au contenu de la colonne a
    Le tableau créé s'appelle Tableau1

    1ère méthode :
    désactiver l'affichage écran
    ajouter une ligne (Listrows.Add)
    écrire dedans en colonne a le nombre
    en colonne b la formule

    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
    Sub Remplir1()
    Dim LO As ListObject, LR As ListRow, i As Long
        With Sheets("Feuil1")
            Set LO = .ListObjects("Tableau1")
            Application.ScreenUpdating = False
            .Range("J2").Value = Now
            LO.Range.Cells(1, 1).Offset(1, 0).Value = 1
            LO.Range.Cells(1, 1).Offset(1, 1).Formula = "=""z""&[@a]"
            For i = 2 To 10000
                Set LR = LO.ListRows.Add
                LR.Range.Cells(1, 1).Value = i
                LR.Range.Cells(1, 2).Formula = "=""z""&[@a]"
            Next i
            .Range("K2").Value = Now
            Application.ScreenUpdating = True
        End With
    End Sub
    Temps d'exécution chez moi : environ 2 minutes

    méthode 2 : la même en désactivant les calculs en plus

    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
    Sub Remplir2()
    Dim LO As ListObject, LR As ListRow, i As Long
        With Sheets("Feuil1")
            Set LO = .ListObjects("Tableau1")
            Application.ScreenUpdating = False
            Application.Calculation = xlCalculationManual
            .Range("J3").Value = Now
            LO.Range.Cells(1, 1).Offset(1, 0).Value = 1
            LO.Range.Cells(1, 1).Offset(1, 1).Formula = "=""z""&[@a]"
            For i = 2 To 10000
                Set LR = LO.ListRows.Add
                LR.Range.Cells(1, 1).Value = i
                LR.Range.Cells(1, 2).Formula = "=""z""&[@a]"
            Next i
            .Range("K3").Value = Now
            Application.ScreenUpdating = True
            Application.Calculation = xlCalculationAutomatic
        End With
    End Sub
    Temps d'exécution chez moi : environ 1 minute 30 sec

    Bon je vous passe tous les tests intermédiaires

    méthode 5 : on remplit un tableau VBA (Array) de 10000 lignes et 1 colonne avec des nombres de 1 à 10000
    on écrit ce tableau à partir de A2 dans la feuille de calcul
    on s'assure que le tableau s'est agrandi en lui imposant la bonne taille
    on colle la formule en colonne b

    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
    Sub Remplir5()
    Dim LO As ListObject, i As Long, Tablo()
        With Sheets("Feuil1")
            Set LO = .ListObjects("Tableau1")
            Application.ScreenUpdating = False
            Application.Calculation = xlCalculationManual
            .Range("J6").Value = Now
            ReDim Tablo(1 To 10000, 1 To 1)
            For i = 1 To 10000
                Tablo(i, 1) = i
            Next i
            LO.Range.Offset(1, 0).Resize(10000, 1).Value = Tablo
            LO.Resize .Range("$A$1:$B$10001")
            LO.ListColumns("b").DataBodyRange.Formula = "=""z""&[@a]"
            .Range("K6").Value = Now
            Application.ScreenUpdating = True
            Application.Calculation = xlCalculationAutomatic
        End With
    End Sub
    temps d'exécution : moins d'1 seconde

  2. #2
    Membre Expert
    Avatar de tototiti2008
    Homme Profil pro
    Formateur/développeur
    Inscrit en
    Octobre 2008
    Messages
    1 414
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Formateur/développeur

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 414
    Billets dans le blog
    3
    Par défaut
    Re,

    Après si vous avez de meilleures idées, dites le moi
    peut-être y a t'il plus direct

  3. #3
    Membre Expert
    Avatar de tototiti2008
    Homme Profil pro
    Formateur/développeur
    Inscrit en
    Octobre 2008
    Messages
    1 414
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Formateur/développeur

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 414
    Billets dans le blog
    3
    Par défaut
    Re,
    même principe pour vider le tableau

    méthode 1
    vider chaque ligne (ListRow.Delete)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Sub Efface1()
    Dim LO As ListObject, i As Long, NbLig As Long
        With Sheets("Feuil1")
            .Range("J7").Value = Now
            Set LO = .ListObjects("Tableau1")
            NbLig = LO.ListRows.Count
            For i = 1 To NbLig
                LO.ListRows(1).Delete
            Next
            .Range("K7").Value = Now
        End With
    End Sub
    environ 3 minutes

    méthode 2 :
    effacer les cellules et redimensionner le tableau

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Sub Efface2()
    Dim LO As ListObject
        With Sheets("Feuil1")
            .Range("J8").Value = Now
            Set LO = .ListObjects("Tableau1")
            LO.DataBodyRange.ClearContents
            LO.Resize .Range("$A$1:$B$2")
            .Range("K8").Value = Now
        End With
    End Sub
    moins d'1 seconde

  4. #4
    Expert confirmé
    Homme Profil pro
    retraité
    Inscrit en
    Juin 2012
    Messages
    3 465
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : retraité
    Secteur : Associations - ONG

    Informations forums :
    Inscription : Juin 2012
    Messages : 3 465
    Par défaut
    En ajustant le code que m'a proposé l'IA, cela se fait en 0.06 secondes (Intel Core i7).
    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
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    Sub CreerRemplirTableau1()
        Dim ws As Worksheet
        Dim tbl As ListObject
        Dim debutTemps As Single
        Dim dataA As Variant, i As Long
     
        Set ws = ActiveSheet  ' Ou Worksheets("Feuil1")
     
        debutTemps = Timer
     
        Application.ScreenUpdating = False
        Application.Calculation = xlCalculationManual
     
        ' Efface si existe
        On Error Resume Next
        ws.ListObjects("Tableau1").Delete
        On Error GoTo 0
     
        ws.Range("A1:B10000").Clear
     
        ' Array pour A (1 à 10000)
        ReDim dataA(1 To 10000, 1 To 1)
        For i = 1 To 10000
            dataA(i, 1) = i
        Next i
     
        ws.Range("A1").Resize(10000, 1).Value = dataA
     
        ' **Ajout en-têtes EXPLICITES** avant création
        ws.Range("A1").Value = "A"
        ws.Range("B1").Value = "B"
        ws.Range("A2").Resize(10000, 1).Value = dataA  ' Décale data vers A2:A10000
     
        ' Crée tableau sur A1:B10000 avec en-têtes fournis
        Set tbl = ws.ListObjects.Add(xlSrcRange, ws.Range("A1:B10001"), , xlYes)
        tbl.Name = "Tableau1"
     
        ' Formule en colonne B (toutes lignes, index sûr)
        tbl.ListColumns(2).DataBodyRange.Formula = "=""z "" & [@A]"
     
        Application.Calculation = xlCalculationAutomatic
        Application.ScreenUpdating = True
     
        Range("J6") = "Tableau1 créé et rempli en " & Format(Timer - debutTemps, "0.00") & " secondes."
    End Sub

  5. #5
    Rédacteur

    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Août 2013
    Messages
    1 051
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : Finance

    Informations forums :
    Inscription : Août 2013
    Messages : 1 051
    Par défaut
    Citation Envoyé par EricDgn Voir le message
    En ajustant le code que m'a proposé l'IA, cela se fait en 0.06 secondes (Intel Core i7).
    Effectivement, si vous posez une formule en première ligne, elle est automatiquement recopiée par Excel sur les lignes qui suivent, pas besoin de faire une boucle pour modifier 10 000 cellules.
    Mais ça ne répond pas à la remarque formulée par tototiti2008 : la modification de la valeur d'une cellule dans un tableau structuré est plus chronophage que dans une plage classique. Et sur de grandes interventions ça devient gênant.

    Une solution que je propose :
    1 : enregistrer le contenu du tableau dans une variable, par exemple : Mémoire = TS.ListObject.DataBodyRange.Formula
    2 : faire les modifications voulues dans cette mémoire : Mémoire(Ligne, Colonne) = NouvelleValeur
    3 : copier cette mémoire dans le tableau : TS.ListObject.DataBodyRange.Formula = Mémoire

    C'est ce que je fais avec la fonction TS_ModifCellule

    Plus d'informations et de fonctions pour gérer les tableaux structurés dans cette documentation : https://laurent-ott.developpez.com/t...aux-Structures

    Bonne continuation.

  6. #6
    Expert confirmé
    Homme Profil pro
    retraité
    Inscrit en
    Juin 2012
    Messages
    3 465
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : retraité
    Secteur : Associations - ONG

    Informations forums :
    Inscription : Juin 2012
    Messages : 3 465
    Par défaut
    Oui, tout à fait d'accord: effectuer des modifications dans un tableau structuré est trop souvent plus chronophage que dans une plage classique ... ce qui conduit à passer par des tableaux (array) temporaires (ou Power Query).
    Bien cordialement.

  7. #7
    Membre Expert
    Avatar de tototiti2008
    Homme Profil pro
    Formateur/développeur
    Inscrit en
    Octobre 2008
    Messages
    1 414
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Formateur/développeur

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 414
    Billets dans le blog
    3
    Par défaut
    Bonjour,

    Merci de vos remarques

    En ajustant le code que m'a proposé l'IA, cela se fait en 0.06 secondes (Intel Core i7).
    Les dernières versions de chacuns de mes codes sont également rapides, après on pourrait faire une comparaison plus fine

    Cependant, à mon avis, la version proposée par l'IA a plusieurs soucis
    1) Elle supprime le tableau
    On perd donc les éventuelles couleurs particulières du style de tableau
    Il faudrait peut-être en plus récupérer le style de tableau précédent
    2) Elle efface les cellules avec Clear
    On perd donc le format des cellules
    3) elle part du principe que le tableau va s'agrandir
    Alors, oui, c'est généralement le cas mais c'est lié à une option d'Excel que l'on n'a pas testé
    Donc moi j'ai rajouté des bretelles à la ceinture en redimensionnant le tableau à la bonne taille (j'aurais pu tester l'option mais je ne sais plus par coeur où elle est)
    Pour le reste, elle fait la même chose que mon dernier code

    Une solution que je propose :
    1 : enregistrer le contenu du tableau dans une variable, par exemple : Mémoire = TS.ListObject.DataBodyRange.Formula
    2 : faire les modifications voulues dans cette mémoire : Mémoire(Ligne, Colonne) = NouvelleValeur
    3 : copier cette mémoire dans le tableau : TS.ListObject.DataBodyRange.Formula = Mémoire

    C'est ce que je fais avec la fonction TS_ModifCellule
    Bonne piste pour les modifications
    J'avoue là je m'étais concentré sur les suppressions de lignes en masse et l'ajout de lignes en masse car c'est qui me semblait le plus lent au premier abord

  8. #8
    Membre Expert
    Avatar de tototiti2008
    Homme Profil pro
    Formateur/développeur
    Inscrit en
    Octobre 2008
    Messages
    1 414
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Formateur/développeur

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 414
    Billets dans le blog
    3
    Par défaut
    Re,

    l'option qui fait que parfois le tableau ne s'agrandit pas :
    https://www.developpez.net/forums/d2.../#post12069815

  9. #9
    Membre Expert
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    1 564
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 1 564
    Par défaut
    Hello,

    Ce n'est pas un secret,
    Parcourir cellule par cellule une plage (que ce soit issu d'un tableau structuré ou non), c'est lent !
    Passer par un tableau 2D est bien plus rapide (puisque les plages sont convertibles en tableau et vice-versa).
    Par contre, on perd en lisibilité du code source.
    A utiliser selon les besoins.

  10. #10
    Membre Expert
    Avatar de tototiti2008
    Homme Profil pro
    Formateur/développeur
    Inscrit en
    Octobre 2008
    Messages
    1 414
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Formateur/développeur

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 414
    Billets dans le blog
    3
    Par défaut
    Bonsoir,

    Ce n'est pas un secret,
    Parcourir cellule par cellule une plage (que ce soit issu d'un tableau structuré ou non), c'est lent !
    oui mais pas à ce point

    le code suivant écrit dans les cellules
    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
    Sub Remplir6()
    Dim i As Long
        With Sheets("Feuil1")
            Application.ScreenUpdating = False
            Application.Calculation = xlCalculationManual
            .Range("J9").Value = Now
            For i = 1 To 10000
                .Cells(i + 1, 1).Value = i
                .Cells(i + 1, 2).FormulaR1C1 = "=""z""&rc[-1]"
            Next i
            Application.ScreenUpdating = True
            Application.Calculation = xlCalculationAutomatic
            .Range("K9").Value = Now
        End With
    End Sub
    il met 7 secondes à s'éxécuter chez moi, à comparer aux 1 minutes 30 secondes quand on a un tableau structuré avec Listrows.Add

  11. #11
    Membre Expert
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    1 564
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 1 564
    Par défaut
    Je pense que c'est simplement parceque l'objet ListObject est plus lourd que l'objet Range.

  12. #12
    Membre Expert
    Avatar de tototiti2008
    Homme Profil pro
    Formateur/développeur
    Inscrit en
    Octobre 2008
    Messages
    1 414
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Formateur/développeur

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 414
    Billets dans le blog
    3
    Par défaut
    Bonjour,

    Oui, 13 X plus lourd si je fais un rapport des temps de traitement

Discussions similaires

  1. [XL-2007] Problème de filtrage avec VBA d'un tableau structuré
    Par ESVBA dans le forum Macros et VBA Excel
    Réponses: 5
    Dernier message: 03/08/2023, 23h20
  2. [XL-2016] Liste de validation depuis un tableau structuré (listobject)
    Par benoitdevries dans le forum Macros et VBA Excel
    Réponses: 5
    Dernier message: 14/05/2019, 19h29
  3. [XL-2007] VBA : remplir un tableau // incomptabilité de type
    Par jnauche dans le forum Excel
    Réponses: 3
    Dernier message: 13/03/2014, 15h19
  4. [XL-2003] VBA-Remplir un tableau a deux dimensions
    Par gualoule dans le forum Excel
    Réponses: 3
    Dernier message: 05/08/2009, 01h49
  5. [VBA] remplir un tableau suivant certaines contraintes
    Par perophron dans le forum Général VBA
    Réponses: 11
    Dernier message: 02/05/2007, 11h30

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo