formation vba excel

Post on 18-Dec-2014

833 Views

Category:

Software

84 Downloads

Preview:

Click to see full reader

DESCRIPTION

Apprenez à écrire vos macros pour le tableur Excel en Visual Basic. Cette formation couvre les rudiments de programmation ainsi que la découverte du modèle objet Excel sous-jacent.

TRANSCRIPT

## Visual Basic for Applications [Excel]

Olivier Le Goaërolivier.legoaer@univ-pau.fr

|Plan de la formation|

✔Avant-propos Quelques généralités pour partir du bon pied

✔Noyau Visual Basic Programmation avec le langage généraliste Visual Basic

✔Modèle objet d'Excel Exploiter le VB dans le contexte spécifique des objets

du tableur Microsoft Excel©

✔Motifs de code Portions de code récurrents et réutilisables à travers

différents projets VBA

## Avant-propos

| Relation entre VB et VBA |

Visual Basic for Applications (VBA)

Visual Basic for Applications (VBA)

Visual Basic (VB)Visual Basic (VB)

Langage de programmation orienté objet

VB couplé au modèle objet des applications

Domaine Bureautique

Domaine CAO

Domaine Statistique

| Le Visual Basic |

✔Directement dérivé du BASIC La partie « Visual » de Visual basic – l’éditeur de

fenêtres et les outils d’édition – rend la programmation plus accessible

✔Contient les bases de la programmation Objet Mais supporte toujours la programmation procédurale à

l'ancienne (GOTO, LABEL)

✔Nécessite un interpréteur pour être éxecuté Déjà présent dans toute version de Windows > 2000 Mais peut être compilé en code natif depuis VB 5

| Le Visual Basic for Applications |

✔Un programme VBA s'exécute nécessairement dans un programme hôte Ce programme hôte peut être Excel, Word, Autocad, …

✔Vise à automatiser des tâches d'habitude réalisées manuellement dans l'hôte

✔Le programme hôte expose donc des objets spécifiques pour être piloté par programmes Modèle objet Microsoft Excel : Classeur, Feuille, Plage... Modèle objet Microsoft Word : Document, Paragraphe... Modèle objet Autocad : Dessin, Calque...

## Noyau Visual Basic

| Aspects lexicaux |

✔Séparateurs d'instructions

✔Commentaires

✔Césures

'Ceci est un commentaire en VB, ignoré lors de l'exécution

CeciEstUneInstruction _ BeaucoupTropLongueAEcrire

...CeciEstUneInstructionCeciEstUneAutreInstruction : SuiviDuneAutreSurLaMemeLigneEtEnVoiciEncoreUneAutre...CoucouJeSuisLaDerniereInstruction

| Aspects lexicaux |

✔Blocs d'instructions

✔Les blocs s'imbriquent entre eux

✔Quelques blocs usuels (Voir suite des diapos) Sub...End sub, Function...End function, If...End if, While...Wend, Do Until...Loop, With...End With, For...Next, Select...End Select, Try...Catch...finally

UnTruc 'Marqueur du début d'un bloc...... 'On indente (tabulation) le code interne au bloc... 'pour une meilleure lisibilité...

End UnTruc 'Marqueur de fin du bloc

| Système de types |

✔La déclaration des variables peut être rendue obligatoire avec en préambule (conseillé)

✔Types de bases Nombres entiers : Byte, Integer, Long, LongLong, LongPtr Nombres décimaux : Single, Double, Decimal, Currency Valeurs booléennes : Boolean Chaînes de caractères : String Dates : Date Union de tous les types : Variant

Option Explicit

| Déclarer variables et constantes |

✔Une variable sert à mémoriser une valeur qui peut changer au cours de l'exécution

✔Une constante sert à mémoriser une valeur figée pour le reste de l'exécution

Dim nb_siege as Integer 'Déclaration en tant que nombre entier

nb_siege = 15 'Affectation de la valeur initialenb_siege = 89 'Nouvelle valeur (écrase la précédente)

Const PI as Double = 3.14159265359 'Affectation directe de la valeurConst TVA as Double = 19.60Const SIEGE_RESERVE as Byte = 2

nb_siege = nb_siege + SIEGE_RESERVETVA = 7.70 Impossible car constante !

| Quelques conventions |

✔Il est interdit d'utiliser des espaces ou des caractères spéciaux dans les noms

✔Pour la lisibilité, préférez le caractère _ ou bien l'écriture en « Camel Case »

✔Mais VB est en réalité insensible à la casse

Dim accèlération du vehicule as Double Faux !

Dim acceleration_du_vehicule as DoubleDim accelerationDuVehicule as Double

Dim prix as Double

Prix = 456.56pRiX = PRIX * prix – priX + Prix 'Se réfèrent tous à la même variable

| Modes Lecture/Ecriture |

✔La position d'une variable par rapport à l'opérateur d'affectation est primordial A gauche de celui-ci : la variable est en mode écriture;

elle se réfère au contenant A droite de celui-ci : la variable est en mode lecture;

elle se réfère au contenu

Const nb_siege_total as Integer = 450Dim nb_siege_occupe as Integer

nb_siege_occupe = 45nb_siege_occupe = nb_siege_totalnb_siege_occupe = nb_siege_occupe + 10nb_siege_occupe = nb_siege_total _

* nb_siege_occupe ^ 0

Dites, pour chaque variable ou constante,

si elle est utilisée en lecture ou

bien en écriture

| Types et opérateurs |

✔La déclaration vous contraint uniquement aux opérateurs qui se rapportent au type choisi Pour les nombres (entiers ou décimaux) : +, -, /, *, ^ Pour les booléens : not, or, and, xor Pour les chaînes de caractères : &

✔Les fonctions obéissent au même principe...

Dim X as DoubleDim Y as BooleanDim Z as String

X = (5 + 6) * -1Y = not (True and False)Z = "Le silence " & "des agneaux"

|Structure de contrôles |

✔Le flux d'exécution par défaut d'un programme est séquentiel (instruction après instruction)

✔Mais il peut être contrôlé grâce à des structures spéciales qui forment des blocs Condition : If expression Then … Else … End If Boucle : While expression … Wend Itération : For valDebut To valFin … Next

✔La logique booléenne est au coeur de ces structures Savoir si oui ou non, le bloc doit être exécuté

| Type tableau |

✔Un type supplémentaire est disponible, construit à partir des autres types : le tableau

✔Apparition d'une structure de contrôle dédiée

Dim t_prix(1 to 10) as Double 'indice numérique allant de 1 à 10

t_prix(1) = 78.863t_prix(2) = 45.456 + t_prix(1)

Dim i as ByteDim total as Double

Total = 0

For i=1 to 10 step 1Total = total + t_prix(i)

Next i

Dim p as DoubleDim total as Double

Total = 0

For each p in t_prixTotal = total + p

Next value

Version classique avec For Version avec For Each

| Sous programmes |

✔Un programme est scindé en sous-parties : les sous-programmes Appliquer l'adage « diviser pour mieux reigner » Ceci fait naître une hiérarchie de programmes ayant

alternativement les rôles appelant/appelé Le programme dit principal n'a donc pas d'appelant

✔Deux types de sous-programmes existent Les fonctions : ces sous-programmes renvoient un

résultat au programme qui les a appelé Les procédures : ces sous-programmes ne renvoient

aucun résultat au programme qui les a appelé

| Hierarchie d'appels |

Programme(principal)

Sous-Programme#1

Sous-Programme#2

Sous-Programme#1.1

Sous-Programme#2.1

Sous-Programme#2.2

Sous-Programme#2.3

appelant appelant

appelant

appelant

appelant appelant

appelé appelé

appelé appelé appelé appelé

appelé

| Fonctions versus procédures |

Procedure

Fonction#1

Procedure#2

Fonction#1.1

Procedure#2.1

Procedure#2.2

Fonction#2.3

appelant appelant

appelant

appelant

appelant appelant

appelé appelé

appelé appelé appelé appelé

Resultat Retour

Resultat Retour

Resultat Retour

appelé

|Définition de sous programmes |

✔Définition d'une fonction

✔Définition d'une procédure

Function pumpItUp() as Boolean

...

...pumpItUp = uneValeurBooleenne 'Mécanisme de retour (en tout dernier)

End Function

Sub pumpItUp()

...

...

...

End Sub

| Portée des variables |

✔Les variables déclarées au sein des sous-programmes sont dites « locales » Elles n'ont pas d'existence en dehors de ceux-ci

✔Comment alors les sous-programmes peuvent s'échanger des données entre eux ? Via des valeurs de retour ou via des paramètres...

Function f1() as BooleanDim exemple as Integer 'Portée locale à f1()...

End Function

Sub p1()exemple = exemple * 2 Impossible depuis p1() !

End Sub

| Sous-programmes paramétrés |

✔Un sous-programme peut nécessiter 0 ou plusieurs valeurs pour fonctionner On défini alors des paramètres qui possèdent chacun

un nom et un type

Function f1() as Integer '0 paramètre...

End Function

Sub p1(isReady as Boolean) '1 paramètre...

End Sub

Sub p2(msg1 as String, msg2 as String) '2 paramètres...

End Sub

|Exemples... |

✔Version à 1 paramètre

✔Version à 2 paramètres

Pour chaque versionrepérez les variables ou constantes locales, et les paramètres

Function calculerPrix(prixHT as Double) as DoubleConst TVA as Double = 19.60Dim prixTTC as Double

prixTTC = prixHT + prixHT * TVA/100CalculerPrix = prixTTC

End Function

Function calculerPrix(prixHT as Double, TVA as Double) as DoubleDim prixTTC as Double

prixTTC = prixHT + prixHT * TVA/100CalculerPrix = prixTTC

End Function

| Paramètres facultatifs |

✔On peut considérer certains paramètres comme pouvant être omis (c-a-d facultatifs)

✔Il est alors nécessaire de leur choisir une valeur par défaut en cas d'ommission

Sub pumpItUp(a as Integer, Optional b as String, c as Byte)...... 'attention, b peut ne pas avoir de valeur...

End Sub

Sub pumpItUp(a as Integer, Optional b as String = "Olivier", c as Byte).........

End Sub

|Exemple... |

✔Version à 2 paramètres, dont 1 est optionnel Si l'on omet d'indiquer une valeur de TVA, le calcul se

fera par défaut avec une TVA à 19.6%

Function calculerPrix(prixHT as Double, Optional TVA as Double = 19.60) as DoubleDim prixTTC as Double

prixTTC = prixHT + prixHT * TVA/100CalculerPrix = prixTTC

End Function

| Appel de sous-programmes |

✔La finalité de tout sous-programme est d'être appelé par un programme appelant Cas de l'appel d'une fonction

Cas de l'appel d'une procedure (pas de parenthèses !)

Dim test as Boolean...test = f1()...'test contient uneValeurBooleenne

Function f1() as Boolean......f1 = uneValeurBooleenne

End Function

...p1...

Sub p1()......

End Sub

| Passage de paramètres |

✔Le programme appelant doit passer des valeurs aux paramètres des sous-programmes Il s'agit d'une liaison d'arguments avec les paramètres

correspondants, dans le respect du typage

x et False sont des arguments val et ok sont des paramètres

Dim x as Bytex = 23

p1 x, False

Sub p1(val as Byte, ok as Boolean)......

End Sub

programme appelant programme appelé

| Passage par nom ou par position|

✔Passage de paramètres par position Les arguments sont liés implicitement dans l'ordre des

paramètres (mais ambiguïtés quand facultatifs)

✔Passage de paramètres par nommage La liaison des arguments avec les paramètres sont

explicités avec :=

x = 23

p1 x, False

Sub p1(val as Byte, ok as Boolean)...

End Sub 1 2

1 2

x = 23

p1 ok:=False, val:=x'l'ordre n'importe plus ici

Sub p1(val as Byte, ok as Boolean)...

End Sub

| Passage par valeur ou référence |

✔Passage de paramètres par valeur Le sous-programme ne peut pas agir sur la valeur de

l'argument du programme appelant (par défaut)

✔Passage de paramètres par référence Le sous-programme peut agir sur la valeur de

l'argument du programme appelant

x = 23p1 x, False'x vaut toujours 23

Sub p1(ByVal val as Byte, ok as Boolean)val = val * 4

End Sub

x = 23p1 x, False'x vaut désormais 92

Sub p1(ByRef val as Byte, ok as Boolean)val = val * 4

End Sub

| Gestion des erreurs |

✔Il est possible gérer le cas où l'exécution du code plante

Public Sub calculDeLaMortQuiTue(ByVal diviseur As Integer) Dim resultat as Double

On Error GoTo casDesespere ' Insérer ici le code susceptible de planter

resultat = 143 / diviseur ' Et si diviseur vaut 0 ? hein ??? Exit Sub

casDesespere: ' Insérer le code à réaliser en cas d'erreur

Msgbox "T'as l'air malin maintenant ! Pffff....." Resume NextEnd Sub

| Programmation objet |

✔Une classe d'objet est une structure regroupant deux catégories de membres Les propriétés : valeurs attachées aux objets (données) Les méthodes : fonctions ou procédures attachés aux

objets (traitements)

'3 propriétés (les données)nom as Stringprenom as Stringage as Byte

'1 méthode (le traitement)Sub sayHello()

MsgBox "Je suis" & Me.nom & " " & Me.prenomEnd Sub

Classe « Client »

Auto-référence avec le mot clé « Me »

| Visibilité des membres |

✔La visibilité de chaque membre peut être : Publique (par défaut) : propriété ou méthode de l'objet

utilisable depuis n'importe où dans le programme Privé : propriété ou méthode de l'objet utilisable

uniquement au sein de la même structure

'3 propriétés + visibilitéPublic nom as StringPublic prenom as StringPrivate age as Byte

'1 méthode + visibilitépublic Sub sayHello()

MsgBox "Je suis" & Me.nom & " " & Me.prenomEnd Sub

Classe « Client »

| Accesseurs et mutateurs |

✔Le VB gère explicitement les méthodes dites « accesseurs » et « mutateurs » Accesseur : fonction destinée exclusivement à récupérer

la valeur d'une propriété (mode lecture) Mutateur : procédure destinée exclusivement à affecter

une valeur à une propriété (mode écriture)

Private nom as String

Public Property Get Nom() As String Nom = UCase(Me.nom)End Property

Public Property Let Nom(n as String)Me.nom = n

End Property

Classe « Client »

| Création et manipulation d'objet |

✔Déclaration d'une variable typée par une classe

✔Affectation d'un nouvel objet à la variable

✔L'accès aux membres de l'objet utilise une notation pointée

Dim c1 as Client 'Type complexe (Classe)

Set c1 = new Client 'Affectation d'un objet à une variable

c1.nom = "Le Goaër" 'écriture d'une propriété de l'objetc1.prenom = "Olivier" 'écriture d'une propriété de l'objetc1.age = 32 impossible car visibilité privée !c1.sayHello 'appel de la procédure de l'objet...

| Références sur objet |

✔Une variable typé par une classe possède une référence à un objet en mémoire

✔Cas de la référence nulle

Dim c1 as Client 'déclaration mais manque l'affectation

If c1 is Nothing Then...

End If

Dim c1,c2,c3,c4 as Client

Set c1 = new Clientc2 = c1 'recopie d'une référencec3 = c2c4 = c1

objetClient

c1

c2

c3

c4

| Accès en cascade |

✔L'accès aux membres d'un même objet peut avoir une syntaxe simplifiée

✔Très utile pour initialiser rapidement les propriétés d'un objet notamment

Dim c1 as Client

Set c1 = new Client

c1.nom = "Le Goaër"c1.prenom = "Olivier"c1.sayHello

Dim c1 as Client

Set c1 = new Client

With c1.nom = "Le Goaër".prenom = "Olivier".sayHello

End With

## Modèle objet d'Excel

| Projet VBA |

✔A chaque fichier Excel peut être associé un projet VBA Contiendra le code des macros Savoir où positionner son code est primordial !

Code lié aux classeurs et feuilles chargées(Mot clé « Me » autorisé)

Code pour créer des formulaires(Interface graphique utilisateur)

Code indépendant

Classes d'objet personnalisées

| Hierarchie d'appels des macros|

Macro#1

Macro#2

Macro#1.1

Macro#2.1

Macro#2.2

Macro#2.3

appelant appelant

appelant

appelant

appelant appelant

appelé appelé

appelé appelé appelé appelé

appelé

| Lancer une macro|

✔Depuis un projet VBA ✔Depuis le tableur

Fonctionne uniquement pour les procédures,de surcroît sans paramètres...

| Explorateur d'objets de classes |

Moteur de recherche(classes et

membres de classes)

Modules de classes, Modules, Enumérationsfournis par VBA Excel

Membres d'une classe donnée

Propriété

Méthode

Signature du membreLien de navigation

(vers d'autres classes)

+ Documentation Officielle (en français)

| Bibliothèque de fonctions Excel|

✔La bibliothèque des fonctions Excel est en fait un module spécial contenant des macros VBA Module WorksheetFunction On utilise le nom anglais standardisé des fonctions

Nom françisé Nom anglaisSOMME() SUM()MOYENNE AVERAGE()NB.SI() COUNTIF()BDMOYENNE() DAVERAGE()RECHERCHEV() VLOOKUPNBVAL() COUNTA()... ...

| Enrichir la bibliothèque Excel|

✔Cette bibliothèque peut tout à fait être enrichie par vos propres fonctions Doivent être positionnées dans un Module propre Doivent avoir une visibilité publique Doivent retourner un type de base et avoir pour

paramètres des types de bases ou la classe Range Peut parfois être volatile (Application.volatile)

✔Macros appelées depuis la zone de formules du tableau Excel E5 = maFonctionCustom(B6:V45; K3) * 2

| Nouvelle fonction : exemple|

|Modèle objet Excel |

✔En VBA Excel, vous disposez d'un ensemble d'objets déjà instanciés à partir de classes Ces objets sont le strict reflet de ce que vous avez sous

les yeux dans le tableur Excel

✔Synchronisation objet/tableur Chaque action réalisée au niveau des objets a un

impact au niveau du tableur, et vice versa

✔La (très) mauvaise idée de VBA Excel Les objets et leur propriétés portent souvent le même

nom que leur classes :-/

| Métaphore de l'iceberg |

Public name as StringPublic path as String...

Public Sub saveAs(Optional fileName as String, ...)...

End Sub...

Classe « WorkBook »

Dim thisWorkbook as WorkBook

Set thisWorkbook = new WorkBookthisWorkbook.name = le_nom_du_classeur_chargéthisWorkbook.path = le_chemin_du_classeur_chargé

ThisWorkbook.saveAs filename:="Bilan Comptable"

Code exécuté au chargement du fichier Excel(pour refléter ce que vous avez sous les yeux)

Votre code

| Classes usuelles |Classe Objet(s)Application Représente Excel (objet unique/singleton)WorkBook Représente un classeur ouvertWorkSheet Représente une feuille de calcul ouverteChart Représente un graphiqueControl Représente un contrôle de formulaire (Bouton, Case à

cocher, ...)Font Représente une fonte (Italique, gras, police, couleur)

Range Représente un ensemble de cellules (une seule, colonnes entières, lignes entières...)

WorkBooks Représente un ensemble de classeursWorkSheets Représente un ensemble de feuilles de calculSheets Représente un ensemble de feuilles (calcul et autres)Charts Représente un ensemble de graphiquesControls Représente un ensemble de contrôles de formulaires

Classes dérivées de la classe

« Collection »

| Diagramme de classe |

Name as StringVersion as StringWorkbooks as WorkBooks

Application

Sub CalculateFull()

count as Longitem() as WorkBook

<<Collection>>WorkBooks

Function add() as WorkBook

Name as StringPath as StringWorkSheets as WorkSheets

WorkBook

Sub close()Sub saveAs()

count as Longitem() as WorkSheet

<<Collection>>WorkSheets

Function add() as WorkSheet

Name as StringIndex as LongCells(,) as RangeRange() as Range

WorkSheet

Sub Activate()

Cells(,) as Rangerows as RangeRow as Longcount as Longitem() as RangeInterior as Interior

<<Collection>>Range

Function Select()

| Diagramme de classes |

Name as StringVersion as StringWorkbooks as WorkBooks

Application

Sub CalculateFull()

count as Longitem() as WorkBook

<<Collection>>WorkBooks

Function add() as WorkBook

Name as StringPath as StringWorkSheets as WorkSheets

WorkBook

Sub close()Sub saveAs()

count as Longitem() as WorkSheet

<<Collection>>WorkSheets

Function add() as WorkSheet

Name as StringIndex as LongCells(,) as RangeRange() as Range

WorkSheet

Sub Activate()

Cells(,) as Rangerows as RangeRow as Longcount as Longitem() as RangeInterior as Interior

<<Collection>>Range

Sub Select()

...

| Diagramme d'objets |

name="Excel"Version=10.7

:Applicationcount=1

:WorkBooks

name="Shadok"path="c:/Bureau/"

:Workbook

count=4

:Worksheets

name="Ga"visible=xlSheetVisible

:WorkSheet

name="Bu"visible=xlSheetVisible

:WorkSheet

name="Zo"visible=xlSheetVisible

:WorkSheet

name="Meu"visible=xlSheetHidden

:WorkSheet

|Naviguer entre les objets |

'Ecriture dans une propriété d'un objetApplication.workbooks.item(1).worksheets.item(3).Range("B3").value = "yep !"

ApplicationApplication

WorkbooksWorkbooks(Collection)

WorkSheetsWorkSheets(Collection)

WorkBookWorkBook

WorkSheetWorkSheetWorkSheetWorkSheetRangeRange(Collection)

VariantVariant

'Appel d'une méthode d'un objet (ici une procédure)ThisWorkbook.saveAs filename:="Bilan Comptable"

WorkBookWorkBook

| Décomposons la navigation |

Dim monExcel as ApplicationDim collectionClasseurs as WorkbooksDim unClasseur as WorkBookDim collectionFeuilles as WorksheetsDim uneFeuille as WorkSheetDim unePlage as Range

Set monExcel = ApplicationSet collectionClasseurs = monExcel.workbooksSet unClasseur = collectionClasseurs.item(1)Set collectionFeuilles = unClasseur.worksheetsSet uneFeuille = collectionFeuilles.item(3)Set unePlage = uneFeuille.Range("B3")unePlage.value = "yep !"

'Ecriture dans une propriété d'un objetApplication.workbooks.item(1).worksheets.item(3).Range("B3").value = "yep !"

| Positionnement du code |

✔Si votre code est lié aux objets du projet VBA

✔Sinon (Module, Module de Classe, ...)

'Me est l'auto-référénce à l'objet qui contient le code'On suppose ci-dessous que c'est Feuil2Me.name = "Hello"

'Navigation complète depuis l'objet racine Application 'Accès à un classeur/feuille via son index ou via son petit nomApplication.workbooks.item(1).worksheets.item(3).name = "Hello"Application.workbooks.item("Shadock").worksheets.item("Zo").name = "Hello"

'Accès direct à l'objet feuilleFeuil2.name = "Hello"

'Via l'objet ActiveSheetApplication.workbooks.item(1).worksheets.item(3).activateActiveSheet.name = "Hello"

| Cas des énumérations |

✔Les énumérations sont des modules de classes un peu particuliers Elles servent à typer des variables (comme les classes) Mais leurs membres sont uniquement des constantes

✔Conventions de nommage Celles liées au noyau VB sont préfixées par « Vb »

– VbYesNo, VbCalendar, VbArchive... Celles liées au tableur Excel sont préfixées par « Xl »

– XlChartType, XlDataTable, XlSheetVisible...

| Evènements |

✔Il existe en réalité une troisième catégorie de membres de classes : les évènements Ce sont des méthodes déclenchées quand quelque-

chose se produit sur l'objet de la classe

✔Exemples d'évènement VBA Excel Liés au tableur Excel

– L'utilisateur a ouvert son classeur, a fermé son classeur, a activé une feuille, a selectionné une plage...

Liés aux contrôles de formulaire– L'utilisateur a cliqué sur un bouton, a décoché une case,

a saisi un champs...

| Programmation par evènements|

✔Explorateur de classes ✔Code projet VBA

| Outil de débogage |

✔Espionner ✔Exécuter la macro en mode pas-à-pas (F8)

| Enregisteur de macros |

✔Outil qui génère automatiquement un code équivalent à ce que vous faites dans le tableur Pratique quand vous ne savez pas quel code VBA écrire

✔Mais n'est certainement pas la solution à tout... Le code généré contient de nombreux parasites La tentation d'avoir recours à l'enregisteur n'aide pas à

comprendre donc à progresser L'immense majorité des cas pratiques repose sur des

problèmes d'ordre algorithmique où l'enregisteur n'est d'aucun secours

| Enregistreur : cas d'école |Range("A19").SelectSelection.Font.ColorIndex = 3Selection.Borders(xlDiagonalDown).LineStyle = xlNoneSelection.Borders(xlDiagonalUp).LineStyle = xlNoneWith Selection.Borders(xlEdgeLeft) .LineStyle = xlContinuous .Weight = xlMedium .ColorIndex = xlAutomaticEnd WithWith Selection.Borders(xlEdgeTop) .LineStyle = xlContinuous .Weight = xlMedium .ColorIndex = xlAutomaticEnd WithWith Selection.Borders(xlEdgeBottom) .LineStyle = xlContinuous .Weight = xlMedium .ColorIndex = xlAutomaticEnd WithWith Selection.Borders(xlEdgeRight) .LineStyle = xlContinuous .Weight = xlMedium .ColorIndex = xlAutomaticEnd WithWith Selection .HorizontalAlignment = xlCenter .VerticalAlignment = xlBottom .WrapText = False .Orientation = 0 .AddIndent = False .IndentLevel = 0 .ShrinkToFit = False .ReadingOrder = xlContext .MergeCells = FalseEnd With

With Range("A19") .Font.ColorIndex = 3 .HorizontalAlignment = xlCenter .Borders.Weight = xlMediumEnd With

Les performances et l'intelligibilité

du code sont bien meilleures ainsi non ?

Code généré par l'enregistreur de macro

Code équivalent écrit par un humain

## Motifs de code

| Entrées/sorties standards |Dim annee as ByteDim info as StringDim choix as Byte

'Méthode de saisie basiqueannee = Interaction.inputBox(prompt:="Marignan ?", title:="Quizz")

'Méthode de saisie avec contrôle du type (1 -> nombre)annee = Application.inputBox(prompt:="Marignan ?", title:="Quizz", type:=1)

info = "Marignan " & annee & "!"

'Méthode d'affichage utilisée comme procédureInteraction.msgBox prompt:=info, buttons:=vbInformation

'Méthode d'affichage utilisée comme functionchoix = Interaction.msgBox(prompt:=info, buttons:=vbYesNo)

'Méthode d'affichage du débogueur (apparaîtra dans la fenêtre d'exécution)Debug.Print "L'utilisateur a entré " & info

| Manipulation de feuille de calcul |

Dim nouveau as Worksheet

'Creation d'une nouvelle feuille dans la collectionSet nouveau = thisWorkbook.worksheets.add(after:=Me)

'Accès aux propriétés en cascadeWith nouveau

.name = "Bilan"

.visible = xlSheetVisible

.cells(1,2).value = "Ventes prévisionnelles"

.enableCalculation = FalseEnd with

'Ramène la feuille en toute première positionNouveau.move before:=thisWorkbook.worksheets.item(1)

'Suppression de la feuilleNouveau.delete

| Manipuler les plages |

'Selection d'une plage réduite à une seule celluleFeuil1.Range("C7").Select 'equivaut à Feuil1.cells(7, 3)

'Selection d'une plage de cellules contigüesFeuil1.Range("A2:R45").Select

'Selection d'une plage de cellules non-contigüesFeuil1.Range("A2:D25;F4:B9").Select

'Selection de la plage encadrée par les colonnes D à P inclusesFeuil1.Range(Feuil1.columns(4), Feuil1.columns(16)).Select

'Selection de la plage encadrée par les lignes 8 à 153 inclusesFeuil1.Range(Feuil1.rows(8), Feuil1.rows(153)).Select

'Selection de la plage de diagonale C7 à H33Feuil1.Range(Feuil1.Range("C7"), Feuil1.Range("H33")).Select

'Selection de la plage par décalageFeuil1.Range("G22:R45").Offset(8,-2).Select 'Soit E30:P53

| Fond & forme des plages |

'Valeur interne de la cellule stockée par le tableur (Cf. codage de données)Feuil1.cells(2,2).value2 = 29930'Valeur formatée de la cellule (souvent valeur formatée = valeur interne)Feuil1.cells(2,2).value = #10/12/1981#

'Séance de maquillage pour notre celluleWith Feuil1.cells(2,2)

.Font.ColorIndex = 3 'couleur tirée de la palette Excel (parmi 56) .Font.Bold = True

.Interior.Color = RGB(59, 89, 152) 'couleur libre (> 16 millions)

.Borders.Weight = 4End With

'Remise à zero de la forme et du fondWith Feuil1.cells(2,2)

.clear

.clearContent

.Interior.Pattern = xlPatternNoneEnd With

| Compter les lignes utilisées|

Dim CombienDeLignes as Integer

'usedRange est la plage englobante déterminée par le tableurCombienDeLignes = Feuil1.usedRange.rows.count

'Rechercher « à taton » la dernière cellule vide d'une colonne donnée Dim iLigne as IntegeriLigne = 1While not Feuil1.cells(iLigne, 2) = ""

iLigne = iLigne + 1WendCombienDeLignes = iLigne - 1

'Récupérer le n° de la dernière ligne d'une colonne donnéeCombienDeLignes = Feuil1.columns(2).end(xlDown).row

'Réutiliser la fonction tableur NBVAL() sur une colonne donnéeCombienDeLignes = Application.CountA(Feuil1.columns("A"))

'Passer par la méthode SpecialCellsCombienDeLignes = Feuil1.SpecialCells(xlCellTypeLastCell).Row

| Copier/coller |

'Copier/collé rudimentaire d'une cellule à une autreFeuil2.Range("A2").value = Feuil1.Range("B78").value

'Copier/collé de plages de cellulesFeuil1.Range("A2:R45").copy'...Données mises en zone mémoire tampon (le « presse-papier »)...Feuil2.paste 'En A2:R45 par défautFeuil2.paste destination:=Feuil2.Range("B4:S47") 'Destination explicite

'Version plus immédiateFeuil1.Range("A2:R45").copy destination:=Feuil2.Range("B4:S47")

'Sur le même principe, copier/coller de colonnes ou de lignesFeuil1.Columns("E").copy destination:=Feuil2.Columns(4)

| Ouverture d'un répertoire |

Dim vaFiles As Variant Dim i As Long

vaFiles = Application.GetOpenFilename(FileFilter:= _ "Excel Files (*.xls), *.xls", Title:="Ouvrir Fichier(s)", MultiSelect:=True) If Not IsArray(vaFiles) Then Exit Sub 'Sortie si aucun fichiers

With Application 'Désactive le rafraichissement de l'affichage (meilleures performances)

.ScreenUpdating = False For i = 1 To UBound(vaFiles) .workbooks.Open vaFiles(i) 'Ouverture de chaque classeur Next i .ScreenUpdating = True 'Réactive le rafraichissement de l'affichageEnd With

| Parcours d'une plage |

Dim iLigne, iColonne as IntegerDim plage as RangeDim cellule as Range

Set plage = Feuil1.Range("A2:R45")

'Version classique (risque de poser problème si non contigües)For iLigne=1 to plage.rows.count

For iColonne=1 to plage.columns.countplage.cells(iLigne, iColonne).value = "Yeaaaaaah"

NextNext

'Version par itération sur une collectionFor each cellule in plage

cellule.value = "Yeaaaaaah"Next

| Génération d'un graphique |

Dim courbe as Chart

'ajoute une feuille de graphique au classeur (≠ feuille de calcul)Set courbe = ThisWorkbook.Charts.Add

With courbe'graphique type ligne (Voir enumération XlChartType)

.ChartType = xlLineMarkers'sélection de la source de données. Ici une plage

.SetSourceData Source:=Feuil1.Range("B10:C56") .HasTitle = True .ChartTitle.Text = "Ceci est un graphique" .SeriesCollection(1).Name = "Nom de la série"End With

'Déplace la feuille de graphique en dernière position'Sheets représente la collection des feuilles (de graphique ET de calcul)ActiveChart.Move after:=ThisWorkbook.Sheets.item(ThisWorkbook.Sheets.Count)

| Open Data & Services Web |

Public Function VilleSelonCodePostal(CP as String) as String

'URL d'un service web gratuit de conversion CP->VilleConst URL As String = "http://www.cp-ville.com/cpcom.php?cpcommune=" & CP

Dim httpRequest As Object Dim jsonResult As String Dim lFirstChar, lLastChar As Long

Set httpRequest = CreateObject("MSXML2.XMLHTTP.6.0") httpRequest.Open "GET", URL, False httpRequest.Send jsonResult = httpRequest.responsetext

'Parsing JSON très rudimentaire, mais qui marche :-P lFirstChar = InStr(jsonResult, "{""ville"":") + 10 lLastChar = InStr(lFirstChar, jsonResult, ",") - 1 VilleSelonCodePostal = Mid$(jsonResult, lFirstChar, lLastChar - lFirstChar)

End Function

| Barre de menu personnalisée |

Dim my_bar as CommandBar

Dim my_ctrl As CommandBarControl

Set my_bar = Application.CommandBars.Add(Name:="Sample Menu Bar", _Position:=msoBarTop, MenuBar:=True, Temporary:=False)

'my_bar.Name = "olivier4"'my_bar.Enabled = True'my_bar.Visible = True

Set my_ctrl = my_bar.Controls.Add(Type:=msoControlButton)my_ctrl.Caption = "coucou"

| Participez ! |

Vous pensez à un code suffisamment général et

utile pour être réutilisable par tous ?

Envoyez-le à olivier.legoaer@univ-pau.fr

top related