Astuces VBA

Dates et heures :

  • Calculer le nombre de jours dans un mois

    Pour calculer le nombre de jours dans un mois ou définir le dernier jour du mois, vous pouvez utiliser la formule suivante :
    Sub nb_jours_mois()
       
        date_test = CDate("6/2/2012") 'Une date quelconque pour cet exemple

        nb_jours = Day(DateSerial(Year(date_test), Month(date_test) + 1, 1) - 1)
       
    End Sub

    Pour mieux comprendre cette formule, la voici dans une version décortiquée et commentée :
    Sub nb_jours_mois()
       
        'Une date quelconque pour cet exemple
        date_test = CDate("6/2/2012")
       
        'Mois / année de la date
        mois = Month(date_test)
        annee = Year(date_test)
       
        'Calcul du premier jour du mois suivant
        date_mois_suivant = DateSerial(annee, mois + 1, 1)
       
        'Date du dernier jour
        dernier_jour_mois = date_mois_suivant - 1
       
        'Nombre de jour dans le mois (= dernier jour)
        nb_jours = Day(dernier_jour_mois)
       
    End Sub

    Fonction

    Vous pouvez également l'utiliser en tant que fonction en ajoutant le code suivant dans un module :
    Function NB_JOURS(date_test As Date)
        NB_JOURS = Day(DateSerial(Year(date_test), Month(date_test) + 1, 1) - 1)
    End Function
    Exemple d'utilisation de la fonction en VBA :
    Sub exemple()
        test = NB_JOURS(Range("A1"))
        MsgBox test
    End Sub
    fonction - nb jours dans mois Exemple d'utilisation de cette même fonction sur une feuille de calcul :
    fonction2 - nb jours dans mois
  •  
  • Formats d'affichage des dates et heures

    Voici les principaux caractères utilisables pour définir le format des dates et heures :

    CaractèresExempleDescription
    d7Jour (numérique sans zéro)
    dd07Jour (numérique avec zéro)
    dddmar.Jour (texte raccourci)
    ddddmardiJour (texte entier)
    m2Mois (numérique sans zéro)
    mm02Mois (numérique avec zéro)
    mmmfévrMois (texte raccourci)
    mmmmfévrierMois (texte entier)
    yy12Année (2 derniers chiffres)
    yyyy2012Année (4 chiffres)
    h8Heures sans zéro (0-23)
    hh08Heures avec zéro (00-23)
    n3Minutes sans zéro (0-59)
    nn03Minutes avec zéro (00-59)
    s8Secondes sans zéro (0-59)
    ss08Secondes avec zéro (00-59)
    Ainsi que quelques exemples de formats de dates et heures :
    Sub dates_et_heures()

        'Now renvoie la date et l'heure en cours (07.02.2012 09:09:02)
        date_test = Now()
       
        'Renvoie : 07.02.12
        Range("A1") = Format(date_test, "dd.mm.yy")

        'Renvoie : mardi 7 février 2012
        Range("A2") = Format(date_test, "dddd d mmmm yyyy")

        'Renvoie : Mardi 7 Février 2012
        Range("A3") = WorksheetFunction.Proper(Format(date_test, "dddd d mmmm yyyy"))

        'Renvoie : mar. 07
        Range("A4") = Format(date_test, "ddd dd")

        'Renvoie : MAR 07
        Range("A5") = "'" & Replace(UCase(Format(date_test, "ddd dd")), ".", "")

        'Renvoie : FÉVRIER 2012
        Range("A6") = UCase(Format(date_test, "mmmm yyyy"))
       
        'Renvoie : 07.02.2012 09:09
        Range("A7") = Format(date_test, "dd.mm.yyyy hh:mm")

        'Renvoie : Le 7 février à 9h09'02''
        Range("A8") = Format(date_test, "Le d mmmm à h\hmm'ss''")

        'Renvoie : 9H09
        Range("A9") = Format(date_test, "h\Hmm")

    End Sub
     

Divers :

  • Diminuer le temps d'exécution d'une macro

    Lorsque vous utilisez une macro qui effectue un grand nombre de modifications sur votre feuille, Excel actualise l'affichage à chaque modification ce qui peut considérablement ralentir la macro ...
    Pour demander à Excel de ne pas actualiser l'affichage, ajoutez ceci :
    Sub exemple()

        Application.ScreenUpdating = False
       
        'Code ici ...
     
        Application.ScreenUpdating = True 'Facultatif
     
    End Sub

    Exemple concret de gain de temps

    Le test suivant a été effectué avec la macro qui gènère le calendrier annuel de l'application Calendrier-Pratique.
    Sans ScreenUpdating, le temps d'exécution était de 31.97 secondes :
    avant - screenupdating Avec ScreenUpdating, le temps d'exécution a été réduit à seulement 0.44 secondes :
    apres - screenupdating Si votre macro est un peu lente, pensez-y !
     
  • Comment activer les macros ?

    Dans la plupart des cas, lorsque vous ouvrez pour la première fois un classeur qui contient des macros, Excel les désactive par mesure de sécurité et vous demande si vous souhaitez activer les macros (exemple avec Excel 2010) :
    macros - activer les macros Mais il peut arriver que les macros soient désactivées et qu'Excel ne vous propose pas de les activer ...
    Pour commencer (si ce n'est pas déjà fait), enregistrez le fichier sur votre PC (si vous ouvrez un fichier Excel depuis un site Web directement, sans l'enregistrer, les macros sont parfois désactivées sans notification).
    L'activation/désativation des macros diffère selon la version d'Excel utilisée. Vous trouverez ci-dessous des informations pour activer les macros pour la plupart des versions d'Excel (2013/2010/2007/2002).

    Activer les macros (EXCEL 2013)

    Cliquez sur "FICHIER" > "Options" :
    2013 options - activer les macros Puis sur "Centre de gestion de la confidentialité" > "Paramètres du Centre de gestion de la confidentialité" :
    2013 confidentialite - activer les macros Et enfin sur "Paramètres des macros" :
    2013 activer - activer les macros Le choix par défaut (et recommandé) est "Désactiver toutes les macros avec notification" (c'est celui qui vous invite à activer les macros à l'ouverture).

    Activer les macros (EXCEL 2010)

    Cliquez sur "Fichier" > "Options" :
    2010 options - activer les macros Puis sur "Centre de gestion de la confidentialité" > "Paramètres du Centre de gestion de la confidentialité" :
    2010 confidentialite - activer les macros Et enfin sur "Paramètres des macros" :
    2010 activer - activer les macros Le choix par défaut (et recommandé) est "Désactiver toutes les macros avec notification" (c'est celui qui vous invite à activer les macros à l'ouverture).

    Activer les macros (EXCEL 2007)

    Cliquez sur "Options Excel" :
    2007 options - activer les macros Puis sur "Centre de gestion de la confidentialité" > "Paramètres du Centre de gestion de la confidentialité" :
    2007 confidentialite - activer les macros Et enfin sur "Paramètres des macros" :
    2007 activer - activer les macros Le choix recommandé est "Désactiver toutes les macros avec notification" (c'est celui qui vous invite à activer les macros à l'ouverture).

    Activer les macros (EXCEL 2002)

    Cliquez sur "Outils" > "Macro" > "Sécurité" :
    2002 securite - activer les macros Le choix recommandé est "Niveau de sécurité moyen" (c'est celui qui vous invite à activer les macros à l'ouverture).
    2002 niveau securite - activer les macros
  • Créer une animation

    Pour apprendre à réaliser une animation (par exemple : déplacer un objet de manière fluide), un tutoriel vidéo a été créé.

    Sub DeplacerUnObjet()
        
        If Sheets("Feuil1").TextBox_recherche.Value = "" Then 'Si champ vide
            
            Sheets("Feuil1").Shapes("Fleche").Top = 7.5
     
            Sheets("Feuil1").Shapes("Fleche").Left = 306
     
            Range("A1").Select
     
            secondes = 0.01
     
            For ii = 1 To 3
     
                For i = 3 To 117 Step 3
     
                    timer_avant = Timer
     
                    Do While Timer < timer_avant + secondes
                        DoEvents
                    Loop
     
                    Sheets("Feuil1").Shapes("Fleche").Left = 306 - i
     
                    Range("A1").Select
     
                Next
     
                For i = 3 To 117 Step 3
     
                    timer_avant = Timer
     
                    Do While Timer < timer_avant + secondes
                        DoEvents
                    Loop
     
                    Sheets("Feuil1").Shapes("Fleche").Left = 189 + i
     
                    Range("A1").Select
     
                Next
     
            Next
     
            Sheets("Feuil1").Shapes("Fleche").Left = 2000
     
        Else 'Si champ rempli
        
            'Instructions pour la recherche ici ...
            
        End If
     
    End Sub


  • Désactiver les événements

    Si vous avez besoin d'exécuter un bout de code sans déclencher d'événements, placez le code entre ces 2 lignes :
    Sub exemple()

        Application.EnableEvents = False ' => désactive les événements
     
        'Le code ...
     
        Application.EnableEvents = True ' => réactive les événements
     
    End Sub
     
  • Effectuer une action selon la version d'Excel

    Pour déterminer la version d'Excel de l'utilisateur et effectuer une action différente selon la version en cours d'utilisation, vous pouvez utiliser Val(Application.Version) qui vous renvoie (le numéro de) la version d'Excel.

    Voici les numéros des versions d'Excel à utiliser pour effectuer des tests :
    8Excel 97 (Mac : 98)
    9Excel 2000 (Mac : 2001)
    10Excel 2002
    11Excel 2003 (Mac : 2004)
    12Excel 2007 (Mac : 2008)
    14Excel 2010 (Mac : 2011)
    15Excel 2013
    Par exemple pour tester si la version d'Excel est inférieure à 2007, vous pouvez utiliser ce code :
    If Val(Application.Version) < 12 Then
        'Si version d'Excel inférieure à 2007
    Else
        'Si version d'Excel égale à 2007 ou supérieure
    End If
  • Importer des données d'un site Web

    Pour apprendre à créer une macro pour importer des données à partir d'un site Web, un tutoriel vidéo a été créé.
  • Stopper une macro en cours d'exécution

    Il peut arriver qu'on lance une macro bien trop lente ou pire encore, une boucle infinie ...
    Heureusement, avec Ctrl + Pause (Break) il est possible de stopper une macro en cours d'exécution !
    stop - stopper macro

Feuilles et classeurs :

  • Empêcher la modification du nom d'une feuille

    Si la modification du nom d'une feuille Excel peut provoquer des erreurs, il peut être intéressant de l'interdire.
    Une solution simple consiste à entrer le code suivant dans la feuille qui vous intéresse et remplacer Exemple par le nom de la feuille :
    Private Sub Worksheet_SelectionChange(ByVal Target As Range)
        If ActiveSheet.Name <> "Exemple" Then
            ActiveSheet.Name = "Exemple"
        End If
    End Sub
    A chaque changement de sélection, le nom de la feuille sera vérifié et remplacé si nécessaire.
     
  • Empêcher l'enregistrement d'un fichier Excel

    Si vous avez créé un fichier qui nécessite l'activation des macros pour fonctionner et que vous souhaitez interdire l'enregistrement de modifications, c'est possible et ça ne prend qu'un instant.

    Ouvrez votre fichier sans activer les macros (ou en activant le "Mode Création") et collez le code suivant dans ThisWorkbook :
    Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
        Cancel = True 'Annule les demandes d'enregistrement
    End Sub

    Private Sub Workbook_BeforeClose(Cancel As Boolean)
        Application.ThisWorkbook.Saved = True 'Informe Excel que le fichier a déjà été enregistré (cela évite d'avoir une demande d'enregistrement à la fermeture)
    End Sub
    Il ne vous reste plus qu'à enregistrer votre fichier (vous pouvez toujours l'enregistrer tant que les macros sont désactivées).
  • Interdire la sélection de plusieurs cellules

    Une solution pour interdire à l'utilisateur de sélectionner plusieurs cellules à la fois est d'ajouter cette simple ligne de code dans l'événement Worksheet_SelectionChange de la feuille où cette interdiction doit être appliquée :
    Private Sub Worksheet_SelectionChange(ByVal Target As Range)
        ActiveCell.Select
    End Sub
    A chaque changement de sélection, la cellule active sera sélectionnée (ActiveCell = 1 seule cellule) ...

    Forcer l'activation des macros

    Une solution consiste à masquer préalablement toutes les feuilles sauf une puis, lorsque l'utilisateur active les macros, afficher toutes les feuilles ...

    Pour mettre en place cette solution, commencez par créer la feuille de démarrage (celle que l'utilisateur verra tant que les macros ne seront pas activées) :
    feuille demarrage - forcer activation des macros Masquez ensuite toutes les feuilles sauf celle de démarrage (propriété : Visible) :
    visible - forcer activation des macros Et entrez le code suivant dans ThisWorkbook :
    Private Sub Workbook_Open()

        'Affichage de la feuille EXEMPLE
        Sheets("EXEMPLE").Visible = -1
       
        'Feuille de démarrage cachée
        Sheets("MACROS").Visible = 2

    End Sub
    Enregistrez, fermez et testez !
    Le fichier de cet exemple : exemple.xls

  • Masquer les onglets

    Pour masquer les onglets d'un classeur et ainsi empêcher la navigation entre les feuilles, utilisez le code suivant :
    Sub masquer()
        ActiveWindow.DisplayWorkbookTabs = False
    End Sub
    Et pour réafficher les onglets :
    Sub afficher()
        ActiveWindow.DisplayWorkbookTabs = True
    End Sub

Mise en forme :

  • Mise en forme de caractères dans une cellule

    Pour modifier la mise en forme de certains caractères, utilisez Characters :
    Range("A1").Characters(NO_DEPART, NB_DE_CARACTERES)

    Exemple pratique

    depart - mise en forme caracteres Dans cet exemple, la macro passera les 2-3 premiers caractères en italique et le nom de la ville en gras :
    objectif - mise en forme caracteres La macro en détails :
    Sub test()

        For ligne = 1 To 12
       
            'Contenu de la cellule
            contenu = Cells(ligne, 1)
           
            'Contenu divisé en un tableau de 3 parties
            tab_contenu = Split(contenu, " ")
           
            'Longueur de la partie 1
            longueur_partie_1 = Len(tab_contenu(0))
           
            'Longueur de la partie 2
            longueur_partie_2 = Len(tab_contenu(1))
           
            'Partie 1 en ITALIQUE
            Cells(ligne, 1).Characters(1, longueur_partie_1).Font.Italic = True
           
            'Partie 2 en GRAS
            Cells(ligne, 1).Characters(longueur_partie_1 + 2, longueur_partie_2).Font.Bold = True

        Next

    End Sub

Nombres et calculs :

  • Générer des nombres aléatoires


    Voici le code à utiliser pour générer une valeur aléatoire entre 1 et 50 :
    Sub aleatoire()

        'Initialiser le générateur de nombres aléatoires
        '=> Randomize : à ajouter avant d'utiliser Rnd pour obtenir des valeurs complètement aléatoires
        Randomize
       
        'Nombre aléatoire entier entre 1 et 50 :
        nombre_aleatoire = Int(50 * Rnd) + 1
       
        MsgBox nombre_aleatoire
       
    End Sub
    Pour obtenir par exemple une valeur entre 1 et 22, remplacez simplement 50 (dans le code ci-dessus) par 22.
  • Générer des codes aléatoires

    Sub code_alea()
        'www.blog-excel.com/generer-code-aleatoire
        Randomize
     
        carac = "ABCD1234"
        lettre_aleatoire = ""
     
        For i = 1 To 10
            nombre_aleatoire = Int(Len(carac) * Rnd) + 1
            lettre_aleatoire = lettre_aleatoire & Mid(carac, nombre_aleatoire, 1)
            If i = 5 Then lettre_aleatoire = lettre_aleatoire & "-"
        Next
     
        MsgBox lettre_aleatoire
    End Sub
  • Racine carrée / carré

    Racine carrée

    Pour obtenir la racine carrée d'une valeur en VBA, vous avez besoin de la fonction Sqr :
    Sub exemple()

        nombre = 9
       
        MsgBox Sqr(nombre) 'Affiche la racine carrée : 3

    End Sub

    Carré

    Pour obtenir le carré d'un nombre, il vous suffit d'utiliser "^" (comme pour une formule dans une cellule) :
    Sub exemple()

        nombre = 9
       
        MsgBox nombre ^ 2 'Affiche le carré : 81
        MsgBox nombre ^ 3 'Affiche le cube : 729

    End Sub

UserForm et contrôles :

  • Créer un champ de recherche en VBA

    Dans ce tutoriel, vous verrez comment mettre en place un champ de recherche (TextBox) et afficher les résultats de différentes manières (dans cet exemple, affichage des résultats : sur la feuille + dans une ListBox) :champ-recherche - champ-de-recherche-vba
  • Option Compare Text
     
    Private Sub TextBox1_Change()
        
        Application.ScreenUpdating = False
     
        Range("A2:A24").Interior.ColorIndex = 2 'Exemple 1 (feuille)
        ListBox1.Clear 'Exemple 2 (ListBox)
        
        If TextBox1 <> "" Then
            For ligne = 2 To 24
                If Cells(ligne, 1) Like "*" & TextBox1 & "*" Then
                    Cells(ligne, 1).Interior.ColorIndex = 43 'Exemple 1 (feuille)
                    ListBox1.AddItem Cells(ligne, 1) 'Exemple 2 (ListBox)
                End If
            Next
        End If
     
    End Sub

    Créer une barre de progression


    Aperçu de la barre :
    Barre de progression Excel (progress bar)
  • Liste déroulante personnalisée


    Le contrôle ComboBox ne permet pas de mettre en forme les lignes de sa liste.
    Pourtant, la liste déroulante visible sur cette image fonctionne très bien :
    combobox coloree - creer liste deroulante personnalisee
  • UserForm modal


    Pour comprendre comment travailler sur une feuille Excel tout en ayant un UserForm ouvert, consultez le tutoriel vidéo disponible sur le blog Excel-Pratique :
  • Utiliser des variables dans le nom d'un contrôle

    Pouvoir agir sur un contrôle en fonction d'une variable peut s'avérer très utile pour développer plus efficacement.

    Par exemple, pour supprimer le contenu de 20 TextBox, il est possible d'écrire :
    Private Sub CommandButton_vider_Click()
       
        TextBox1.Value = ""
        TextBox2.Value = ""
        TextBox3.Value = ""
        TextBox4.Value = ""
        TextBox5.Value = ""
        TextBox6.Value = ""
        TextBox7.Value = ""
        TextBox8.Value = ""
        TextBox9.Value = ""
        TextBox10.Value = ""
        TextBox11.Value = ""
        TextBox12.Value = ""
        TextBox13.Value = ""
        TextBox14.Value = ""
        TextBox15.Value = ""
        TextBox16.Value = ""
        TextBox17.Value = ""
        TextBox18.Value = ""
        TextBox19.Value = ""
        TextBox20.Value = ""
       
    End Sub
    Mais grâce à Controls, il est possible de réduire le code à 3 lignes :
    Private Sub CommandButton_vider_Click()
       
        For i = 1 To 20
            Controls("TextBox" & i).Value = ""
        Next
       
    End Sub

Variables :

  • Supprimer une variable tableau

    Si vous souhaitez réinitialiser un tableau pour pouvoir modifier sa taille et son contenu, utilisez l'instruction Erase.

    Exemple avec un tableau dynamique :

    Sub exemple_simple()
       
        nombre_exemple = 11
       
        'Déclaration du tableau dynamique
        Dim tab_exemple()
       
        'Redimensionnement
        ReDim tab_exemple(nombre_exemple - 1)
       
        'EXEMPLE
        MsgBox UBound(tab_exemple) ' => renvoie : 10
     
        'Suppression du tableau
        Erase tab_exemple
       
        'Nouveau redimensionnement possible après suppression
        ReDim tab_exemple(15)
       
        'EXEMPLE
        MsgBox UBound(tab_exemple) ' => renvoie : 15
     
    End Sub
    L'instruction Erase peut s'avérer très utile lorsque votre tableau dynamique est déclaré en tant que variable Global ...

    Exemple avec un tableau de taille fixe :

    Sub exemple_simple()
       
        'Déclaration du tableau
        Dim tab_exemple(10)
       
        'EXEMPLE : attribution de valeurs
        For i = 0 To 10
            tab_exemple(i) = i
        Next
       
        'EXEMPLE
        MsgBox tab_exemple(5) ' => renvoie : 5
     
        'Suppression du contenu du tableau
        Erase tab_exemple
       
        'EXEMPLE
        MsgBox tab_exemple(5) ' => ne renvoie rien (vide)
     
    End Sub
    Avec un tableau de taille fixe, les éléments sont réinitialisés (vidés).

Cours VBA : utilisations des fonctions Excel

Il est possible d'utiliser les fonctions Excel dans le code VBA.
Après avoir entré WorksheetFunction, la liste des fonctions apparaît :
1 - fonctions vba Les fonctions sont toutes en anglais ...
Pour s'y retrouver, une liste des fonctions traduites en anglais est disponible sur ce site, en voici un extrait :
Fonction en françaisFonction en anglaisDescription de la fonction
NBCOUNTdétermine les nombres compris dans la liste des arguments.
NB.SICOUNTIFcompte le nombre de cellules qui répondent à un critère donné dans une plage.
NB.SI.ENSCOUNTIFScompte le nombre de cellules à l’intérieur d’une plage qui répondent à plusieurs critères.
NB.VIDECOUNTBLANKcompte le nombre de cellules vides dans une plage.
NBVALCOUNTAdétermine le nombre de valeurs comprises dans la liste des arguments.
La fonction choisie pour cet exemple est donc NB.VIDE.
2 - fonctions vba Dans l'exemple suivant, le nombre de cellules vides de la plage "A1:D8" est enregistré dans la variable puis affiché dans la boîte de dialogue :
Sub test()
    var_test = WorksheetFunction.CountBlank(Range("A1:D8"))
    MsgBox var_test
End Sub
 
 

Cours VBA : créer une fonction personnalisée

 

 

Pour cet exemple, nous allons créer une fonction SI personnalisée utilisable sur une feuille de calcul comme n'importe quelle autre fonction.
Pour afficher une valeur (B2) si une cellule (C2) contient une valeur ("OUI"), nous pouvons utiliser la fonction SI avec la formule =SI(C2="OUI";B2;0) :

fonction si - creer fonction personnalisee L'objectif ici est de créer une fonction capable de faire cela =SI(C2 a un fond vert;B2;0) que nous écrirons comme ceci : =SI_VERT(C2;B2) :
fonction si couleur - creer fonction personnalisee

Développer la fonction personnalisée

Commencez par créer votre fonction :
Function SI_VERT(paye As Range, montant)
   
End Function
Les arguments :
  • paye As Range : la cellule à tester
  • montant : la valeur à entrer si VRAI
Dans le cas présent, si le test est FAUX, la valeur sera 0 à chaque fois, il est donc inutile d'avoir un argument pour cela.
Pour vérifier si la couleur est correcte, vous pouvez utiliser une cellule contenant la bonne couleur comme point de comparaison :
Function SI_VERT(paye As Range, montant)

    couleur = Sheets("Feuil1").Range("K1").Interior.color

End Function
Mais pour éviter de dépendre d'une cellule, nous allons utiliser ici le n° de la couleur qui nous intéresse :
Function SI_VERT(paye As Range, montant)

    couleur = 5296274 'Vert

End Function
Pour connaître le n° de couleur de fond d'une cellule, sélectionnez la cellule et exécutez cette macro :
Sub test_color()
    MsgBox ActiveCell.Interior.color
End Sub
no de couleur - creer fonction personnalisee Il ne reste plus qu'à tester la couleur avec If :
Function SI_VERT(paye As Range, montant)
   
    Application.Volatile
   
    couleur = 5296274 'Vert
 
    If paye.Interior.color = couleur Then 'Si VRAI
       SI_VERT = montant
    Else 'Si FAUX
       SI_VERT = 0
    End If
   
End Function
La fonction est maintenant prête à l'emploi.
Application.Volatile indique que la fonction est volatile (comme c'est le cas pour la fonction SI), ce qui signifie qu'elle doit être recalculée à chaque changement de valeur. Par exemple, si vous modifiez l'un des montants (ou n'importe quelle autre cellule), la fonction est recalculée est affichera le bon montant.
En revanche, la modification de la couleur de fond ne déclenche pas cette mise à jour. Pour recalculer les valeurs sans attendre, vous pouvez par exemple appuyer sur "Delete" en sélectionnant une cellule vide ou ajouter un bouton "Actualiser" pour tout recalculer d'un clic :
Sub actualiser()
    Application.Calculate
End Sub
fonction si vert - creer fonction personnalisee

Compléments

Une autre manière d'écrire cette même fonction :
Function SI_VERT(paye As Range, montant)
    Application.Volatile
    SI_VERT = 0 'Si FAUX
    If paye.Interior.color = 5296274 Then SI_VERT = montant 'Si VRAI
End Function
Vous pouvez télécharger le fichier qui a servi d'exemple en cliquant ici.


 

 

Cours VBA : utilisations des tableaux (exercice)

Pour mettre en pratique l'utilisation des tableaux, vous allez réaliser par étapes la macro qui a servi d'exemple pour démontrer la rapidité des tableaux ...
Voici le point de départ de l'exercice (la base de données a été réduite à 1000 lignes) :
Le fichier : tableaux_exercice.xls

bd - tableaux vba exercice Objectif de l'exercice : la procédure devra parcourir la base de données en boucle et comptabiliser pour chaque année et chaque n° de client le nombre de "OUI" ou "NON" (selon le choix de l'utilisateur) et entrer ce décompte dans la cellule correspondante.
res - tableaux vba exercice Complétez la macro suivante pour enregistrer la base de données de la feuille "BD" dans un tableau :
Sub mettre_a_jour()
    Dim derniere_ligne As Integer
   
    'Dernière ligne de la base de données
    '...
       
    'Enregistrement de la base de données dans un tableau dynamique
    Dim tab_bd()
    '...
       
End Sub
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Une solution :
Sub mettre_a_jour()
    Dim derniere_ligne As Integer
   
    'Dernière ligne de la base de données
    derniere_ligne = Sheets("BD").Range("A1").End(xlDown).Row

    'Enregistrement de la base de données dans un tableau dynamique
    Dim tab_bd()
    ReDim tab_bd(derniere_ligne - 2, 2)
   
    For ligne = 2 To derniere_ligne
        tab_bd(ligne - 2, 0) = Sheets("BD").Range("A" & ligne)
        tab_bd(ligne - 2, 1) = Sheets("BD").Range("B" & ligne)
        tab_bd(ligne - 2, 2) = Sheets("BD").Range("C" & ligne)
    Next
End Sub
Il ne s'agit là que d'une répétition de ce qui a été vu à la page précédente ...
Il va maintenant falloir transformer cette macro pour :
  • Déterminer le choix de l'utilisateur ("OUI" ou "NON")
  • Calculer le nombre de "OUI" ou "NON" de la base de données pour définir la taille du tableau (Redim)
  • Enregistrer dans le tableau uniquement les lignes de la base de données avec "OUI" ou "NON" (il n'est donc plus utile d'enregistrer la 3e colonne)
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Une solution :
Sub mettre_a_jour()
    Dim derniere_ligne As Integer, valeur_recherchee As String, ligne_insertion As Integer, valeur_oui_non As String, taille As Integer
   
    'Dernière ligne de la base de données
    derniere_ligne = Sheets("BD").Range("A1").End(xlDown).Row

    'Valeur recherchée (OUI ou NON)
    If Sheets("RES").OptionButton_oui.Value = True Then
        valeur_recherchee = "OUI"
    Else
        valeur_recherchee = "NON"
    End If
   
    'Nombre de OUI ou NON
    taille = WorksheetFunction.CountIf(Sheets("BD").Range("C2:C" & derniere_ligne), valeur_recherchee)
   
    'Enregistrement de la base de données dans un tableau
    Dim tab_bd()
    ReDim tab_bd(taille - 1, 1)

    ligne_insertion = 0
   
    For ligne = 2 To derniere_ligne
        valeur_oui_non = Sheets("BD").Range("C" & ligne)
        If valeur_oui_non = valeur_recherchee Then
            tab_bd(ligne_insertion, 0) = Sheets("BD").Range("A" & ligne)
            tab_bd(ligne_insertion, 1) = Sheets("BD").Range("B" & ligne)
            ligne_insertion = ligne_insertion + 1
        End If
    Next
End Sub
Le choix de l'utilisateur est tout d'abord déterminé grâce à :
'Valeur recherchée (OUI ou NON)
If Sheets("RES").OptionButton_oui.Value = True Then
    valeur_recherchee = "OUI"
Else
    valeur_recherchee = "NON"
End If
La fonction NB.SI (Countif) a été utilisée pour calculer le nombre de OUI ou de NON :
'Nombre de OUI ou NON
taille = WorksheetFunction.CountIf(Sheets("BD").Range("C2:C" & derniere_ligne), valeur_recherchee)
La taille du tableau a été adaptée au nombre de OUI ou de NON et réduite à 2 colonnes :
ReDim tab_bd(taille - 1, 1)
Les données sont ensuite enregistrées dans le tableau si la valeur de la 3e colonne correspond au choix de l'utilisateur :
'N° d'insertion dans le tableau
ligne_insertion = 0

'Parcours de la base de données
For ligne = 2 To derniere_ligne
    'Valeur de la colonne C (OUI ou NON)
    valeur_oui_non = Sheets("BD").Range("C" & ligne)
    'Si la valeur correspond au choix de l'utilisateur, la ligne est enregistrée
    If valeur_oui_non = valeur_recherchee Then
        'Enregistrement de la valeur de la colonne A
        tab_bd(ligne_insertion, 0) = Sheets("BD").Range("A" & ligne)
        'Enregistrement de la valeur de la colonne B
        tab_bd(ligne_insertion, 1) = Sheets("BD").Range("B" & ligne)
        'Une ligne a été enregistrée => le n° d'insertion dans le tableau augmente de 1
        ligne_insertion = ligne_insertion + 1
    End If
Next
Le tableau ne contient plus que les données qui nous intéressent.
Il nous reste encore à :
  • Parcourir chaque cellule du "tableau" de la feuille "RES" à l'aide de 2 boucles (même principe que l'exercice du damier)
  • Et y ajouter le nombre total d'entrées du tableau correspondant à l'année et au n° de client pour chaque cellule
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Une solution :
'Décomptes de "OUI"/"NON"
For annee = 2011 To 2026
    For no_client = 1 To 30
        compteur = 0
        For i = 0 To UBound(tab_bd)
            If Year(tab_bd(i, 0)) = annee And tab_bd(i, 1) = no_client Then
                compteur = compteur + 1
            End If
        Next
        Cells(annee - 2009, no_client + 1) = compteur
    Next
Next
La solution en détails :
'Boucle pour chaque ligne
For annee = 2011 To 2026
    'Boucle pour chaque colonne
    For no_client = 1 To 30
        'Compteur réinitialisé
        compteur = 0
        'Parcours du tableau
        For i = 0 To UBound(tab_bd)
            'Vérifie si la ligne du tableau correspond à l'année et au n° de client
            If Year(tab_bd(i, 0)) = annee And tab_bd(i, 1) = no_client Then
                'Si l'année et le n° de client correspondent, le compteur augmente de 1
                compteur = compteur + 1
            End If
        Next
        'Après avoir parcouru le tableau, le total est entré dans la cellule correspondante
        Cells(annee - 2009, no_client + 1) = compteur
    Next
Next
Et pour finir, la macro complète :
Sub mettre_a_jour()
    Dim derniere_ligne As Integer, valeur_recherchee As String, ligne_insertion As Integer, valeur_oui_non As String, taille As Integer, compteur As Integer
   
    'Suppression du contenu
    Range("B2:AE17").ClearContents
   
    'Dernière ligne de la base de données
    derniere_ligne = Sheets("BD").Range("A1").End(xlDown).Row

    'Valeur recherchée (OUI ou NON)
    If Sheets("RES").OptionButton_oui.Value = True Then
        valeur_recherchee = "OUI"
    Else
        valeur_recherchee = "NON"
    End If
   
    'Nombre de OUI ou NON
    taille = WorksheetFunction.CountIf(Sheets("BD").Range("C2:C" & derniere_ligne), valeur_recherchee)
   
    'Enregistrement de la base de données dans un tableau
    Dim tab_bd()
    ReDim tab_bd(taille - 1, 1)

    ligne_insertion = 0
   
    For ligne = 2 To derniere_ligne
        valeur_oui_non = Sheets("BD").Range("C" & ligne)
        If valeur_oui_non = valeur_recherchee Then
            tab_bd(ligne_insertion, 0) = Sheets("BD").Range("A" & ligne)
            tab_bd(ligne_insertion, 1) = Sheets("BD").Range("B" & ligne)
            ligne_insertion = ligne_insertion + 1
        End If
    Next
   
    'Décomptes de OUI ou NON
    For annee = 2011 To 2026
        For no_client = 1 To 30
            compteur = 0
            For i = 0 To UBound(tab_bd)
                If Year(tab_bd(i, 0)) = annee And tab_bd(i, 1) = no_client Then
                    compteur = compteur + 1
                End If
            Next
            Cells(annee - 2009, no_client + 1) = compteur
        Next
    Next
End Sub
Et le fichier : tableaux_exercice_complete.xls
exercice - tableaux vba exercice

Cours VBA : utilisations des tableaux

Les tableaux sont des "variables" qui permettent de stocker une multitude de valeurs. Nous avons effleuré le sujet à la leçon sur les variables, nous allons maintenant l'approfondir ...

Intérêt des tableaux

Imaginez que dans une procédure vous ayez besoin de stocker 500 valeurs. S'il fallait créer 500 variables pour stocker toutes ces valeurs, cela deviendrait très compliqué, tandis qu'avec un tableau, le stockage et l'utilisation de ces valeurs seront grandement simplifiés.
Le second intérêt des tableaux est leur "rapidité". Parcourir un tableau de données demande beaucoup moins de temps que parcourir un "tableau" (composé de cellules) sur une feuille Excel ...
Rien de tel qu'un exemple pour mieux comprendre ...
Sur la première feuille ("BD") : une base de données de 5000 lignes sur 3 colonnes :
bd - tableaux vba Sur la seconde feuille : un "tableau" récapitulatif où seront comptabilisés les "OUI" en fonction des années et des clients :
res - tableaux vba Dans le cas présent, la procédure va parcourir la base de données en boucle et comptabilisera pour chaque année et chaque n° de client le nombre de "OUI" avant de l'entrer dans la cellule correspondante.
Sans utiliser de tableau, il faudra 131.44 secondes à Excel pour exécuter la procédure :
sans - tableaux vba En enregistrant d'abord la base de données (de la feuille "BD") dans un tableau et en effectuant ensuite les mêmes calculs (en utilisant le tableau à la place de la base de données de la feuille "BD"), il ne faudra que 1.74 secondes pour exécuter la procédure :
avec - tableaux vba Et si l'on décide d'optimiser la procédure en n'enregistrant que les données avec les "OUI" dans le tableau (ce qui représente environ le 3/4 des données), 1.02 secondes suffisent :
avec opti - tableaux vba
Dans cet exemple, l'utilisation d'un tableau a permis d'exécuter la procédure environ 128x plus rapidement et cette différence peut encore augmenter sensiblement lorsque l'on travaille avec plusieurs bases de données en même temps (voir un second exemple).
Vous l'avez compris, l'utilisation de tableaux peut vraiment faire la différence.
Cet exemple sera détaillé en fin de leçon ...

Déclaration d'un tableau

Voici quelques exemples de déclarations (si les 2 premiers ne sont pas clairs pour vous, relisez ceci) :
'Exemple de déclaration d'un tableau à 1 dimension
Dim tab1(4)

'Exemple de déclaration d'un tableau à 2 dimensions
Dim tab2(6, 1)

'Exemple de déclaration d'un tableau dynamique
Dim tab()
Si vous ne pouvez pas entrer de valeurs fixes (parce que cela dépend de la taille de la base de données par exemple), laissez les parenthèses vides.
Vous n'avez pas besoin de déclarer un type (string, long, etc.), dans bien des cas cela ralentirait votre procédure ...

Enregistrer des données dans un tableau

Commençons par enregistrer ces quelques données dans un tableau :
enreg-1-dim - tableaux vba Nous voulons enregistrer ici 11 x 1 valeurs, il faudra donc créer un tableau à une dimension :
'Déclaration
Dim tab_exemple(10)
Rappelez-vous que la numérotation d'un tableau commence à 0 (c'est une norme en programmation, autant prendre de bonnes habitudes dès le début même s'il est possible de modifier cela en VBA).
Chaque élément du tableau reçoit ensuite sa valeur :
'Enregistrement des valeurs dans le tableau
tab_exemple(0) = Range("A2")
tab_exemple(1) = Range("A3")
tab_exemple(2) = Range("A4")
tab_exemple(3) = Range("A5")
tab_exemple(4) = Range("A6")
tab_exemple(5) = Range("A7")
tab_exemple(6) = Range("A8")
tab_exemple(7) = Range("A9")
tab_exemple(8) = Range("A10")
tab_exemple(9) = Range("A11")
tab_exemple(10) = Range("A12")
Vous pouvez utiliser, modifier chaque élément du tableau comme une variable.
En voici un exemple avec tab_exemple(8) :
Sub enreg_tab()
    'Déclaration
    Dim tab_exemple(10)
   
    'Enregistrement des valeurs dans le tableau
    tab_exemple(0) = Range("A2")
    tab_exemple(1) = Range("A3")
    tab_exemple(2) = Range("A4")
    tab_exemple(3) = Range("A5")
    tab_exemple(4) = Range("A6")
    tab_exemple(5) = Range("A7")
    tab_exemple(6) = Range("A8")
    tab_exemple(7) = Range("A9")
    tab_exemple(8) = Range("A10")
    tab_exemple(9) = Range("A11")
    tab_exemple(10) = Range("A12")
   
    'Test 1
    MsgBox tab_exemple(8) '=> renvoie : 04.02.2016
 
    'Modification de l'une des valeurs
    tab_exemple(8) = Year(tab_exemple(8))
   
    'Test 2
    MsgBox tab_exemple(8) '=> renvoie : 2016
End Sub
Pour enregistrer ce même tableau plus rapidement, une boucle For est toute indiquée :
'Déclaration
Dim tab_exemple(10)

'Enregistrement des valeurs dans le tableau
For i = 0 To 10
    tab_exemple(i) = Range("A" & i + 2)
Next
 
 

Le tableau à 2 dimensions

Pour enregistrer plusieurs colonnes de données, une dimension supplémentaire est nécessaire. En voici un exemple :
enreg-2-dim - tableaux vba suite Enregistrement des données dans un tableau à 2 dimensions :
'Déclaration
Dim tab_exemple(10, 2) 'Tableau de 11 x 3 "cases"

'Enregistrement des valeurs dans le tableau
For i = 0 To 10
    tab_exemple(i, 0) = Range("A" & i + 2)
    tab_exemple(i, 1) = Range("B" & i + 2)
    tab_exemple(i, 2) = Range("C" & i + 2)
Next
Et quelques exemples de valeurs :
MsgBox tab_exemple(0, 0) '=> renvoie : 11.03.2026
MsgBox tab_exemple(0, 1) '=> renvoie : 24
MsgBox tab_exemple(9, 2) '=> renvoie : NON
MsgBox tab_exemple(10, 2) '=> renvoie : OUI

Le tableau dynamique

Imaginons que cette même base de données soit régulièrement mise à jour et que l'on ne puisse donc pas entrer de valeurs fixes à la déclaration ...
enreg-dynamique - tableaux vba suite Pour connaître le n° de ligne de la dernière cellule d'un bloc de cellules non vides, autrement dit, la dernière ligne de notre base de données, utilisez cette formule :
derniere_ligne = Range("A1").End(xlDown).Row
Si vous entrez une variable lors de la déclaration, Excel ne l'acceptera pas.
Déclarez un tableau dynamique (parenthèses vides), puis définissez ses dimensions avec Redim :
Dim tab_exemple()
ReDim tab_exemple(derniere_ligne - 2, 2)
De cette manière vous enregistrerez automatiquement toutes les lignes de la base de données dans le tableau :
Sub enreg_tab()
    derniere_ligne = Range("A1").End(xlDown).Row 'Dernière ligne de la base de données

    Dim tab_exemple()
    ReDim tab_exemple(derniere_ligne - 2, 2)
   
    'Enregistrement des valeurs dans le tableau
    For i = 0 To derniere_ligne - 2
        tab_exemple(i, 0) = Range("A" & i + 2)
        tab_exemple(i, 1) = Range("B" & i + 2)
        tab_exemple(i, 2) = Range("C" & i + 2)
    Next
End Sub

Ubound

Dans l'exemple ci-dessus, le dernier n° de notre tableau était derniere_ligne - 2 :
For i = 0 To derniere_ligne - 2
Une autre solution pour connaître ce n° consiste à utiliser la fonction Ubound :
For i = 0 To UBound(tab_exemple)
Cette fonction renvoie le plus grand n° pour une dimension choisie (par défaut la première).
Quelques exemples pour mieux comprendre :
Sub enreg_tab()
    Dim tab_exemple(10, 2)
   
    MsgBox UBound(tab_exemple) '=> renvoie : 10
    MsgBox UBound(tab_exemple, 1) '=> renvoie : 10
    MsgBox UBound(tab_exemple, 2) '=> renvoie : 2
End Sub

Enregistrer une plage de cellules

Il est possible d'enregistrer une plage de cellules dans un tableau sans passer par une boucle.
'Déclaration
Dim tab_exemple(10, 2) 'Tableau de 11 x 3 "cases"

'Enregistrement des valeurs dans le tableau
For i = 0 To 10
    tab_exemple(i, 0) = Range("A" & i + 2)
    tab_exemple(i, 1) = Range("B" & i + 2)
    tab_exemple(i, 2) = Range("C" & i + 2)
Next
Le code ci-dessus peut être remplacé par :
'Déclaration
Dim tab_exemple()

'Enregistrement des valeurs dans le tableau
tab_exemple = Range("A2:C12").Value
Même si au premier abord cette seconde méthode semble séduisante, elle peut dans bien des cas vous faire perdre plus de temps que la première méthode ...
En enregistrant vos données dans le tableau de cette manière, le premier n° n'est pas 0 mais 1, cela peut être source de confusion ... De plus, si au cours du développement vous choisissez de n'enregistrer dans le tableau que les données répondant à certains critères (ou effectuer toute autre opération), vous aurez besoin de tout réécrire avec une boucle ...
Cette seconde méthode reste tout de même intéressante lorsque vous avez besoin d'enregistrer l'ensemble du contenu d'une grande base de données, car plus rapide qu'avec une boucle (gain d'environ 0.2 secondes pour 15'000 entrées).

Array

Vous aurez peut-être parfois besoin de créer un tableau contenant des données "fixes".
Une solution consiste à l'écrire ligne par ligne :
Dim fr(5)

fr(0) = "SI"
fr(1) = "RECHERCHEV"
fr(2) = "SOMME"
fr(3) = "NB"
fr(4) = "ESTNUM"
fr(5) = "STXT"
Heureusement, vous pouvez vous simplifier la tâche en utilisant Array :
fr = Array("SI", "RECHERCHEV", "SOMME", "NB", "ESTNUM", "STXT")
Voici un exemple d'utilisation de la fonction Replace (utile pour mieux comprendre l'exemple suivant) :
Sub remplacement()
    Dim chaine_a_traiter As String

    'Une chaîne pour cet exemple
    chaine_a_traiter = "Hello World !"
   
    'Remplacement de "World" par "toi" dans la chaîne de caractères
    chaine_a_traiter = Replace(chaine_a_traiter, "World", "toi")

    'La chaîne après remplacement
    MsgBox chaine_a_traiter '=> renvoie "Hello toi !"
End Sub
Maintenant si l'on veut remplacer une série de valeurs par une autre série, l'utilisation de tableaux (Array) est toute indiquée :
Sub traduction() 'Exemple simplifié de traduction FR-EN de formules
    Dim chaine_a_traiter As String

    'Une chaîne pour cet exemple
    chaine_a_traiter = "Formule à traduire : SOMME(SI(ESTNUM(A1:E1);A1:E1;0))"
   
    'Les 2 séries de valeurs
    fr = Array("SI", "RECHERCHEV", "SOMME", "NB", "ESTNUM", "STXT")
    en = Array("IF", "VLOOKUP", "SUM", "COUNT", "ISNUMBER", "MID")
   
    'Remplacement de "SI" par "IF", de "RECHERCHEV" par "VLOOKUP", etc.
    For i = 0 To UBound(fr)
        chaine_a_traiter = Replace(chaine_a_traiter, fr(i), en(i))
    Next

    'La chaîne après les remplacements
    MsgBox chaine_a_traiter '=> renvoie "Formule à traduire : SUM(IF(ISNUMBER(A1:E1);A1:E1;0))"
End Sub

Split

La fonction Split permet de convertir une chaîne de caractères en un tableau.
Pour convertir cette chaîne de caractères en tableau :
chaine = "SI/RECHERCHEV/SOMME/NB/ESTNUM/STXT"
Utilisez la fonction Split et définissez le séparateur :
fr = Split(chaine, "/")
Le tableau fr renverra les valeurs suivantes :
MsgBox fr(0) '=> renvoie : SI
MsgBox fr(1) '=> renvoie : RECHERCHEV
MsgBox fr(2) '=> renvoie : SOMME
MsgBox fr(3) '=> renvoie : NB
MsgBox fr(4) '=> renvoie : ESTNUM
MsgBox fr(5) '=> renvoie : STXT
Les 3 tableaux suivants renvoient également les mêmes valeurs :
fr = Array("SI", "RECHERCHEV", "SOMME", "NB", "ESTNUM", "STXT")
fr = Split("SI,RECHERCHEV,SOMME,NB,ESTNUM,STXT", ",")
fr = Split("SI RECHERCHEV SOMME NB ESTNUM STXT", " ")
L'exemple suivant renvoie la 3e valeur de la chaîne de caractères :
MsgBox Split("SI,RECHERCHEV,SOMME,NB,ESTNUM,STXT", ",")(2) '=> renvoie : SOMME
somme - tableaux vba suite La fonction à l'opposé de Split est Join.
Cette fonction permet d'assembler les valeurs d'un tableau en une chaîne de caractères.
MsgBox Join(Array(1, 2, 3, 4, 5), "") '=> renvoie : 12345
join - tableaux vba suite