Bureautique · Excel

Macros
& VBA

Enregistrer, écrire et déboguer des macros Excel — variables, boucles, objets Range/Sheet/Workbook, événements, UserForms et automatisations concrètes.

Qu'est-ce qu'une macro ?

ℹ️

Une macro est une séquence d'instructions enregistrées ou écrites en VBA (Visual Basic for Applications) qui automatisent des tâches répétitives dans Excel. Une macro peut en quelques secondes faire ce qui prendrait des heures manuellement.

Cas d'usage typiqueExemple
Mise en forme automatiqueColorier en rouge toutes les cellules négatives
Traitement de donnéesNettoyer 5 000 lignes importées d'un ERP
Génération de rapportsCréer un PDF récapitulatif mensuel automatiquement
Import/ExportCharger des CSV, les transformer, les consolider
Envoi automatiqueEnvoyer un rapport Outlook à une liste de contacts
Validation complexeVérifier la cohérence des données à la saisie
Interface utilisateurFormulaire de saisie avec liste déroulante et contrôles
⚠️

Format de fichier : un classeur contenant des macros doit être enregistré au format .xlsm (Excel avec macros activées), pas .xlsx (qui supprime les macros à la sauvegarde).

Activer l'onglet Développeur
' L'onglet Développeur est masqué par défaut.

Fichier → Options → Personnaliser le ruban
→ Cocher "Développeur" → OK

L'onglet Développeur contient :
  Visual Basic → Ouvrir VBE (éditeur)
  Macros       → Gérer/exécuter les macros
  Enregistrer  → Démarrer l'enregistrement
  Insérer      → Boutons, cases à cocher…
  Propriétés   → Paramètres du contrôle actif

' Raccourcis clavier :
Alt+F8      → Liste des macros
Alt+F11     → Ouvrir VBE (éditeur VBA)
Alt+F4      → Fermer VBE

Enregistrer une macro

1
Développeur → Enregistrer une macro
Donner un nom (sans espaces), un raccourci optionnel, choisir où la stocker.
2
Effectuer les actions à enregistrer
Cliquer, taper, formater… Excel traduit chaque action en code VBA.
3
Développeur → Arrêter l'enregistrement
Ou cliquer sur le carré ■ dans la barre d'état.
4
Alt+F8 → Exécuter
Ou utiliser le raccourci clavier défini à l'étape 1.
5
Alt+F11 → Modifier le code
Retoucher le VBA généré pour le rendre plus robuste.
EmplacementPortée
Ce classeurDisponible uniquement dans ce fichier .xlsm
Nouveau classeurCrée un nouveau fichier pour la macro
Classeur de macros perso.PERSONAL.XLSB — disponible dans TOUS les classeurs Excel
Code généré — exemple mise en forme
' Macro enregistrée — mise en forme d'un en-tête
Sub MiseEnForme_EnTete()
'
' Raccourci clavier : Ctrl+Shift+E
'
    Range("A1:E1").Select
    With Selection.Interior
        .Pattern = xlSolid
        .PatternColorIndex = xlAutomatic
        .ThemeColor = xlThemeColorAccent1
        .TintAndShade = -0.249946941783223
        .PatternTintAndShade = 0
    End With
    With Selection.Font
        .Bold = True
        .Color = -16777216   ' ← code couleur RGB
    End With
End Sub

' ⚠ Problèmes du code enregistré :
' - Utilise .Select partout (lent et fragile)
' - Valeurs magiques (ThemeColorAccent1, -0.249...)
' - Pas de commentaires clairs
' → Voir section "Objets Excel" pour la version propre

L'éditeur VBE

Microsoft Visual Basic for Applications — MonClasseur.xlsm
Projet
📁 VBAProject
Microsoft Excel
📄 ThisWorkbook
📄 Feuil1
📄 Feuil2
Modules
📝 Module1
📝 Module2
Formulaires
🪟 UserForm1
' Module1 — Macros générales
Option Explicit ' ← forcer la déclaration des variables

Sub MaPremiéreMacro()
Dim msg As String
msg = "Bonjour depuis VBA !"
MsgBox msg
End Sub
Zone VBERôle
Explorateur de projetArborescence du classeur : feuilles, modules, UserForms
Fenêtre de codeÉcrire et modifier le code VBA
Fenêtre Exécution (Ctrl+G)Tester des expressions : taper ?ActiveCell.Value
Fenêtre EspionSurveiller la valeur d'une variable pendant l'exécution
Fenêtre Variables localesVoir toutes les variables en mode débogage
Raccourci VBEAction
F5Exécuter la macro
F8Pas à pas (ligne par ligne)
F9Poser/enlever un point d'arrêt
Ctrl+GFenêtre Exécution
Ctrl+EspaceAutocomplétion IntelliSense
Shift+F2Aller à la définition
Ctrl+ZAnnuler (dans l'éditeur)

Variables & types

Déclaration et types de données
Option Explicit  ' Toujours — interdit les variables non déclarées

Sub DémonstrationVariables()

    ' Types numériques
    Dim i         As Integer    ' -32 768 à 32 767
    Dim l         As Long       ' ±2 milliards — préférer Long à Integer
    Dim d         As Double     ' décimal double précision
    Dim c         As Currency   ' montants — 4 décimales fixes

    ' Texte
    Dim nom       As String
    Dim code      As String * 5 ' longueur fixe : 5 caractères

    ' Autres
    Dim actif     As Boolean    ' True / False
    Dim dt        As Date
    Dim obj       As Object     ' objet générique (liaison tardive)
    Dim val       As Variant    ' n'importe quel type — flexible mais lent

    ' Affectation
    nom = "Alice"
    l   = 100000
    d   = 3.14
    dt  = Date        ' date du jour
    actif = True

    ' Constantes
    Const TVA     As Double = 0.21
    Const APPNAME As String = "MonApp"

End Sub
Tableaux & portée des variables
' Tableaux — taille fixe
Dim mois(1 To 12) As String
mois(1) = "Janvier"
mois(2) = "Février"

' Tableaux dynamiques
Dim données() As Double
ReDim données(1 To 100)
ReDim Preserve données(1 To 200) ' garder les valeurs

' Portée des variables

' Local (dans une Sub) :
Sub MaSub()
    Dim x As Integer  ' visible dans MaSub uniquement
End Sub

' Module (en haut du module, hors Sub) :
Dim compteur As Long   ' visible dans tout le module

' Global (tous les modules) :
Public nomApp As String

' Conversion de types :
CStr(42)        ' → "42"
CLng("100")     ' → 100 (Long)
CDbl("3,14")   ' → 3.14
CDate("01/03") ' → date

' Fonctions utiles :
IsNumeric("42")   ' True
IsEmpty(val)     ' True si Variant non initialisé
IsNull(val)      ' True si Null
Len("Bonjour")   ' 7
UCase("abc")    ' "ABC"

Conditions — If / Select Case

If … ElseIf … Else
Sub Conditions()
    Dim note As Integer
    note = 14

    ' If simple
    If note >= 10 Then
        MsgBox "Réussi"
    End If

    ' If/Else
    If note >= 10 Then
        MsgBox "Réussi"
    Else
        MsgBox "Échoué"
    End If

    ' If/ElseIf/Else
    Dim mention As String
    If     note >= 16 Then mention = "Distinction"
    ElseIf note >= 14 Then mention = "Très bien"
    ElseIf note >= 12 Then mention = "Bien"
    ElseIf note >= 10 Then mention = "Suffisant"
    Else                    mention = "Insuffisant"
    End If

    ' Opérateurs logiques
    If note >= 10 And note <= 20 Then ' ET
    If note < 0 Or note > 20 Then      ' OU
    If Not (note >= 10) Then           ' NON

End Sub
Select Case
Sub SelectCase()
    Dim pays As String
    pays = "BE"

    ' Select Case sur texte
    Select Case pays
        Case "BE"
            MsgBox "Belgique"
        Case "FR"
            MsgBox "France"
        Case "NL", "LU"
            MsgBox "Pays-Bas ou Luxembourg"
        Case Else
            MsgBox "Autre pays"
    End Select

    ' Select Case sur plages de nombres
    Dim note As Integer
    note = 14
    Select Case note
        Case Is >= 16
            MsgBox "Distinction"
        Case 14 To 15
            MsgBox "Très bien"
        Case 10 To 13
            MsgBox "Bien ou Suffisant"
        Case Else
            MsgBox "Insuffisant"
    End Select

End Sub

Boucles — For / Do / While

For Next & For Each
' For Next — compteur numérique
Dim i As Long
For i = 1 To 10
    Cells(i, 1).Value = i * 2
Next i

' Décrémenter (Step négatif)
For i = 10 To 1 Step -1
    ' utile pour supprimer des lignes
    If Cells(i, 1).Value = "" Then
        Rows(i).Delete
    End If
Next i

' For Each — itérer sur une collection
Dim cellule As Range
For Each cellule In Range("A1:A20")
    If cellule.Value < 0 Then
        cellule.Font.Color = vbRed
    End If
Next cellule

' Sortie anticipée
For i = 1 To 1000
    If Cells(i, 1).Value = "" Then Exit For
    ' traitement...
Next i
Do Loop & While
' Do While — vérifier avant
Dim i As Long
i = 1
Do While Cells(i, 1).Value <> ""
    ' traiter la ligne i
    i = i + 1
Loop

' Do Until — jusqu'à ce que
i = 1
Do Until Cells(i, 1).Value = ""
    i = i + 1
Loop

' Do Loop While — vérifier après (exécute au moins 1 fois)
Do
    i = i + 1
Loop While i <= 100

' Astuce : trouver la dernière ligne non vide
Dim dernLigne As Long
dernLigne = Cells(Rows.Count, "A").End(xlUp).Row
' → Équivalent de Ctrl+↑ depuis A1048576

' Boucle sur toutes les lignes de données
For i = 2 To dernLigne  ' 2 = skip l'en-tête
    ' traiter ligne i...
Next i

Sub & Function

Sub — procédures
' Sub = procédure — fait quelque chose, ne retourne rien

' Sub sans paramètre
Sub NettoyerFeuille()
    ActiveSheet.Cells.ClearContents
End Sub

' Sub avec paramètres
Sub ColorierPlage(ByVal plage As Range, _
                    ByVal couleur As Long)
    plage.Interior.Color = couleur
End Sub

' Appeler une Sub
NettoyerFeuille
ColorierPlage Range("A1:D10"), vbYellow
Call ColorierPlage(Range("A1"), vbRed)

' ByVal vs ByRef
Sub TestPassage(ByVal x As Integer)
    x = 999   ' modifie une copie — original inchangé
End Sub

Sub TestPassage2(ByRef x As Integer)
    x = 999   ' modifie l'original !
End Sub

' Paramètre optionnel
Sub Saluer(Optional nom As String = "monde")
    MsgBox "Bonjour " & nom
End Sub
Function — fonctions personnalisées
' Function = retourne une valeur
' Utilisable dans les cellules Excel comme =MaFonction()

' Fonction simple
Function TTC(prixHT As Double, tva As Double) _
         As Double
    TTC = prixHT * (1 + tva)
End Function
' Dans une cellule : =TTC(B2;0,21)

' Retourner une chaîne
Function Mention(note As Integer) As String
    Select Case note
        Case Is >= 16 : Mention = "Distinction"
        Case Is >= 14 : Mention = "Très bien"
        Case Is >= 10 : Mention = "Suffisant"
        Case Else     : Mention = "Insuffisant"
    End Select
End Function

' Fonction qui retourne une erreur si invalide
Function DivSafe(a As Double, b As Double) _
         As Variant
    If b = 0 Then
        DivSafe = CVErr(xlErrDiv0)  ' retourne #DIV/0!
    Else
        DivSafe = a / b
    End If
End Function

Gestion des erreurs

On Error — stratégies
' On Error Resume Next — ignorer l'erreur (dangereux !)
On Error Resume Next
    Dim ws As Worksheet
    Set ws = Sheets("PeutÊtreInexistante")
On Error GoTo 0  ' ← toujours réactiver après
If ws Is Nothing Then
    MsgBox "Feuille introuvable"
End If

' On Error GoTo Label — gestion structurée
Sub ImporterDonnées()
    On Error GoTo GestionErreur

    ' Code principal
    Dim val As Double
    val = CDbl(ActiveCell.Value)   ' peut échouer
    MsgBox "Valeur : " & val
    Exit Sub  ' ← IMPORTANT : ne pas tomber dans GestionErreur

GestionErreur:
    MsgBox "Erreur " & Err.Number & " : " & Err.Description
    ' Err.Clear  → effacer l'erreur
    ' Resume Next → continuer à la ligne suivante
    ' Resume      → réessayer la ligne en erreur

End Sub
Débogage
' Debug.Print — afficher dans la fenêtre Exécution
Dim i As Long
For i = 1 To 5
    Debug.Print "Ligne " & i & " : " & Cells(i,1).Value
Next i
' → Ctrl+G pour voir la sortie

' Point d'arrêt (F9) :
' Cliquer dans la marge gauche du code
' Une ligne rouge apparaît
' F5 s'arrête sur cette ligne
' F8 pour avancer pas à pas
' Survoler une variable pour voir sa valeur

' Stop — point d'arrêt dans le code
For i = 1 To 100
    If i = 50 Then Stop  ' pause quand i=50
    Cells(i, 1) = i
Next i

' Tester dans la fenêtre Exécution :
' ? ActiveCell.Value       → affiche la valeur
' ? ActiveSheet.Name      → nom de la feuille active
' ActiveCell.Value = 99   → modifier directement

Cellules & plages (Range)

Référencer et manipuler des cellules
' Référencer une cellule
Range("A1")               ' par adresse
Range("A1:C10")          ' plage
Range("A1:C10").Cells(2,3) ' cellule relative dans la plage
Cells(1, 1)              ' Cells(ligne, colonne) — dynamique !
Cells(1, "A")           ' colonne par lettre
ActiveCell                 ' cellule actuellement sélectionnée

' Lire et écrire
Dim val As Variant
val = Range("B2").Value             ' lire
Range("B2").Value = 42             ' écrire
Range("C1").Formula = "=A1+B1"    ' formule EN
Range("C1").FormulaLocal = "=A1+B1" ' formule FR
Range("C1").FormulaR1C1 = "=R1C1+R1C2"

' Navigation dynamique
Range("A1").Offset(1, 0)   ' 1 ligne en dessous
Range("A1").Offset(0, 2)   ' 2 colonnes à droite
Range("A1").Resize(10, 3) ' étendre à 10 lignes × 3 colonnes
Range("A1").End(xlDown)    ' aller jusqu'en bas (Ctrl+↓)
Range("A1").CurrentRegion  ' plage contiguë autour de A1
Mise en forme sans .Select
' ✅ Version propre — sans Select
With Range("A1:E1")
    .Interior.Color = RGB(68, 114, 196)  ' bleu
    .Font.Color     = vbWhite
    .Font.Bold      = True
    .Font.Size      = 11
    .Borders.LineStyle = xlContinuous
    .HorizontalAlignment = xlCenter
End With

' Taille de colonne
Columns("A").ColumnWidth = 20
Columns("A:D").AutoFit    ' ajustement automatique
Rows(1).RowHeight = 30

' Copier / Coller
Range("A1:D10").Copy Range("F1")   ' copier-coller direct
Range("A1:D10").Copy
Range("F1").PasteSpecial xlPasteValues  ' valeurs seulement
Application.CutCopyMode = False          ' effacer les fourmis

' Effacer
Range("A1:D10").ClearContents  ' données seulement
Range("A1:D10").ClearFormats   ' formats seulement
Range("A1:D10").Clear          ' tout

Feuilles & classeurs

Worksheets — manipuler les feuilles
' Référencer une feuille
Sheets("Ventes")              ' par nom
Sheets(1)                     ' par index (1 = première)
ActiveSheet                    ' feuille active
ThisWorkbook.Sheets("Ventes") ' dans ce classeur

' Accéder à une cellule d'une autre feuille
Sheets("Ventes").Range("A1").Value = 100

' Créer / supprimer
Sheets.Add After:=Sheets(Sheets.Count) ' à la fin
ActiveSheet.Name = "Rapport Mars"
Sheets("Brouillon").Delete          ' sans confirmation :
Application.DisplayAlerts = False
Sheets("Brouillon").Delete
Application.DisplayAlerts = True

' Copier / déplacer
Sheets("Modèle").Copy After:=Sheets(Sheets.Count)
Sheets("Feuil1").Move Before:=Sheets(1)

' Masquer / afficher
Sheets("Data").Visible = xlSheetHidden
Sheets("Data").Visible = xlSheetVeryHidden ' non visible dans UI
Sheets("Data").Visible = xlSheetVisible

' Boucler sur toutes les feuilles
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
    ws.Range("A1").Value = ws.Name
Next ws
Workbooks — classeurs
' Ouvrir un classeur
Dim wb As Workbook
Set wb = Workbooks.Open("C:\data\rapport.xlsx")
Set wb = Workbooks.Open(Application.GetOpenFilename())

' Créer un nouveau classeur
Set wb = Workbooks.Add

' Sauvegarder
ThisWorkbook.Save
ThisWorkbook.SaveAs "C:\exports\rapport.xlsx", xlOpenXMLWorkbook
wb.SaveAs Filename:="export.xlsx", _
          FileFormat:=xlOpenXMLWorkbook

' Sauvegarder en PDF
ThisWorkbook.Sheets("Rapport").ExportAsFixedFormat _
    Type:=xlTypePDF, _
    Filename:="C:\rapport.pdf", _
    Quality:=xlQualityStandard

' Fermer
wb.Close SaveChanges:=True
wb.Close SaveChanges:=False

' Boucler sur tous les classeurs ouverts
Dim w As Workbook
For Each w In Application.Workbooks
    Debug.Print w.Name
Next w

Tableaux structurés & TCD

ListObjects — tableaux structurés
' Référencer un tableau structuré
Dim tbl As ListObject
Set tbl = Sheets("Données").ListObjects("TabVentes")

' Propriétés utiles
tbl.Name                    ' nom du tableau
tbl.DataBodyRange           ' données sans en-tête
tbl.HeaderRowRange          ' ligne d'en-tête
tbl.ListRows.Count          ' nombre de lignes
tbl.ListColumns.Count       ' nombre de colonnes
tbl.ListColumns("CA").DataBodyRange ' colonne "CA"

' Ajouter une ligne
Dim newRow As ListRow
Set newRow = tbl.ListRows.Add
newRow.Range(1) = Date
newRow.Range(2) = "Dupont"
newRow.Range(3) = 1500

' Supprimer des lignes avec critère
Dim i As Long
For i = tbl.ListRows.Count To 1 Step -1
    If tbl.ListRows(i).Range(3).Value < 100 Then
        tbl.ListRows(i).Delete
    End If
Next i

' Trier le tableau
tbl.Sort.SortFields.Clear
tbl.Sort.SortFields.Add Key:=tbl.ListColumns("CA").DataBodyRange, _
    SortOn:=xlSortOnValues, Order:=xlDescending
tbl.Sort.Apply
Actualiser les TCD
' Actualiser un TCD spécifique
Dim tcd As PivotTable
Set tcd = Sheets("Dashboard").PivotTables("TCD_Ventes")
tcd.RefreshTable

' Actualiser tous les TCD du classeur
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
    Dim pt As PivotTable
    For Each pt In ws.PivotTables
        pt.RefreshTable
    Next pt
Next ws

' Filtrer un TCD par code VBA
Dim champ As PivotField
Set champ = tcd.PivotFields("Région")
champ.ClearAllFilters
champ.CurrentPage = "Nord"

' Modifier la plage source d'un TCD
tcd.ChangePivotCache _
    ThisWorkbook.PivotCaches.Create( _
        SourceType:=xlDatabase, _
        SourceData:=Sheets("Données").ListObjects("TabVentes"))

Événements

Événements de feuille (dans Feuil1)
' Double-clic dans le module de la feuille (pas un Module)

' Déclenché quand une cellule change
Private Sub Worksheet_Change(ByVal Target As Range)
    ' Target = la cellule (ou plage) qui a changé
    If Not Intersect(Target, Range("B:B")) Is Nothing Then
        ' Quelque chose a changé en colonne B
        If Target.Value < 0 Then
            Target.Font.Color = vbRed
        Else
            Target.Font.ColorIndex = xlAutomatic
        End If
    End If
End Sub

' Déclenché avant modification
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
    ' Surligher la ligne et colonne de la sélection
    Cells.Interior.ColorIndex = xlNone
    With Target
        .EntireRow.Interior.Color = RGB(255,255,200)
        .EntireColumn.Interior.Color = RGB(200,255,255)
    End With
End Sub

' Double-clic
Private Sub Worksheet_BeforeDoubleClick( _
    ByVal Target As Range, Cancel As Boolean)
    Cancel = True   ' annule le comportement par défaut
    MsgBox "Double-clic sur " & Target.Address
End Sub
Événements du classeur (dans ThisWorkbook)
' À l'ouverture du classeur
Private Sub Workbook_Open()
    ' Actualiser tous les TCD
    ThisWorkbook.RefreshAll
    ' Aller sur le dashboard
    Sheets("Dashboard").Activate
    MsgBox "Bienvenue — données actualisées"
End Sub

' Avant la sauvegarde
Private Sub Workbook_BeforeSave( _
    ByVal SaveAsUI As Boolean, Cancel As Boolean)
    ' Horodater la dernière sauvegarde
    Sheets("Info").Range("A1") = "Sauvegardé : " & Now
End Sub

' Avant la fermeture
Private Sub Workbook_BeforeClose(Cancel As Boolean)
    If MsgBox("Sauvegarder avant de fermer ?", _
       vbYesNo) = vbYes Then
        ThisWorkbook.Save
    End If
End Sub

' Changement de feuille active
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
    If Sh.Name = "Dashboard" Then
        Sh.PivotTables(1).RefreshTable
    End If
End Sub

MsgBox & InputBox

MsgBox — afficher des messages
' Affichage simple
MsgBox "Traitement terminé !"

' Avec titre et icône
MsgBox "Opération réussie", vbInformation, "Succès"
MsgBox "Fichier introuvable", vbCritical, "Erreur"
MsgBox "Voulez-vous continuer ?", vbQuestion, "Attention"

' Boutons disponibles :
vbOKOnly         ' OK seul (défaut)
vbOKCancel       ' OK + Annuler
vbYesNo          ' Oui + Non
vbYesNoCancel    ' Oui + Non + Annuler
vbRetryCancel    ' Réessayer + Annuler

' Récupérer le choix
Dim réponse As Integer
réponse = MsgBox("Supprimer les données ?", _
           vbYesNo + vbCritical, "Confirmation")

If réponse = vbYes Then
    Range("A2:Z1000").ClearContents
ElseIf réponse = vbNo Then
    MsgBox "Annulé."
End If
InputBox — saisie utilisateur
' InputBox VBA — retourne une chaîne ou "" si Annuler
Dim saisie As String
saisie = InputBox("Entrez votre nom :", _
                    "Identification", _
                    "Alice")           ' valeur par défaut
If saisie = "" Then
    MsgBox "Annulé" : Exit Sub
End If

' Application.InputBox — plus puissant (type strict)
Dim nb As Double
nb = Application.InputBox( _
    "Entrez un nombre :", Type:=1) ' Type=1 = nombre

' Types Application.InputBox :
' 0 = formule    1 = nombre    2 = texte
' 4 = booléen    8 = plage     16= erreur

' Sélectionner une plage
Dim plage As Range
On Error Resume Next
Set plage = Application.InputBox( _
    "Sélectionnez la plage de données :", _
    Type:=8)
On Error GoTo 0
If plage Is Nothing Then Exit Sub
MsgBox plage.Address

UserForm — formulaires personnalisés

Créer et utiliser un UserForm
' VBE → Insertion → UserForm
' Ajouter des contrôles depuis la Boîte à outils :
' TextBox, Label, ComboBox, ListBox,
' CommandButton, CheckBox, OptionButton…

' Dans le code du UserForm (double-clic sur bouton) :

' Initialiser la liste déroulante à l'ouverture
Private Sub UserForm_Initialize()
    ' Remplir un ComboBox
    With ComboBox1
        .AddItem "Nord"
        .AddItem "Sud"
        .AddItem "Est"
        .AddItem "Ouest"
        .Value = "Nord"   ' valeur par défaut
    End With
    ' Focus sur le premier champ
    TextBox1.SetFocus
End Sub

' Clic sur le bouton "Valider"
Private Sub btnValider_Click()
    ' Lire les valeurs
    Dim nom    As String
    Dim région As String
    Dim montant As Double
    nom     = TextBox1.Value
    région  = ComboBox1.Value
    montant = CDbl(TextBox2.Value)

    ' Écrire dans le tableau
    Dim tbl As ListObject
    Set tbl = Sheets("Données").ListObjects("TabVentes")
    Dim r As ListRow
    Set r = tbl.ListRows.Add
    r.Range(1) = Date
    r.Range(2) = nom
    r.Range(3) = région
    r.Range(4) = montant

    MsgBox "Ligne ajoutée !", vbInformation
    Unload Me   ' fermer le formulaire
End Sub
Ouvrir un UserForm & validation
' Depuis une autre Sub, ouvrir le formulaire
Sub OuvrirFormulaire()
    UserForm1.Show       ' modal (bloque Excel)
    UserForm1.Show vbModeless ' non modal
End Sub

' Validation des champs
Private Sub btnValider_Click()
    ' Vérifier que les champs sont remplis
    If Trim(TextBox1.Value) = "" Then
        MsgBox "Le nom est obligatoire", vbExclamation
        TextBox1.SetFocus
        Exit Sub
    End If
    If Not IsNumeric(TextBox2.Value) Then
        MsgBox "Montant invalide", vbCritical
        TextBox2.SetFocus
        Exit Sub
    End If
    ' … enregistrer
End Sub

' Bouton Annuler
Private Sub btnAnnuler_Click()
    Unload Me
End Sub

' Touche Entrée = valider
' Propriété du formulaire → EnterKeyBehavior = True sur le bouton
' Ou: KeyDown event sur les TextBox

Générer un rapport automatiquement

Macro complète — rapport mensuel PDF
Sub GénérerRapportMensuel()
    Dim wsDonnées As Worksheet
    Dim wsRapport As Worksheet
    Dim mois      As String
    Dim cheminPDF As String

    Application.ScreenUpdating = False  ' désactiver le rafraîchissement écran → accélère
    Application.Calculation = xlCalculationManual  ' désactiver le calcul auto pendant la macro

    ' 1. Référencer les feuilles
    Set wsDonnées = ThisWorkbook.Sheets("Données")
    Set wsRapport = ThisWorkbook.Sheets("Rapport")

    ' 2. Déterminer le mois courant
    mois = Format(Date, "yyyy-mm")

    ' 3. Actualiser les TCD
    Dim tcd As PivotTable
    For Each tcd In wsDonnées.PivotTables
        tcd.RefreshTable
    Next tcd

    ' 4. Mettre à jour le titre du rapport
    wsRapport.Range("B2").Value = "Rapport des ventes — " & Format(Date, "mmmm yyyy")

    ' 5. Calculer les KPI
    Dim tbl As ListObject
    Set tbl = wsDonnées.ListObjects("TabVentes")
    wsRapport.Range("D5").Value = Application.WorksheetFunction.Sum( _
        tbl.ListColumns("CA").DataBodyRange)
    wsRapport.Range("D6").Value = Application.WorksheetFunction.Count( _
        tbl.ListColumns("CA").DataBodyRange)
    wsRapport.Range("D7").Value = wsRapport.Range("D5") / wsRapport.Range("D6")

    ' 6. Exporter en PDF
    cheminPDF = Environ("USERPROFILE") & "\Desktop\Rapport_" & mois & ".pdf"
    wsRapport.ExportAsFixedFormat Type:=xlTypePDF, Filename:=cheminPDF

    ' 7. Réactiver
    Application.Calculation = xlCalculationAutomatic
    Application.ScreenUpdating = True

    MsgBox "Rapport généré : " & cheminPDF, vbInformation
End Sub

Importer & nettoyer des données

Macro — importer un CSV et nettoyer
Sub ImporterEtNettoyer()
    Dim chemin     As String
    Dim wbSource   As Workbook
    Dim wsDest     As Worksheet
    Dim dernLigne  As Long
    Dim i          As Long

    ' 1. Choisir le fichier
    chemin = Application.GetOpenFilename("CSV,*.csv,Excel,*.xlsx", , "Sélectionner le fichier")
    If chemin = "Faux" Then Exit Sub  ' Annuler

    Application.ScreenUpdating = False

    ' 2. Ouvrir le fichier source
    Set wbSource = Workbooks.Open(chemin)
    Set wsDest = ThisWorkbook.Sheets("Import")

    ' 3. Copier les données
    wbSource.Sheets(1).UsedRange.Copy
    wsDest.Range("A1").PasteSpecial xlPasteValues
    Application.CutCopyMode = False
    wbSource.Close False

    ' 4. Nettoyer les données importées
    dernLigne = wsDest.Cells(Rows.Count, "A").End(xlUp).Row

    ' Supprimer les lignes vides (en remontant !)
    For i = dernLigne To 2 Step -1
        If Application.WorksheetFunction.CountA(wsDest.Rows(i)) = 0 Then
            wsDest.Rows(i).Delete
        End If
    Next i

    ' Supprimer espaces et harmoniser la casse
    Dim cellule As Range
    For Each cellule In wsDest.Range("B2:B" & dernLigne)
        If cellule.Value <> "" Then
            cellule.Value = Application.WorksheetFunction.Trim( _
                StrConv(cellule.Value, vbProperCase))
        End If
    Next cellule

    ' 5. Convertir en tableau structuré
    dernLigne = wsDest.Cells(Rows.Count, "A").End(xlUp).Row
    wsDest.ListObjects.Add(xlSrcRange, wsDest.Range("A1:E" & dernLigne), , xlYes).Name = "TabImport"

    Application.ScreenUpdating = True
    MsgBox dernLigne - 1 & " lignes importées et nettoyées.", vbInformation
End Sub

Envoyer un e-mail via Outlook

Macro — envoyer le rapport par e-mail
' Référence requise : Outils → Références → Microsoft Outlook XX.X Object Library

Sub EnvoyerRapportEmail()
    Dim olApp  As Object    ' Outlook.Application (liaison tardive)
    Dim olMail As Object    ' Outlook.MailItem
    Dim pdfPath As String

    ' 1. Générer le PDF
    pdfPath = Environ("TEMP") & "\rapport_temp.pdf"
    ThisWorkbook.Sheets("Rapport").ExportAsFixedFormat _
        Type:=xlTypePDF, Filename:=pdfPath

    ' 2. Créer l'objet Outlook (liaison tardive — fonctionne sans référence)
    Set olApp = CreateObject("Outlook.Application")
    Set olMail = olApp.CreateItem(0)   ' 0 = olMailItem

    ' 3. Configurer l'e-mail
    With olMail
        .To      = "direction@entreprise.com"
        .CC      = "comptabilite@entreprise.com"
        .Subject = "Rapport mensuel — " & Format(Date, "mmmm yyyy")
        .Body    = "Bonjour," & vbCrLf & vbCrLf & _
                   "Veuillez trouver en pièce jointe le rapport des ventes du mois." & vbCrLf & _
                   "Cordialement,"
        .Attachments.Add pdfPath
        ' .Send     → envoyer directement
        .Display   ' → ouvrir pour révision avant envoi
    End With

    ' 4. Libérer les objets
    Set olMail = Nothing
    Set olApp  = Nothing

End Sub

Cheat sheet VBA

Structure du code

Option ExplicitToujours — forcer les déclarations
Sub / End SubProcédure sans retour
Function … As TypeRetourne une valeur
With … End WithAgir sur un objet sans répéter
On Error GoToGestion d'erreurs structurée
Debug.PrintTrace dans la fenêtre Exécution

Objets clés

Range("A1")Cellule ou plage
Cells(l, c)Cellule dynamique
Sheets("Nom")Feuille par nom
ThisWorkbookLe classeur contenant la macro
.End(xlDown)Fin de plage (Ctrl+↓)
.Offset(l, c)Décalage relatif

Performance

ScreenUpdating = FalseDésactiver le rafraîchissement
Calculation = ManualDésactiver le calcul auto
Éviter .SelectAgir directement sur l'objet
For i → To dernLigneNe pas boucler sur tout
Step -1Supprimer des lignes en remontant

Raccourcis VBE

Alt+F11Ouvrir / fermer VBE
F5Exécuter la macro
F8Pas à pas
F9Point d'arrêt
Ctrl+GFenêtre Exécution
Ctrl+EspaceAutocomplétion