Polycopié
Transcription
Polycopié
Révision Excel – Boîte de dialogue : La société RidoConf Objectifs : Révisions Excel, Insertion d’objets dans une feuille, Boîtes de dialogues L'entreprise RidoConf est une SARL Spécialisée : - dans la vente de tissus d'ameublement et de linge de maison - dans la confection sur mesure de voilages et de doubles rideaux Le coût de confection des rideaux est fonction du type de tissu, du modèle de rideau souhaité, des dimensions de la fenêtre et de l'ampleur désirée (coefficient applicable à la largeur réelle permettant d'envisager plusieurs type de plis). Pour fixer leur choix, les clients souhaitent disposer des coûts correspondants à plusieurs hypothèses de réalisation. Il vous est demandé de réaliser un modèle Excel permettant de proposer et remettre immédiatement au client les éléments du coût correspondant aux différentes hypothèses envisagées lors de sa visite. Ces hypothèses limitées aux choix du tissu et du modèle de confection sont appelées propositions. A partir des caractéristiques de la fenêtre à équiper - hauteur et largeur -, il est possible d'envisager les différentes hypothèses de réalisation en fonction : - de l'ampleur désirée (coefficient entre 1 et 3) de l’ourlet (entre 0 à 20% de longueur en plus) du modèle de rideau souhaité de la référence du tissu Le modèle conditionne le coût horaire de la façon et la durée moyenne du travail par mètre carré confectionné. Chaque type de tissu d'ameublement comporte une référence, un nom, une largeur, trois prix dégressifs au mètre : prix1: achats <5mètres ; prix2 entre 5 et 10 mètres ; prix3 achats >= 10 mètres(Cf. tableau Tissu). Chaque modèle est caractérisé par un numéro, un nom et une estimation du temps de travail par mètre carré réalisé(Cf. tableau Modèle). La façon exprime pour un code donné le coût horaire de travail(Cf. Tableau Façon). Chaque proposition comporte : un numéro, la date, le coût du tissu, de la façon et le coût total. 1°) Réaliser un modèle sous Excel en utilisant les fonctions Recherche(H ou V) ou Index et Equiv. 2°) Modifier le modèle initial de façon à ce que tous les choix du client se fassent dans une boîte de dialogue. G. Mauffrey Introduction à la programmation VBA page 1/51 Annexe 1 – Données Tissus, Modèles, Façon 1 Tissu Référence 24 47 70 93 116 181 246 311 376 441 506 520 534 548 562 Nom Venise Suisse Miami Wallis Tahiti Agadir Madras Tabriz Corfou Hébrides Majorque Annaba Korogo Hawai Roma 2 Largeur 120 cm 140 cm 90 cm 90 cm 120 cm 240 cm 140 cm 140 cm 90 cm 240 cm 90 cm 120 cm 90 cm 90 cm 240 cm Prix1 15,00 € 17,00 € 12,00 € 10,00 € 18,00 € 21,00 € 20,00 € 26,00 € 15,00 € 26,00 € 9,00 € 12,00 € 15,00 € 10,00 € 25,00 € Prix2 12,50 € 15,00 € 12,00 € 8,00 € 15,00 € 18,00 € 15,00 € 25,00 € 14,00 € 20,00 € 8,00 € 10,00 € 12,00 € 10,00 € 22,00 € Heures façon/Modèle de rideau Nom Heure/M² Numéro 15 Provençal 1,25 H 104 Bonne femme 1,50 H 193 Brise Bise 1,00 H 282 Louis XV 2,00 H 371 Régence 1,30 H 460 Empire 2,20 H 549 Campagnard 1,80 H 638 Droit 0,80 H Prix3 10,00 € 12,00 € 10,00 € 8,00 € 12,00 € 15,00 € 14,00 € 22,00 € 12,00 € 15,00 € 7,00 € 8,00 € 12,00 € 10,00 € 21,00 € Code façon 57 35 79 13 35 101 79 57 Coût Façon Code façon Prix 13 12,00 € 35 12,50 € 57 14,00 € 79 14,50 € 101 17,50 € G. Mauffrey Introduction à la programmation VBA page 2/51 Annexe 2 – A propos du modèle de facturation La démarche à suivre pour la facturation est composée de deux étapes : 1. Calcul du prix du tissu : 1.1. Une fois le tissu choisi (donc la largeur définie), déterminer le nombre de largeurs de tissu (‘lés’) nécessaires pour couvrir la largeur de la fenêtre (ne pas oublier de tenir compte de l’ampleur). On pourra éventuellement tenir compte d’un ourlet fixe (p.e. 10cm) sur chaque lé, ou le prendre en tant que pourcentage en plus (de 0 à 20%). 1.2. En déduire le métrage de tissu nécessaire et éventuellement la chute (tissu inutilisé) 1.3. En déduire le prix global du tissu 2. Calcul de la façon : 2.1. Déterminer la surface utile, c’est à dire la surface de tissu à travailler (donc sans les chutes). 2.2. En fonction du modèle choisi, déterminer le temps nécessaire et le code façon. 2.3. En déduire le coût de la façon. 3. Le prix à facturer est la somme du prix du tissu et du coût de la façon. Fonctions Excel utilisées : Recherche ou Rechercheh ou Recherchev, Index, Indirect, Arrondi.sup. Rappel : dans un modèle sous tableur les données doivent être séparées des équations, aucune constante ne doit apparaître dans les équations. G. Mauffrey Introduction à la programmation VBA page 3/51 Annexe 3 – Création et utilisation d'une boîte de dialogue Nous allons indiquer ici comment créer et utiliser une boîte de dialogue identique à celle ci : La création se fait en Visual Basic, dans le menu "Affichage-Barres d'outil" sélectionner la barre Visual Basic, puis cliquer sur Visual Basic Editor, il apparaît alors une nouvelle fenêtre : Dans le menu insertion choisir UserForm, la fenêtre devient alors : G. Mauffrey Introduction à la programmation VBA page 4/51 Il apparaît trois fenêtres : une fenêtre contenant l'objet (la boîte de dialogues), une fenêtre décrivant les propriétés de l'objet, et une boîte à outils permettant d'ajouter des contrôles à la boîte de dialogue. Dans la fenêtre Propriétés, on peut modifier le titre (‘caption’) de la boîte de dialogue et son nom de façon à lui associer un identificateur plus "parlant" (par défaut le nom est ‘Userform + un numéro’) par exemple ‘Choix’. 1) Ajout d'une liste déroulante à la boîte de dialogue Dans la boîte à outil choisir l'objet "Zone de liste modifiable", le dessiner sur la boîte de dialogue, lui donner un nom par exemple Maliste1. La façon la plus simple de mettre cette liste déroulante en relation avec la feuille de calcul est d'utiliser les propriétés de l'objet : • La propriété "RowSource" correspond à la zone de la feuille contenant la liste des éléments parmi lesquels l'utilisateur doit faire son choix : indiquer ici le nom de cette zone, (à condition bien sû de l'avoir nommée). 2) Insertion d'un compteur et d'une zone de texte associée Dans la boîte à outil choisir l'objet "Zone de texte", le dessiner sur la boîte de dialogue et lui donner un nom par exemple Texte1 et lui affecter une cellule ControlSource ; puis choisir l'objet "Toupie", le dessiner sur la boîte de dialogue et lui donner un nom par exemple Compteur1. Remplir les propriétés Max, Min et value de cet objet (Attention ces valeurs sont entières). G. Mauffrey Introduction à la programmation VBA page 5/51 Pour lier ces deux objets, il faut alors créer des méthodes associées aux événements intéressants, ici le fait de cliquer sur la toupie ou d'entrer une valeur dans la zone de texte. Pour cela sélectionner un objet et cliquer sur le bouton droit de la souris pour choisir "code". • Pour la toupie, par défaut il vous est demandé le code pour tout changement de valeur (événement Change), il faut alors mettre à jour la valeur de la zone Texte1 par le code suivant : Choix.Texte1.Value=Choix.Compteur1.Value/100 • Pour la zone de texte, on opère de la même façon, soit avec l'événement Change, soit ce qui est plus simple si on veut contrôler la valeur entrée avec l'événement Exit : Choix.Compteur1.Value=Choix.Texte1.Value*100 3) Ajout du bouton OK Dessiner le bouton changer son Caption, puis lui affecter comme code en cas de click, la fin de dialogue en cachant simplement la boîte : Choix.Hide 4) Initialisation des objets Pour que les listes déroulantes et les zones de texte ne soient pas vides lors du premier chargement de la boîte de dialogue, il est possible d'utiliser l'événement Initialize de la boîte, avec le code suivant : Choix.Maliste1.ListIndex=0 (affiche le premier élément) Choix.Texte1.Value=Choix.Compteur1.Value/100 5) Exécution de la boîte de dialogue Insérer un module contenant une seule macro d'une ligne : Choix.Show Il suffira alors d'exécuter cette macro pour ouvrir le dialogue et de mettre dans la deuille de calcul les éléments choisis par l’utilisateur : Range("tissu")=Choix.Maliste1.value Amélioration de la boîte de dialogue Il s'agit ici de faire apparaître l'imprimé du tissu, dans une image quand le client choisit un autre tissu et de visualiser les dimensions relatives de la fenêtre. G. Mauffrey Introduction à la programmation VBA page 6/51 On obtiendra alors le dialogue suivant : Pour cela, il nous faut d'abord dans les données Excel associer à chaque tissu un fichier image, donc ajouter une colonne à la table de données des tissus cette dernière colonne contenant le chemin d'accès complet à ce fichier (Exemple c:\mesdessins\imprime1.wmf). Dans un premier temps, il est possible de considérer une image unique pour tous les tissus. Sur la boîte de dialogue, il faudra alors préparer une zone image pour recevoir cette image, et ajouter deux barres de défilements pour ajuster sa taille qui correspondra à celle de la fenêtre, pour afficher les dimensions de la fenêtre on utilisera aussi deux zones de libellés. La taille maximum de l'image correspond à la taille maximum de la fenêtre (par exemple 150 pixels sur 90 pixels pour une fenêtre de 5m sur 3m); on aura alors un facteur de conversion de 0,3 entre les pixels sur l'image et les mètres sur la fenêtre (noté ‘coef’ dans la suite). La zone image (nous lui avons donné le nom de im_fenetre) est définie sur la boîte de dialogue par son sommet supérieur gauche (propriétés ‘top’ et ‘left’ de l'objet) et sa hauteur et largeur (propriétés ‘height’ et ‘width’ de l'objet). Ces quatre propriétés devront être modifiées quand l'utilisateur utilisera les barres de défilement; de façon plus précise les deux propriétés top et height avec la barre verticale, left et width avec la barre horizontale. Les valeurs correspondant au coin inférieur gauche de l'image à la taille maximale sont conservées au moment de l'initialisation de la boîte de dialogue : Lebas = Im_fenetre.Top+im_fenetre.Height Lagauche=Im_fenetre.Left Ces valeurs serviront à calculer la place de l'image à chaque définition de la taille de la fenêtre. Les barres de défilement sont à placer sur la boîte de dialogue aux côtés de la zone image dans son format le plus grand. Ne pas oublier de définir le maximum et le minimum des valeurs admissibles (ces valeurs doivent être entières et correspondent aux dimensions maximales possibles en cm pour la fenêtre), ces deux barres seront nommées respectivement sc_hauteur et sc_largeur. En désignant par lab_hauteur et lab_largeur les étiquettes associées à l'affichage des valeurs, le code associé au changement de valeur de la barre de défilement est alors le suivant. G. Mauffrey Introduction à la programmation VBA page 7/51 Private Sub Sc_hauteur_Change() Im_fenetre.Top = lebas - (Sc_hauteur.Max - Sc_hauteur.Value) * 0.3 Im_fenetre.Height = (Sc_hauteur.Max - Sc_hauteur.Value) * 0.3 Lab_hauteur.Caption = CStr((Sc_hauteur.Max - Sc_hauteur.Value) / 100) & " m" End Sub Les deux premières instructions concernent l'image (sa position et sa taille), la dernière est uniquement un affichage dans l'étiquette de la valeur correspondant en mètres pour la fenêtre. L'écriture pour l'autre barre de défilement est laissée au lecteur. Il nous reste à changer d'image quand l'utilisateur change de tissu, donc à associer ce changement d'image au changement de valeur de la liste modifiable du tissu (combotissu). En nommant nomfic la variable contenant le nom du fichier image, le code est le suivant : Private Sub Combotissu_Change() Im_fenetre.Picture = LoadPicture(nomfic) End Sub G. Mauffrey Introduction à la programmation VBA page 8/51 Éléments de programmation avec VBA La programmation en Visual Basic pour Application (VBA) permet d’ajouter aux logiciels de Microsoft Office des fonctionnalités nouvelles, tout en utilisant les interfaces déjà définies par ces applications. Les programmes en VBA, ne sont pas des entités indépendantes et ne peuvent fonctionner que sous l’application parent (Excel, Word etc..). D’autre part ces applications peuvent utiliser des objets propres à l’application parent par l’intermédiaire d’objets prédéfinis accessibles au programmeur ; par exemple une ou plusieurs cellules d’une feuille de calcul, un graphique ou des dialogues prédéfinis tels que le dialogue d’ouverture de fichiers ou de sauvegarde. L’incorporation de ces nouvelles fonctionnalités se fait par l’intermédiaire de « Macros » qui sont des procédures sans argument qui peuvent être appelées depuis l’application parent (ici Excel). 3 Organisation d'un projet sous Excel L'ensemble des macros, procédures, fonctions, boites de dialogues et éventuellement objets constituant une application en VBA est appelée un projet. Ces différents constituants doivent être implémentés dans des zones précises : Projet VBA Modules Modules de Classe UserForms Déclarations Procedures Fonctions Propriétés Méthodes Déclarations Gestion des événements Un module est un ensemble de procédures et de fonctions qui utilisent en commun des variables et des constantes qui leur sont propres et qui, par défaut, ne sont pas accessibles aux autres modules ou boites de dialogues. Un module de classe permet à l'utilisateur de définir ses propres objets, propriétés, méthodes, de façon conceptuelle. Nous reviendrons dans un autre chapitre sur ces modules. Un UserForm est une boite de dialogue, contenant à la fois la description physique des contrôles qui la composent et les procédures événementielles nécessaires à leur gestion. Dans ce chapitre nous nous limiterons aux modules. 4 Notions générales de programmation Un programme est un ensemble d'instructions qui permettent de résoudre une classe de problèmes ; ces instructions sont regroupées en entités qui constituent des procédures, des fonctions ou des objets. Les instructions sont exécutées en séquence dans l'ordre où elles apparaissent dans le programme. Ces instructions sont constituées de « mots –clés » propres au langage et de variables qui permettent de stocker des valeurs durant l'exécution du programme. G. Mauffrey Introduction à la programmation VBA page 9/51 4.1 La notion de variables et de type de variable Une variable est une zone de la mémoire centrale qui permet de stocker des valeurs durant l'exécution du programme, cette valeur peut bien sûr évoluer au cours de cette exécution. En général la nature du contenu de la variable reste la même durant tout le programme (par exemple entier, réel ou chaîne de caractères) : on dit que la variable est typée, le type de la variable détermine la taille utilisée en mémoire. Il est d'usage en "bonne programmation" de déclarer les variables avant leur utilisation, certains langages tels que Pascal, C ou Java rendent obligatoire cette déclaration, en revanche le Basic autorise l'utilisation de variables sans déclaration ; il est toutefois recommandé de faire cette déclaration. Enfin le langage VBA, contrairement à Java par exemple, n'est pas sensible à la « casse » (no « case sensitive »), c'est à dire qu'il ne différencie pas les majuscules des minuscules. 4.1.1 Les différents types de variable. Tous les langages possèdent des types prédéfinis que l'on peut utiliser dans les programmes, en VBA les principaux types sont les suivants : 1. Types "classiques" Entier : entre -32 768 et 32 767, nommé INTEGER. Entier long : entre -2 147 483 648 et 2 147 483 647, nommé LONG. Réel simple : entre -3,402823E38 et -1,401298E-45 pour les nombres négatifs et entre 1,401298E-45 et 3,402823E38 pour les positifs, nommé SINGLE Réel double : entre -1,79769313486232E308 et -4,94065645841247E-324 pour les nombres négatifs et entre 4,94065645841247E-324 et 1,79769313486232E308 pour les positifs, nommé DOUBLE. Booléen : ne peuvent avoir pour valeur que True ou False, nommé BOOLEAN. Chaîne de caractères : contient du texte (2^31 caractères au max), nommé STRING. Une chaîne de caractère est affectée à une variable avec des guillemets : Machaine="Voilà trois mots" Pour assembler deux ou plusieurs chaînes de caractères on utilise l'opérateur de « concaténation » , & (esperluette ou « et commercial »). 2. Type objet Le type objet est un type générique qui permet à l'utilisateur de définir ses propres objets dans la philosophie de la programmation objet, nous reviendrons dans un autre chapitre sur cette notion. Toutefois, en VBA, les objets de l'application parent sont prédéfinis et peuvent être utilisés dans les programmes, nous ne développerons pas ici tous les objets d'Excel, mais en fonction des exercices nous donnerons quelques indications sur les objets utilisés. On pourra consulter l'aide de VBA ou mieux l'explorateur d'objet de VBA, pour avoir une idée sur la diversité des objets. 3. Le type Variant Le type Variant est le type par défaut de VBA, c'est à dire attribué à toute variable non déclaré explicitement. De façon générale la première affectation de valeur à une variable de ce type lui donne un type "classique" qu'elle conservera par la suite, il est donc assez dangereux d'utiliser ce type (donc de ne pas déclarer une variable dans un programme). G. Mauffrey Introduction à la programmation VBA page 10/51 4.1.2 Les caractéristiques d'une variable Une variable a trois caractéristiques importantes : Son nom : c'est un identificateur qui permet de faire référence à la variable, son premier caractère doit être une lettre, il est composé d'au plus 255 caractères, différents de ., !, @, &, $, #. Il est recommandé de ne pas utiliser de noms déjà définis soit comme mot clé, soit comme fonction, procédure ou objet dans VBA. La visibilité : c'est l'ensemble des modules, procédures ou fonctions qui peuvent accéder à cette variable. Par défaut la visibilité d'une variable est locale, c'est à dire limitée au module, à la procédure ou la fonction où la variable est définie. Nous verrons plus loin comment étendre cette visibilité. Si à un endroit du programme un nom peut faire référence à deux variables visibles, c'est la variable locale (définie dans la procédure) qui a priorité. La durée de vie : c'est le temps d'exécution du programme pendant lequel la variable est accessible (peut prendre une valeur). Par défaut la durée de vie d'une variable est le temps d'exécution du module, de la procédure ou de la fonction dans lequel la variable est utilisée. 4.1.3 La déclaration de variable Pour déclarer une variable, on emploie généralement une instruction Dim. Une instruction de déclaration peut être placée dans une procédure pour créer une variable de niveau procédure. Elle peut être également placée au début d'un module, dans la section Déclarations, pour créer une variable de niveau module. L'exemple suivant crée la variable machaine et spécifie le type de données String : Dim machaine As String Par défaut les déclarations sont locales au niveau où elles sont faites, c'est à dire que la visibilité de la variable est limitée au module ou à la procédure de déclaration. De même leur durée de vie est limitée à l'exécution de la procédure ou du module, la variable étant réinitialisé à chaque exécution. Ces valeurs par défaut peuvent être modifiées par le programmeur. Une variable est rendue visible de tous les modules et formulaires si à la place du mot clé Dim sa déclaration est précédée du mot clé Public dans la partie Déclaration d'un module, dans ce cas sa durée de vie est celle de l'application parent (Excel ici). Exemple : Public nbclients as Integer Une variable peut être déclarée comme Static dans ce cas, elle n'est pas réinitialisée à chaque exécution de la procédure ou du module. Par exemple, la suite d'instructions : Static moncompteur as integer moncompteur=moncompteur+1 …… Donnera la valeur 1 à moncompteur lors de la première exécution de la procédure, puis la valeur 2 à l'exécution suivante etc. , c'est cette déclaration qui permet, par exemple, de nommer par défaut les feuilles d'un classeur Excel. G. Mauffrey Introduction à la programmation VBA page 11/51 Remarque : il est possible de rendre obligatoire la déclaration des variables dans un module en utilisant l'option explicite par l'instruction : Option Explicit 4.2 Les instructions En Basic chaque instruction correspond à une ligne de programme, il est cependant possible en Visual Basic de mettre sur une même ligne plusieurs instructions séparées par ‘ : ’ On distingue deux types d'instructions (en dehors des appels de procédures que nous verrons plus loin) : les instructions d'affectation et les instructions de contrôle. 4.2.1 L'instruction d'affectation L'instruction d'affectation permet de donner une valeur à une variable, elle peut prendre deux formes suivant le type de la variable. Pour une variable de type classique, la syntaxe de l'instruction est la suivante : nom_var=expression La variable de nom ‘nom_var’ prend la valeur définie par expression, l'ancienne valeur est effacée de la mémoire et ne peut plus être récupérée. Exemples machaine ="C'est une chaîne" X= Y+23*Z X = X+1 Attention ne pas confondre cette affectation avec l'égalité mathématique, cette relation d'affectation n'est pas symétrique, l'élément de gauche est modifié et doit donc être une variable, les éléments apparaissant à droite du signe = restent inchangés. Pour une variable de type objet, l'instruction d'affectation commence par le mot clé Set : Dim mazone as Range Set mazone = Range("toto") 4.2.2 Les instructions de contrôle Les instructions de contrôles sont liées aux structures de contrôle structure alternative ou structure répétitive. Une structure alternative est un ensemble d'instructions dont seulement une partie est exécutée suivant certaines conditions, une structure répétitive est un ensemble d'instructions qui sont exécutées un nombre fini de fois. 4.2.2.1 Structures alternatives Une condition est une relation logique entre deux expressions constituées à partir de variable et/ou de constantes. Les opérateurs logiques sont ‘=’ l'égalité (à ne pas confondre avec l'affectation) ‘>’,‘<’, (resp. ‘>=’,‘<=’) inégalités strictes (resp. larges) Les connecteurs logiques qui permettent de modifier ou d'associer des conditions sont : AND, OR, XOR, NOT : conjonction, disjonction, disjonction stricte, négation. Quand on utilise ces connecteurs, il faut mettre entre parenthèses les différentes conditions. G. Mauffrey Introduction à la programmation VBA page 12/51 Remarque : il existe d'autres opérateurs de comparaison que l'on peut consulter dans l'aide en ligne. La structure alternative de base est : Si (condition) alors instruction1 sinon instructions2 , la partie sinon étant facultative. La syntaxe correspondante est : If condition Then Instructions à exécuter si la condition est vérifiée Else Instructions à exécuter si la condition n'est pas vérifiée End If Evidemment la section Else de la structure peut contenir une autre structure alternative. Dans certains cas il est plus court d'utiliser une autre structure qui est la structure de sélection. Cette structure permet d'exécuter certaines instructions suivant les différentes valeurs d'une variable donnée. La syntaxe des instructions correspondantes est la suivante : Select Case nom_var Case val1 Instructions à exécuter si nom_var=val1 Case val2, val3 Instructions à exécuter si nom_var=val2 ou val3 Case val4 To val5 Instructions à exécuter si val4<=nom_var<=val5 Case Is > val6 Instructions à exécuter si nom_var>val6 Case Else Instructions à exécuter dans tous les autres cas End Select Remarque : un seul des "case" est exécuté, il faut donc que les cas ne se recoupent pas. 4.2.2.2 Structure répétitive Une structure répétitive permet l'exécution d'un ensemble d'instructions un nombre fini de fois, nous ne détaillerons pas ici toutes les structures répétitives mais simplement les deux plus importantes. La structure For .. Next Si le nombre de répétition est connu à priori on utilise la structure For .. Next, dont la syntaxe est : For compteur = a to b step c Instructions à exécuter Next compteur a représente la valeur de départ b la valeur maximum et c l'incrément, positif ou négatif. Par défaut c est supposé égal à 1 et la partie step peut être omise dans ce cas. La structure While .. Wend Quand le nombre de répétition n'est pas connue, mais qu'il est limité par une condition, on utilise la structure : G. Mauffrey Introduction à la programmation VBA page 13/51 Initialisation de la condition While condition Instructions à exécuter modification de la condition Wend Les instructions sont répétées tant que la condition est vraie. Attention, il ne faut pas oublier dans ce cas d'initialiser la condition avant d'entrer dans la "boucle" et de modifier cette condition avant l'instruction Wend, sinon soit on n'entre jamais dans la boucle, soit on n'en sort jamais ("boucle infinie"). La structure Do ……. Loop La structure itérative la plus générale est la structure : Do [{While | Until} condition] Instructions à exécuter Modification de la condition Loop Ou Do Instructions à exécuter Modification de la condition Loop [{While | Until} condition] Dans la seconde formulation le programme exécute une fois au moins les instructions de la structure itérative. Remarque : cette structure serait suffisante, la structure For .. Next pouvant être remplacée par la suite d'instructions : compteur = a Do while compteur<=b Instructions à exécuter compteur=compteur+c Loop 4.3 Procédures et Fonctions Plutôt que d'écrire un programme long et difficile à déboguer, il est d'usage en bonne programmation de décomposer les tâches à exécuter en tâches plus petites auxquelles sont associées soit des procédures soit des fonctions. Ceci permet d'ailleurs d'utiliser à partir de différentes procédures ces éléments. Le programme principal, ou la procédure principale en VBA, étant alors presque uniquement constitué de déclaration et d'appel aux procédures et fonctions. 4.3.1 Procédures Une procédure est donc un ensemble d'instructions permettant d'effectuer une tâche précise, en utilisant certaines variables du programme appelant pour modifier les valeurs d'autres variables du programme appelant ou pour effectuer des affichages ou pour saisir des données. Une procédure peut effectuer des modifications sur certaines variables tout en n’utilisant que les valeurs (non modifiées) d'autres variables, on pourrait schématiser une procédure de la façon suivante : G. Mauffrey Introduction à la programmation VBA page 14/51 Procédure Ma proc Entrées Sorties Les variables d'entrée et de sortie doivent correspondre à des variables déclarées dans le programme appelant. Les variables qui sont uniquement utilisées comme variables d'entrée ne doivent théoriquement pas être modifiées durablement par la procédure, et seules leurs valeurs sont passées à la procédure, on dit qu'on a un passage par valeur. En revanche les variables de sortie doivent être modifiées définitivement par la procédure et c'est donc l'adresse mémoire qui doit être passée à la procédure, on dit qu'on a un passage par Référence. Déclaration d'une procédure En VBA la déclaration d'une procédure se fait par le mot clé Sub, la fin de la procédure est marquée par le mot clé End Sub. La déclaration est l'instruction : Sub nom_proc (Byval entr1 as type1, Byval entr2 as type2,..,Byref sor1 as types1,..) Par défaut le passage est par référence, le mot clé Byref peut donc être omis, le type est par défaut variant mais il est recommandé dans la mesure du possible de le spécifier. Les noms de variables entre parenthéses correspondent aux paramètres de la procédure et sont locaux à cette procédure, il ne doivent pas être redéclarés dans le corps de la procédure et ne sont pas nécessairement les mêmes que ceux des variables correspondant dans le programme appelant ; ce qui permet d'appeler cette procédure de différents programmes. Appel d'une procédure Le programme ou procédure qui utilise la procédure doit y faire référence parmi ses instructions, cette instruction particulière est appelée instruction d'appel de procédure. Cette instruction a la forme suivante : nom_proc var1, var2, .. Les variables var1, var2, .. doivent être déclarées dans la procédure appelante et de même type que les paramètres de la procédure et être mises dans le même ordre que lors de la déclaration de procédure. Remarque : en VBA, il est recommandé de déclarer les procédures avant de les appeler dans un programme, car l'éditeur VBA vous aide lors de l’écriture de l'instruction d'appel en énumérant les variables de la déclaration ainsi que leur type. Procédure appelable de l'application parent Seules les procédures sans arguments sont appelables depuis l'application parent, elles correspondent en fait à un programme autonome. 4.3.2 Fonctions Dans le cas particulier où la variable de sortie est unique, il est possible de définir la procédure sous forme de fonction, dans ce cas le nom de la fonction ‘nom_fonc’ joue le rôle de variable de sortie. G. Mauffrey Introduction à la programmation VBA page 15/51 Déclaration d'une fonction La déclaration d'une fonction se fait par le mot clé Function, la fin des instructions de définition étant marquée par le mot clé End Function. La structure d'une fonction est alors la suivante : Function nom_fonc(Byref val1 as type1, Byref val2 as type2,…) as typefonc Instructions… nom_fonc = valeur End Function Ne pas oublier la dernière instruction (dans l'exemple) qui donne la valeur de la fonction. Utilisation d'une fonction dans une procédure Pour utiliser une fonction dans une procédure, il suffit d'affecter sa valeur à une variable(de même type) déclarée dans cette procédure : mavar =nom_fonc(var1,var2,..) où var1, var2 sont des variables ou des valeurs de même type que val1, val2 dans la déclaration. Utilisation d'une fonction dans Excel Les fonctions définies en VBA sont accessibles, sauf spécification du programmeur (voir plus loin), dans une feuille d'un classeur. Il suffit dans une cellule de taper : =nom_fonc(v1,v2,..) où v1, v2 sont des valeurs ou des adresses de cellules. Portée des procédures et fonctions Par défaut les procédures et fonctions sont Public, donc visible de tout module et d'Excel, le programmeur peut changer cette option en précisant le caractère local de la procédure ou fonction par le mot clé Private. Dans ce cas les procédures et fonctions ne peuvent être appelées que d'une procédure ou fonction du module et ne peuvent donc, en particulier, pas être appelées de l'application parent (Excel en l'occurrence). 5 A propos des variables objets définis par Excel Une variable objet est une variable complexe, composée de données ( sous variables qui peuvent elles même être des variables objets) appelées propriétés et de procédures ou fonctions appelées méthodes. Nous verrons dans un autre chapitre comment créer ces variables, ici nous ne intéresserons qu'aux variables objets déjà créées dans le programme Excel et accessibles à l'utilisateur de VBA. Pour atteindre les propriétés ou méthodes d'une variable objet, il faut indiquer le nom de la variable suivie d'un point puis le nom de la propriété ou de la méthode. Il est évidemment hors de question d'être exhaustif, aussi nous n'indiquerons ici que quelques variables de base nécessaires pour les entrées/sorties sur les classeurs et feuilles de calcul. L'ensemble des objets peut être exploré grâce à l'explorateur d'objet de l'éditeur VBA (menu Affichage…Explorateur d'objet ou icône : ). L'objet de base pour atteindre les objets définis par Excel est une variable nommée Application qui représente Excel. Il est généralement inutile de rappeler cette variable quand on utilise ses propriétés. G. Mauffrey Introduction à la programmation VBA page 16/51 5.1 Les classeurs 5.1.1 La collection des classeurs ouverts L'ensemble des classeurs ouverts sous Excel sont des objets de type WorkBook regroupés dans une collection (tableau dynamique) qui est une propriété de l'objet application et qui a pour nom Workbooks. Ces classeurs sont indexés soit par un nombre (1, 2,…) ( mais ce nombre dépend de l'ordre d'ouverture des classeurs) soit par la chaîne de caractères de leur nom. Par exemple pour atteindre le classeur de nom "Cestlemien", on peut utiliser les instructions suivantes : Dim Monclas as WorkBook Set Monclas =Application.WorkBooks("Cestlemien") On peut en fait se dispenser de préciser Application : Set Monclas =WorkBooks("Cestlemien") Le classeur actif est le classeur par défaut, il est repéré par la variable ActiveWorkbook. Pour créer un nouveau classeur (équivalent du menu Fichier Nouveau), on utilisera la méthode (fonction) Add : Set Monclass = WorkBooks.Add Ce classeur deviendra le classeur actif Pour explorer l'ensemble des classeurs ouverts, on utilisera la boucle For each .. in..- Next : Dim Unclas as WorkBook For Each Unclas In Workbooks MsgBox Unclas.Name Next affichera successivement tous les noms des classeurs ouverts. 5.1.2 Quelques propriétés et méthodes de l'objet Workbook Pour fermer un classeur on utilise la méthode Close avec éventuellement deux arguments, le premier argument booléen indiquant s'il faut conserver les modifications, le deuxième donnant le nom du fichier sous lequel doit être sauvegardé le classeur. Monclass.close True,"C:\Mesdocs\Machin.xls" Si les arguments sont omis, la demande de sauvegarde des modifications est affichée, et éventuellement, si le nom est demandé si le classeur n'avait pas déjà été sauvegardé. Pour rendre un classeur actif, on utilise la méthode Activate Monclass.Activate Le classeur devient alors le classeur actif, généralement on aura pris soin de conserver au préalable dans une variable de type Workbook, l'ancien classeur actif : Set AncClasActif=ActiveWorkBook Pour connaître le répertoire du fichier associé à un classeur, on utilisera la propriété Path, pour avoir son nom complet (répertoire+nom de fichier) la propriété FullName, par exemple : MsgBox ActiveWorkbook.FullName G. Mauffrey Introduction à la programmation VBA page 17/51 Un classeur est composé de feuilles de calcul, chaque feuille de calcul est un objet de type WorkSheet, regroupées dans une collection associée à la propriété WorkSheets d'un objet de type WorkBook. Par exemple : Workbooks("Cestlemien").Worksheets Désigne l'ensemble des feuilles de calcul du classeur ouvert et nommé "Cestlemien". On peut explorer les noms des feuilles de calcul comme celui des classeurs à l'aide de la structure, For each .. in..- Next . L'ensemble des feuilles (Calcul et Graphique) d'un classeur est conservé dans la collection Sheets. 5.2 Les objets Feuilles 5.2.1 La collection des feuilles d'un classeur Il n'existe qu'un seul type d'objet Feuille, l'objet feuille de calcul de type WorkSheet, objets regroupés dans la collection Worksheets vue ci-dessus, les feuilles graphiques n'ont pas de type particulier, elles apparaissent dans la collection Sheets, au même titre que les autres feuilles. Nous ne parlerons ici que des feuilles de calcul, nous reviendrons sur les feuilles graphiques dans un autre document. Comme les classeurs, les feuilles de calcul d'un classeurs sont indexées par un numéro et par leur nom, par exemple la feuille de nom "majoliefeuille" du classeur "Cestlemien" peut-être associée à une variable de la façon suivante : Dim LaFeuille as Worksheet Set LaFeuille =WorkBooks("Cestlemien").Worksheets("majoliefeuille") Si la feuille appartient au classeur actif, il est inutile de préciser ce classeur. Pour ajouter une nouvelle feuille de calcul à un classeur, on utilisera la méthode Add de la collection Worksheets, les instructions suivantes ajoutent une feuille au classeur actif et lui donnent le nom "Ma nouvelle feuille" : Dim Nouvfeuil As Worksheet Set Nouvfeuil = Worksheets.Add Nouvfeuil.Name = "Ma nouvelle feuille" La feuille active du classeur est associée à la variable prédéfinie ActiveSheet. Pour énumérer les noms des feuilles de calcul du classeur actif on pourra utiliser les instructions suivantes : Dim elt As Worksheet For Each elt In Worksheets MsgBox elt.Name Next Dans ce cas le nom des feuilles graphiques n'apparaîtra pas, si l'on veut énumérer les noms de toutes les feuilles du classeur actif il faudra utiliser les instruction suivantes : For Each elt In Sheets MsgBox elt.Name Next Attention : on ne peut déclarer la variable ‘elt’ comme ayant un type particulier (Sheet par exemple) car ce type n'existe pas, éventuellement on peut la déclarer comme un objet. G. Mauffrey Introduction à la programmation VBA page 18/51 5.2.2 Quelques propriétés et méthodes de l'objet WorkSheet Nous avons vu précédemment la propriété Name qui permet de retrouver ou de changer le nom d'une feuille, alors que pour un classeur il n'est possible que de retrouver (lire) le nom du classeur et il n'est pas permis de changer ce nom Pour activer une feuille de calcul on utilisera la méthode Activate, comme dans le cas d'un classeur, pour recalculer une feuille de calcul particulière on utilisera la méthode Calculate, cette opération de recalcul d'une seule feuille de calcul n'est possible qu'avec l'utilsiation de macros puisque la touche F9 recalcule toutes les feuilles de tous les classeurs ouverts et correspond en fait à l'instruction : Application.Calculate. On peut protéger et déprotéger une feuille de calcul à l'aide des méthodes Protect et UnProtect suivies du mot de passe : Dim LaFeuille as Worksheet ….. LaFeuille.Unprotect "Monmot" ….. LaFeuille.Protect "Monmot" Enfin pour connaître la plage utilisée sur une feuille on pourra utiliser la propriété UsedRange, qui renvoie un objet Range (cf plus bas) correspondant au rectangle circonscrit à l'ensemble des cellules utilisées de la feuille. 5.3 L'objet Range L'ensemble des cellules d'une feuille est réuni dans une collection Cells. Cette collection est doublement indexée, par les lignes et les colonnes. Pour désigner la cellule se trouvant à l'intersection de la ième ligne et de la jème colonne de la feuille nommée "Mabellefeuille" du classeur nommé "Monbeauclasseur" on utilise la formulation : Workbooks("Monbeauclasseur").Worksheets("Mabellefeuille").Cells(i,j) Si l'on veut faire référence à la feuille active (donc du classeur actif) il suffira d’écrire Cells(i,j). Il n'existe pas d'objet Cellule, mais un objet Range, qui correspond à une zone rectangulaire composée d'une ou plusieurs cellules. 5.3.1 Affectation d'une variable objet Range. Il existe plusieurs méthodes pour affecter une valeur à une variable de type Range, nous donnerons ici les trois principales (pour simplifier l'écriture nous les donnerons dans le cas de la feuille active). A partir des cellules coin supérieur gauche, coin inférieur droit, à partir de la collection Cells : Dim Mazone as Range Set Mazone=Range(Cells(1,1),Cells(4,5)) Ou à partir des adresses de type Excel mises entre guillemets : Set Mazone=Range("A1:E4") Enfin quand on a défini un nom dans un classeur Excel, il est possible de définir une variable à partir de ce nom mis entre guillemets : Set Mazone=Range("lenom") G. Mauffrey Introduction à la programmation VBA page 19/51 Pour explorer toutes les cellules de la variable Mazone, on utilisera la structure For Each : Dim elt as Range For Each elt in Mazone …… Next Enfin, comme pour les feuilles et les classeurs, il existe une variable prédéfinie correspondant à la zone sélectionnée sur la feuille active la variable nommée Selection, la cellule active étant associée à la variable ActiveCell. 5.3.2 Quelques propriétés et méthodes de l'objet Range Nous nous limiterons ici à quelques propriétés simples (Mazone est une variable de type Range déclarée par Dim Mazone as Range) : • Numéro de la ligne supérieure : Mazone.row • Numéro de la colonne de gauche : Mazone.column • Nombre de lignes de la zone : Mazone.rows.count • Nombre de colonnes de la zone : Mazone.columns.count • Pour la cellule se trouvant en ième ligne et jème colonne de la zone: Mazone.Cells(i,j) ; il n'y a pas de contrôle de débordement, en fait ceci localise la cellule qui se trouve à la ième ligne et jème colonne à partir du coin supérieur gauche de la zone. • Valeur de la cellule se trouvant à la ligne i, colonne j : Mazone.Cells(i,j).Value, la propriété Value étant la propriété par défaut, il est inutile de la préciser. • La propriété HasFormula retourne vrai si la cellule contient une formule, faux sinon • La propriété Formula retourne la formule de la cellule (en anglais) ou permet de mettre une formule dans une cellule • Pour effacer le contenu d'une zone : Mazone.Clear • Pour obtenir l'adresse d'une zone sous forme d'une chaîne de caratères : Mazone.Address • Pour décaler une plage, il existe une méthode Offset(décalage lignes, décalage colonnes), les décalages pouvant être positifs, négatifs ou nul. Cette méthode correspond à une fonction et retourne un objet Range. Exemple Dim Mazone as Range, Nouvzone as Range Set Mazone = Range ("C4:D8") Set Nouvzone=Mazone.offset(-2,3) Donnera pour Nouzone, la plage F2:G6 • Pour sélectionner la plage associée à la variable Mazone, on utilise la méthode Select : Mazone.Select • Pour obtenir la zone rectangulaire la plus petite contenant les cellules non vides connexes à une cellule donnée (par exemple la cellule active) on utilise la propriété CurrentRegion. • Pour lire ou entrer une formule dans une cellule, on utilisera soit la propriété Formula pour la formule en Anglais, soit la propriété FormulaLocal pour la formule dans la langue dans laquelle est installé Windows. G. Mauffrey Introduction à la programmation VBA page 20/51 Beaucoup d'autres propriétés peuvent être utiles, par exemple sur les formats, vous pouvez alors utiliser les commandes d'Excel correspondant en les enregistrant, puis les adapter à votre problème. Ne surtout pas oublier d'arrêter l'enregistrement!! G. Mauffrey Introduction à la programmation VBA page 21/51 6 Exercices Dans les trois premiers exercices, on supposera donné le nombre de lignes et de colonnes. 6.1 Exercice 1 Inverser les éléments d’une colonne Exemple : AAAA EEEE BBBB DDDD CCCC donne CCCC DDDD BBBB EEEE AAAA 6.2 Exercice 2 Pour un tableau inverser les éléments. Exemple : AAA AAA1 AAA2 FFF2 FFF1 FFF BBB BBB1 BBB2 EEE2 EEE1 EEE CCC CCC1 CCC2 DDD2 DDD1 DDD DDD DDD1 DDD2 CCC2 CCC1 CCC EEE EEE1 EEE2 BBB2 BBB1 BBB FFF FFF1 FFF2 AAA2 AAA1 AAA donne 6.3 Exercice 3 Pour un tableau, inverser les colonne et si la colonne est paire inverser ses éléments. Exemple : AAA AAA1 AAA2 AAA3 FFF3 AAA2 FFF1 AAA BBB BBB1 BBB2 BBB3 EEE3 BBB2 EEE1 BBB CCC CCC1 CCC2 CCC3 DDD3 CCC2 DDD1 CCC DDD DDD1 DDD2 DDD3 CCC3 DDD2 CCC1 DDD EEE EEE1 EEE2 EEE3 BBB3 EEE2 BBB1 EEE FFF FFF1 FFF2 FFF3 AAA3 FFF2 AAA1 FFF G. Mauffrey donne Introduction à la programmation VBA page 22/51 6.4 Exercice 4 On suppose ici que seul le nombre de lignes est donné, inverser alors les lignes et les éléments de chaque ligne. Exemple : AAA AAA1 AAA2 BBB BBB1 CCC CCC1 CCC2 DDD DDD1 AAA3 FFF3 FFF1 FFF1 FFF EEE donne DDD1 DDD CCC2 CCC1 CCC EEE FFF FFF2 FFF2 FFF3 BBB1 BBB AAA3 AAA2 AAA1 AAA 6.5 Exercice 5 Le programme choisi un nombre au hasard entre 0 et 100 (fonction RND) L’utilisateur doit trouver ce nombre en faisant des propositions (on pourra utiliser la fonction InputBox) 1) A chaque proposition de l’utilisateur le programme répond : • Trop grand • Trop petit Le programme s’arrête si le nombre est trouvé 2) A la fin du programme ajouter le nombre d’essais nécessaire au joueur pour gagner. 3) Dans votre programme vérifier la cohérence du joueur en fonction des informations qu’il reçoit. 6.6 Fusion de deux listes Dans une feuille de calcul, on dispose de deux listes de noms ordonnées par ordre alphabétique. Ecrire un programme qui fait la fusion ordonnée des deux listes en l'affichant dans une autre zone de la feuille. 6.7 Contrôle des résultats d'un vendeur Il s'agit de mettre en évidence les produits dont les objectifs de vente n'ont pas été atteints. Dans une zone de la feuille de calcul vous avez les éléments suivants : Produit Bicyclette Ballons Poupée Voiture Puzzle Objectif 100 2000 500 1500 180 Réalisé 50 2500 480 1420 250 Votre programme doit colorer les lignes où les objectifs ne sont pas atteints : G. Mauffrey Introduction à la programmation VBA page 23/51 Produit Bicyclette Ballons Poupée Voiture Puzzle Objectif 100 2000 500 1500 180 Réalisé 50 2500 480 1420 250 a) Vous supposerez tout d'abord donnés, la zone entière des produits et valeurs des objectifs et réalisés. b) Utiliser une boite de dialogue pour saisir les éléments du programme : Ecrire les procédures suivantes : • sélection des lignes d'une zone dont le coin supérieur gauche, le nombre de lignes, les numéros des colonnes à tester est donné • mise en couleur d'une ligne sélectionnée Ecrire les fonctions retournant le nombre de lignes et de colonnes adjacentes remplies à partir du coin supérieur gauche d'une zone Ecrire le programme utilisant ces procédures et permettant de résoudre le problème posé. 6.8 Coloration de cellules en fonction du contenu Sur une plage de données choisie par l'utilisateur colorier les cellules suivant leur contenu : • Couleur 1 pour les formules • Couleur 2 pour les textes • Couleur 3 pour les valeurs numériques (Utiliser la fonction IsNumeric) • Couleur 4 pour les cellules vides Les couleurs pourront être choisies par l'utilisateur G. Mauffrey Introduction à la programmation VBA page 24/51 7 Annexes – Quelques compléments sur VBA Excel 7.1 L'objet RefEdit d'une boite de dialogue L'objet RefEdit d'une boite de dialogue permet à l'utilisateur de saisir en pointant les adresses définissant une zone Excel. Sa valeur retourne la chaîne de caractères correspondant à la zone pointée : par exemple "$B$2". Il faut donc ensuite transformer cette chaîne en une adresse Excel par l'objet Range : Set mazone = Range(marefedit.value) 7.2 Quelques compléments sur l'objet Range L'objet Range définit une cellule ou un ensemble rectangulaire de cellules d'une feuille de calcul. On peut grâce aux propriétés de cet objet obtenir des renseignements sur cette zone ou adresser des cellules à partir du coin supérieur gauche de cette zone ou modifier l'apparence de cette zone ou d'une partie de la zone. La couleur de fond d'une cellule est attribuée en fonction de la palette associée au Classeur actif, elle est donnée par un nombre entier qui est appelé l'index de la couleur dans la palette, ce nombre est compris entre 0 et 52. Une valeur spéciale notée xlColorIndexnone correspond à aucun remplissage, pour affecter une couleur à l'intérieur d'une cellule on utilisera l'instruction : Mazone.Cells(i,j).Interior.ColorIndex =index de la couleur Pour savoir si une cellule est vide, il faut utiliser la constante Empty : If (Range("toto").Cells(i,j)=Empty) Then … 7.3 Les couleurs Pour utiliser les couleurs dans Excel ou dans les boites de dialogue, le plus simple est de définir leur composition RGB (Rouge, Vert, Bleu), chacune des valeurs étant comprise entre 0 et 255. Par exemple : Mondialogue.BackColor=RGB(0,0,255) définit un fond de boite de dialogue Bleu. RGB(0,0,0) correspond au noir, RGB(255,255,255) au blanc. On peut récupérer les couleurs de la palette avec la fonction Colors, qui est une méthode de l'objet Classeur (Workbook). Par exemple si on veut que le fond d'une zone étiquette(label) soit de la couleur 11 de la palette du classeur, on utilisera l'instruction suivante : Mon_etiquette.backcolor=ActiveWorkbook.Colors(11) G. Mauffrey Introduction à la programmation VBA page 25/51 Fichiers et boites de dialogues 8 Utiliser un fichier de l'application parent (Fichier xls) Il est souvent nécessaire dans une application VBA d'ouvrir un fichier du type de l'application Parent, en demandant à l'utilisateur de sélectionner ce fichier. Il est alors possible d'utiliser le dialogue standard de l'application. Le programmeur a accès à ces dialogues par la propriété ‘Dialogs’ de l'application qui est la collection de dialogues standard, chaque dialogue standard étant repéré par un index (un entier) associé à une mnémonique commençant par ‘xlDialog’ pour Excel, ‘wdDialog’ pour Word, etc… Par exemple l'instruction : Ouvert=Application.Dialogs(xlDialogOpen).Show provoque l'apparition de la boite de dialogue d'ouverture sous Excel : La variable Ouvert est une variable booléenne qui prend la valeur True si l'utilisateur a ouvert un fichier, False si l'utilisateur a cliqué sur le bouton Annuler. Le fichier ouvert est alors actif dans l'application. Pour adresser un autre classeur dans l'application on utilisera l'objet WorkBooks(nomduclasseur). Par exemple pour rendre actif le classeur dont le nom est Toto.xls on utilisera l'instruction : Workbooks("Toto.xls").Activate Il est aussi possible d'ouvrir directement, sans dialogue, un classeur dont on connaît le nom par l'instruction Workbooks.Open filename:=nom du fichier. Par exemple : Workbooks.Open filename:="c:\gm\vbasic\control1.xls" Pour fermer un fichier, on peut utiliser l'instruction Wokbooks(nomduclasseur).Close qui peut avoir comme paramètre (après ‘Close’) le fait de sauvegarder ou pas les modifications. Si ce paramètre est omis, la boite de dialogue de sauvegarde des modifications sera affichée. G. Mauffrey Introduction à la programmation VBA page 26/51 Par exemple : Workbooks ("control1.xls").Close False ferme le classeur précédemment ouvert sans sauvegarde, tandis que l'instruction Workbooks ("control1.xls").Close provoque en cas de modification l'affichage de la boîte de dialogue : Remarque il est possible d'utiliser des variables pour stocker les objets classeurs : Dim PremierCl as Workbook, DeuxiemeCl as Workbook 'On conserve le classeur actif avant d'ouvrir un nouveau classeur Set PremierCl=ActiveWorkbook If Application.Dialogs(xlDialogOpen).Show Then Set DeuxiemeCl=ActiveWorkbook ….. DeuxiemeCl.Close False End If ….. PremierCl.Close False 9 Contrôles multipage Un contrôle multipage est un contrôle qui contient plusieurs pages (ici, 2 pages, ‘Zones’ et ‘Couleur’) atteignables par un onglet dans lesquelles sont implantés des contrôles de saisie, l'utilisateur passant d'une page à l'autre en cliquant sur l'onglet. Les pages sont numérotées à partir de 0. G. Mauffrey Introduction à la programmation VBA page 27/51 Si le nom du contrôle multipage est ‘Detzon’, les pages se nomment ‘Detzon.Pages(0)’, ‘Detzon.Pages(1)’, etc.… Le programmeur n'a pas à gérer le click sur l'onglet ceci est fait automatiquement par Windows, en revanche s'il veut par programme modifier la page visible, le programmeur utilisera la propriété Value de la page. Par exemple pour rendre visible la page ‘Couleur’ de l'exemple ci-dessus, on utilisera l'instruction : Detzon.Pages(1).Value = True 10 Ajouts de contrôles dans une boîte de dialogues par programme Il peut être utile, comme nous le verrons dans l'exemple suivant, d'ajouter des contrôles dans une boîte ou un contrôle d'une boite de dialogue (par exemple une page ou un groupe). Ceci peut se faire à l'initialisation ou lors d'un événement provoqué par l'utilisateur. Pour ce faire, on utilise la méthode Controls.Add(type de contrôle) de l'objet auquel on veut ajouter le contrôle, type de contrôle est une chaîne de caractères définissant la nature du contrôle à ajouter. Les types de contrôles définis en VBA sont les suivants : Type du contrôle Chaîne de caractères CheckBox Forms.CheckBox.1 ComboBox Forms.ComboBox.1 CommandButton Forms.CommandButton.1 Frame Forms.Frame.1 Image Forms.Image.1 Label Forms.Label.1 ListBox Forms.ListBox.1 MultiPage Forms.MultiPage.1 OptionButton Forms.OptionButton.1 ScrollBar Forms.ScrollBar.1 SpinButton Forms.SpinButton.1 TabStrip Forms.TabStrip.1 TextBox Forms.TextBox.1 ToggleButton Forms.ToggleButton.1 (on pourra consulter l'aide en ligne de Controls.Add de MsForms pour plus de détails) Par exemple pour ajouter une étiquette ‘Monlabel’ (de libellé ‘Votre Choix’) à une boîte de dialogue ‘Maboite’, on utilisera les instructions suivantes : Set Monlabel = Maboite.Controls.Add("Forms.Label.1") Monlabel.Caption = "Votre Choix" 11 Un exemple Nous allons montrer ici comment construire le choix des couleurs dans un contrôle multipage nommé ‘Detzon’. G. Mauffrey Introduction à la programmation VBA page 28/51 Le problème : contrairement à Visual Basic, VBA ne connaît pas les collections de contrôle dans une boîte de dialogue, il n'est donc pas possible de définir les 56 couleurs comme une collection d'images et de récupérer par un événement Click, le numéro de la couleur choisie. Une solution : pour simuler ce comportement, nous allons créer des images de couleurs voulues à l'intérieur d'une autre image (nommée ‘Toutes’), les rendre inactive de façon à ce que l'application ne leur attribue pas les clicks de souris mais passe cet événement à l'image les contenant c'est à dire à ‘Toutes’. Remarque : il est plus simple de créer les contrôles images de couleur à l'initialisation car la procédure est moins fastidieuse et le choix des couleurs plus simple. Nous supposerons que l'image ‘Toutes’, en revanche, a été créée graphiquement et que sa taille est suffisante pour contenir toutes les images de couleur. Les images couleur sont présentées dans un tableau à 8 lignes et 7 colonnes (il y a 56 couleurs dans la palette), les couleurs étant rangées par ligne. La constante Marge désigne la marge droite, gauche, haut et bas par rapport à l'image container (Toutes) et aussi l'écart entre chaque image couleur (ligne et colonne) ; la constante Cote désigne le coté du carré correspondant à l'image couleur. Les lignes sont numérotées de 0 à 6 et les colonnes de 0 à 7, la ligne 0 contient donc les couleurs de 1 à 8, la ligne 1 les couleurs de 9 à 16 etc. L'image couleur qui se trouve à l'intersection de la ligne de numéro Ligne et de colonne de numéro Col correspond à la couleur de la palette d'index : 8*Ligne+Col+1. Le sommet supérieur gauche de chaque image est calculé en fonction de la position, et des constantes Marge et Cote. Voici le code correspondant à l'initialisation, les contrôles sont crées dans la page numéro 1 du contrôle multipage Detzon : Const Marge as Integer = 4 Const Cote as Integer = 14 Private Sub UserForm_Initialize() Dim Zcouleur As Image Dim Col As Integer, Ligne As Integer With Detzon.Pages(1) For Col = 0 To 7 For Ligne = 0 To 6 Set Zcouleur = .Controls.Add("Forms.Image.1") Zcouleur.Left = Toutes.Left + Marge + Col * (Cote + Marge/2) Zcouleur.Top = Toutes.Top + Marge + Ligne * (Cote + Marge/2) Zcouleur.Width = Cote Zcouleur.Height = Cote Zcouleur.BackColor = ActiveWorkbook.Colors(Ligne * 8 + Col + 1) 'Pour que le click de la souris arrive au cadre Toutes Zcouleur.Enabled = False Next Ligne Next Col G. Mauffrey Introduction à la programmation VBA page 29/51 End With Detzon.Value = 0 ' Active la première page du contrôle Multipage Detzon ……. End Sub Il nous faut maintenant intercepter le choix de couleur de l'utilisateur. Pour cela il faut connaître, les coordonnées du point où l'utilisateur a cliqué dans l'image ‘Toutes’, puisque les contrôles images de couleur sont inactifs. On utilisera pour ce faire l'événement Mouse_Down qui retourne ces coordonnées (X en abscisse relative à l'objet Toutes, Y en ordonnée), ainsi que le bouton (fmButtonLeft=1 pour le bouton gauche, fmButtonRight=2 pour le bouton droit, fmButtonMiddle=4 pour le bouton central) et la modification par une touche Majuscule, Control ou Alt. Après avoir vérifié que c'est bien le bouton gauche de la souris qui a été appuyé, la ligne et la colonne de l'image sont déterminées en fonction de X et Y, l'index de la couleur peut alors être calculé comme précédemment. Voici le code correspondant, la touche de modification est ignorée : Private Sub Toutes_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single) Dim Ligne As Integer, Col As Integer If Button = 1 Then Ligne = Int((Y - Marge) / (Cote +Marge/2)) Col = Int((X - Marge) / (Cote +Marge/2)) Numcoul = 8 * Ligne + Col + 1 Exemple.BackColor = ActiveWorkbook.Colors(Numcoul) 'Affichage de la couleur choisi dans la zone texte Exemple End If End Sub 12 Exercices Suivi de résultats Chaque semaine, vous recevez les résultats de tournois avec les points accordés à des joueurs sur un fichier Excel, les noms sont dans une zone de deux colonnes commençant en A1 (on pourra par la suite faire choisir la zone dans un contrôle RefEdit), les points dans une zone nommée Points. G. Mauffrey Introduction à la programmation VBA page 30/51 Exemple de fichier que vous pouvez recevoir : Durand 18 Jacques 15 Raymond 13 Albert 8 Bizarre 3 Il s'agit d'écrire un programme qui ne conserve que les trois meilleurs résultats des joueurs. Attention les noms ne sont pas les mêmes chaque semaine, il faut donc ajouter des noms dans votre fichier résumé au fur et à mesure des fichiers résultats. On pourra supposer soit que les fichiers sont nommés Résultatn.xls pour la semaine n, soit que l'utilisateur choisit le fichier résultat à traiter et la feuille de résultat dans ce classeur, on pourrait alors avoir une boîte de dialogue telle que : Indications pour le programme : a) Ecrire et vérifier une fonction ‘Trouvenom’ qui retourne un nombre entier représentant la ligne où se trouve un nom donné dans une zone donnée d'une feuille de calcul, si le nom n'existe pas la fonction retourne le numéro de la première cellule vide. b) Ecrire et vérifier une procédure écrivant la nouvelle note. Indications pour la boîte de dialogue : c) Pour remplir la liste modifiable des feuilles, il faut utiliser la méthode Additem. du contrôle. d) Pour la zone donnant un aperçu de la feuille, on pourra utiliser des contrôles Intitulé (Label). En les créant dynamiquement lors de l'initialisation du dialogue, il est possible de les stocker dans un tableau, ce qui peut faciliter leur gestion. Contrôle des objectifs (suite) Reprendre l'exercice sur le contrôle des objectifs, en utilisant un contrôle multipage pour le choix des zones et le choix des couleurs. Au lieu de se limiter à un exemple de la couleur, on fera apparaître dans le tableau des images couleur, la couleur choisie comme un bouton appuyé, les autres couleurs comme des boutons relevés (utiliser la propriété specialEffect de l'image). Pour cela, on sera conduit à stocker les images couleur dans un tableau. G. Mauffrey Introduction à la programmation VBA page 31/51 13 Annexe : Modification de la barre de menus Il est souvent utile pour des applications "clés en main" de modifier la barre de menu Excel, de façon à ce que l'utilisateur final puisse choisir dans un menu les opérations à effectuer. De plus le nouveau menu doit être installé au chargement du fichier et désinstallé quand l'utilisateur ferme le fichier. Nous allons indiquer ici comment écrire des procédures d'installation et de suppression d'éléments de menu, d'activation de menu, et comment lancer les procédures adéquates à l'ouverture et à la fermeture du fichier. 13.1 Ajout de menus à la barre de menus d'Excel La barre de menu est un objet CommandBar qui fait partie de la collection CommandBars, il peut être utile de stocker la barre de menu dans une variable (globale) : Dim labarre as CommandBar Set labarre = CommandBars.ActiveMenuBar Cette barre de menu, comporte des contrôles (les menus déroulant) qui sont des objets de type CommandBarPopup, il faut donc ajouter un contrôle de ce type à la barre de menu Excel et indiquer le titre de ce menu déroulant dans la propriété Caption de ce contrôle (si l'on veut pouvoir accéder à ce menu par un raccourci, il faut faire précéder la lettre de raccourci par le caractère &). Là aussi il est bon de conserver dans une variable globale ce contrôle de façon à pouvoir le supprimer éventuellement. On insère ce menu avant le ? qui est le dernier menu déroulant : Public monmenu as CommandBarControl Set monmenu = labarre.Controls.Add ( Type := msoControlPopup, Before:=labarre.Controls.Count) With monmenu .Caption = "A&moi" End With Si l'on veut que le menu soit oté quand l'utilisateur ferme l'application, on ajoutera lors de la création du contrôle, le paramètre temporary avec la valeur vraie. L'instruction sera alors: Set monmenu = labarre.Controls.Add(….., Temporary:=true) On ajoutera ensuite ensuite les élément du menu qui seront soit de type CommandBarButton pour des commandes soit CommandBarPopup pour des sous menus. Ces contrôles sont évidemment ajoutés au menu personnalisé. Là aussi on donnera le texte avec la propriété caption, pour associer une procédure à la commande on utilise la propriété OnAction, pour rendre la commande active ou inactive on utilise la propriété Enabled, si l'on veut une ligne de séparation avant la commande on mettra à vrai la propriété BeginGroup qui par défaut est à faux. Les contrôles ainsi créés sont ajoutés à la collection Controls du menu et sont repérés par leur index 1,2,..n qui correspond à l'ordre de création. Par exemple : G. Mauffrey Introduction à la programmation VBA page 32/51 Dim ctrl as CommandBarButton, sousmenu as CommandBarPopup With monmenu.Controls Set ctrl = .Add (Type:=msoControlButton) With ctrl .Caption = "Commande1" .Onaction= "Proc1" End With Remarque : ce sera monmenu.Controls(1) Set sousmenu = .Add(Type :=msoControlPopup) With sousmenu .caption = "sousmenu1" .BeginGroup= True Set Ctrl = .Controls.Add( Type := msoControlButton) etc… Remarque : sousmenu estmonmenu.Controls(2), tandis que Ctrl nouvellement défini est monmenu.sousmenu.controls(1) Toutes les instructions de création du menu seront regroupées dans une procédure, ici nommée Crée_menu. 13.2 Suppression du menu personnalisé Comme le menu personnalisé a été conservé dans une variable globale, il suffit d'écrire une procédure (Ote_menu, par exemple) ne contenant qu'une instruction : Monmenu.Delete 13.3 Activation ou désactivation de commandes Il suffit de changer la valeur de la propriété Enabled du contrôle correspondant : Monmenu.Controls(i).Enabled = Not Monmenu.Controls(i).Enabled 13.4 Installation du menu à l'ouverture du fichier Il peut être bon que le menu ne soit affiché que lorsque le classeur actif est le classeur de l'application, nous allons utiliser l'évenement Activate de l'objet WorkBook d'Excel, pour cela en VBA cliquer dans l'explorateur de projets, sur l'élément ThisWorkbook, puis dans la fenêtre de code, choisir l'élément WorkBook dans la liste déroulante de gauche (qui affiche par défaut Général), automatiquement il y a création d'une procédure WorkBook_Open, il nous faut alors choisir l'événement Activate et dans la procédure WorkBook_Activate il suffit d'écrire l'instruction d'appel de la procédure de création de menu : Crée_menu Pour effacer le menu quand le classeur n'est plus actif, on utilisera l'événement Deactivate, et nous n'entrerons qu'une seule instruction : Monmenu.delete Remarque : si l'on veut que le menu soit actif durant toute la session Excel après le chargement du classeur contenant la macro et quel que soit le classeur actif, il faut alors utiliser l'événement d'ouverture du classeur et bien évidemment ne plus utiliser l'événement Deactivate. G. Mauffrey Introduction à la programmation VBA page 33/51 Récursivité 14 Généralités On appelle récursive toute procédure ou fonction qui de façon directe ou indirecte fait appel à elle-même. Exemple : la fonction puissance nième (pour n>=0) d'un nombre A peut être définie par : A0=1 et An=A*An-1 Ce qui se traduit en VB par la fonction suivante : Function Puissance(ByVal A as Double, Byval n as Integer) as Double If n=0 Then Puissance = 1 (1) Else Puissance = A * Puissance( A , n-1) (2) End if 14.1 End Function Quelques remarques sur cette écriture 1. La procédure est arrêtée par le test conditionnel à 0 (1), Dans toute procédure ou fonction récursive, il doit y avoir une condition d'arrêt, qui empêche toute boucle "infinie" 2. Dans l'instruction (2) bien faire la différence entre le nom Puissance à gauche du signe d'affectation qui donne une valeur à la fonction et l'appel de la fonction puissance qui se trouve à droite et qui donc "relance" la fonction 3. La variable n doit être passée en valeur sous peine de voir sa valeur "écrasée" par les appels successifs de la fonction. En revanche le passage de A est indifférent dans la mesure où cette variable est inchangée dans la fonction 4. Dans le cas où le passage en valeur serait impossible (Tableau, type utilisateur par exemple), il est nécessaire de créer des variables locales dans la fonction ou la procédure. Leur portée étant limitée à la copie en cours de la fonction. 15 Exécution d'une procédure ou fonction récursive : Nous allons suivre ici l'exécution de l'instruction de la procédure appelante X = puissance( 5, 3) 1. Une première "copie" de la fonction est créée en mémoire avec des variables locales A1 =5 et n1=3 L'exécution est suspendue à l'instruction (2) car puissance( 5,2) est inconnue 2. Une deuxième copie de la fonction est alors créée avec les variables locales A2=5 et n2=2 L'exécution est suspendue à l'instruction (2) G. Mauffrey Introduction à la programmation VBA page 34/51 3. Une troisième copie de la fonction est créée avec les variables locales A3=5 et n3=1 L'exécution est suspendue à l'instruction (2) 4. 3b. Cette fois ci, avec A4=5 et n5=0, la copie s'exécute est retourne puissance(5,0)=1 La troisième copie peut se terminer et retourne alors Puissance(5,1)=5 2b. La deuxième copie peut se terminer et retourne alors Puissance(5,2) = 25 1b. La première copie se termine et retourne au programme appelant Puissance(5,3)=125 La récursivité permet de programmer de façon plus simple et souvent plus « lisible », mais en revanche cette méthode utilise plus de mémoire que les méthodes classiques et le temps d’exécution d’un programme peut rapidement dégénérer (cf. exercice 2) G. Mauffrey Introduction à la programmation VBA page 35/51 16 Exercices Exercice n°1 Ecrire une fonction récursive permettant de calculer n ! Exercice n°2 On rappelle que les nombres de Fibonnacci sont définis par F(1)=F(2)=2 F(n)=F(n-1)+F(n-2) a) Ecrire une fonction récursive permettant de calculer le nième nombre de Fibonnacci b) Ecrire une fonction non récursive permettant de calculer ce nombre c) Comparer les temps d’exécution pour n=30, expliquer cette différence. Exercice n°3 Reprendre l'exercice de fusion de deux listes et l'écrire sous forme récursive Exercice n°4 On vous donne la liste suivante : Père Jules Jules Marius César Bernard Edouard Gustave Fils Marius César Bernard Edouard Noël Hubert Jules Il s’agit d’écrire un programme permettant de déterminer les ancêtres d’une personne choisie dans la liste des fils. On pourra améliorer ce programme, en sortant l’arbre généalogique de la personne choisie pour obtenir par exemple : Gustave G. Mauffrey Jules Marius Bernard Noël César Edouard Hubert Introduction à la programmation VBA page 36/51 Exercice n°4 : Quelques Fractales a) La courbe de van Koch En partant d’un segment de longueur L0 (F0), on définit un générateur qui transforme ce segment en quatre segments de longueur L1=L0/3 (F1). Puis ce générateur est appliqué à chacun des 4 segments de F1 (F2) etc.. F0 F1 F2 On obtient ainsi, à la limite, une courbe continue, de longueur infinie (puisque la longueur est multipliée par 4/3 à chaque étape) et non différentiable. Seules les extrémités des segments de chaque étape sont conservées dans la courbe finale. On appelle résolution la longueur minimale qu’un observateur peut distinguer, ceci revient à arrêter le processus de construction à l’étape où la longueur d’un segment est inférieure ou égale à cette résolution. Construire un programme permettant de construire la courbe de van Koch à une résolution donnée : Indications : On définira de façon récursive la transformation d’un segment en quatre segments, en définissant les extrémités des nouveaux segments. Pour ceux qui auraient oublié leur trigonométrie, voici les formules définissant ces coordonnées (dans le repère d’une feuille graphique) x0deb,y0deb définissent les coordonnées de l’extrémité initiale du segment, x0fin, y0fin celles de l’extrémité finale. Avec des notations évidentes : x1deb = x0deb x1fin = (2 * x0deb + x0fin) / 3 y1deb = y0deb y1fin = (2 * y0deb + y0fin) / 3 x2deb = x1fin x2fin = x2deb + (x0fin – x0deb) / 6 + (y0fin – y0deb) * Sqr(3) / 6 y2deb = y1fin y2fin = y2deb - (x0fin – x0deb) * Sqr(3) / 6 + (y0fin – y0deb) / 6 x3deb = x2fin x3fin = x3deb + (x0fin – x0deb) / 6 - (y0fin – y0deb) * Sqr(3) / 6 y3deb = y2fin G. Mauffrey Introduction à la programmation VBA page 37/51 y3fin = y3deb + (x0fin – x0deb) * Sqr(3) / 6 + (y0fin – y0deb) / 6 x4deb = (x0deb + 2 * x0fin) / 3 x4fin = x0fin y4deb = (y0deb + 2 * y0fin) / 3 y4fin = y0fin On partagera le segment suivant le générateur jusqu'à ce que la résolution soit atteinte, alors on tracera le segment correspondant. Voir en annexe les indications pour ouvrir une feuille graphique et tracer des segments sous Excel Si on part d'un carré, au lieu d'un segment on obtient alors le flocon : b) Le triangle de Sierpinski A partir d’un triangle équilatéral (F0), on partage ce triangle en quatre triangles équilatéraux dont on ne conserve que les trois "extérieurs" (F1) l'opération étant alors répétée sur ces trois triangles conservés(F2) ; l'opération se répète indéfiniment. Ici ce sont les côtés qui sont F0 F1 1.1.1 conservés dans la fractale finale. Ecrire un programme, permettant de construire cette fractale à une résolution donnée : Remarque : on pourra utiliser les types suivants définis par l'utilisateur : G. Mauffrey Introduction à la programmation VBA page 38/51 Type MonPoint Abscisse as Integer Ordonnée as Integer End Type Type Triangle Sommets(1 To 3) as MonPoint End Type Indications : On construira les triangles intérieurs à un triangle donné, jusqu'à ce que la résolution voulue soit atteinte auquel cas on tracera le triangle correspondant. G. Mauffrey Introduction à la programmation VBA page 39/51 17 Annexe 1 - Utilisation des dessins sous Excel1. Les dessins sont sous Excel des objets de la collection "Shapes" qui est une propriété d'une feuille de calcul ou graphique. Ils sont donc obtenus en ajoutant des objets sur une feuille bien définie. a) Ajout d'une feuille graphique à un classeur. Les instructions suivantes ajoute une feuille graphique au classeur, l'associe à la variable mondessin, puis détermine la taille de la zone de graphique et enfin donne un nom à la feuille ainsi créée ActiveWorkbook.Sheets.Add Type:=xlChart Set mondessin = ActiveChart With mondessin.ChartArea hauteur = .Height largeur = .Width End With mondessin.Name = "triangle" L'origine des coordonnées de la feuille se trouve dans le coin supérieur gauche de la feuille. b) Ajout d'un segment sur une feuille. Sur la feuille graphique précédemment créer, on peut ajouter un segment de droite joignant le point de coordonnées x1,y1 au point de coordonnées x2,y2 : Set line = mondessin.Shapes.AddLine(x1, y1, x2, y2) c) Ajout d'un triangle On pourrait bien évidemment construire un triangle à l'aide de trois segments comme indiqué au-dessus, cependant dans ce cas la figure ne serait pas considérer comme "fermée" et le remplissage serait délicat à faire. Nous allons donc utiliser des primitives de polygone fermé, qui contienne les fonctions de remplissage, ce sont les "formes libres". Voici la suite d'instructions pour créer un polygone de sommet (x0,y0), (x1,y1), …, (xn,yn). With mondessin.Shapes.BuildFreeform(msoEditingAuto, x0, y0) 'Initialise le polygone par son premier sommet .AddNodes msoSegmentLine, msoEditingAuto, x1, y1 .AddNodes msoSegmentLine, msoEditingAuto, x2, y2 'Ajout des différents sommets .AddNodes msoSegmentLine, msoEditingAuto, xn, yn 'Ne pas oublier de fermer .AddNodes msoSegmentLine, msoEditingAuto, x0, y0 'Sauvegarder dans une variable le polygone fermé Set montruc = .ConvertToShape 'Remplir d'une couleur montruc.Fill.ForeColor.RGB = RGB(100, 100, 100) End With 1 Pour d'autres types de dessin, vous pouvez utiliser l'enregistrement automatique de macro et regarder le code obtenu. G. Mauffrey Introduction à la programmation VBA page 40/51 18 Annexe 2 – Quelques éléments sur la courbe de Koch en tant que fractale La lecture de cette annexe n'est pas indispensable pour la réalisation des programmes. La courbe de Koch est un exemple simple de fractale auto-similaire, à chaque résolution on retrouve le même motif (générateur), si la dimension topologique de cette courbe est la même que celle d'une droite, c'est à dire 1, on "devine" qu'elle occupe plus de place dans le plan qu'une courbe classique (différentiable) car elle se replie beaucoup sur elle-même ; c'est pour cela que sa longueur est infinie, alors qu'elle définit un ensemble fermé et borné (un compact de R2). Toutefois elle ne remplit pas entièrement une surface telle qu'un carré : sa surface est nulle, d'où l'idée de définir une dimension pour laquelle sa longueur sera finie ; cette dimension sera strictement comprise entre 1 et 2. Soit une courbe de longueur finie L, elle peut être approximée par L* (1/ε) segments de longueur ε, de même une surface finie S peut être approximée par S*(1/ε)2 carrés de côté. Ici pour approximer la courbe de van Koch avec des segments de longueur (1/3)n, il en faut L0*(4)n, on peut alors définir comme dimension de cette courbe le nombre DF tel que : 4n=(3n)DF c'est à dire : DF = log(4)/log(3) La "longueur" de la courbe de van Koch dans cet espace fractal est alors L0! La construction faite pour la courbe de van Koch peut être généralisée, à partir d'un générateur qui partage un segment donné en p segments égaux de longueur égale à 1/q fois le segment initial, la dimension de la fractale obtenue étant alors : log(p)/log(q). Exemple : si l'on considère le générateur suivant : On obtient une fractale de dimension 4/3, car ici p=4 et q=2*racine(2) G. Mauffrey Introduction à la programmation VBA page 41/51 19 Annexe 3 – A propos du triangle de Sierpinski Le triangle de Sierpinski propose, en quelque sorte, une approche duale de van Koch de la construction de fractale puisque ici, partant d'une surface, on obtient un ensemble de dimension inférieure. L'origine de cette construction peut se trouver dans l'ensemble de Cantor (exemple classique d'ensemble ne contenant aucun intervalle et compact, avec beaucoup d'autres propriétés intéressantes) défini à partir du schéma générateur : F0 F1 Ce qui conduit à la "poussière" de Cantor de dimension log2/log3 : Le triangle de Sierpinski a comme dimension fractale log3/log2. On peut passer en dimension 3 avec un cube et le schéma générateur suivant : On obtient alors l'"éponge" de Sierpinski de dimension log22/log3 Pour en savoir plus sur les fractales, voici une bibliographie sommaire : - Mandelbrot , B., Les objets fractals (avec une introduction au mouvement brownien fractionnaire utilisé en finance par exemple) – NSB Flammarion, Paris, 1989 - Le Méhauté, A., Les géométries Fractales (est abordée ici la différenciation fractionnaire) – Hermès, Paris, 1990 - Nottale, L., Fractal Space-Time and Microphysics (avec application à la physique et quelques liens avec le chaos) – World Scientific 1993 G. Mauffrey Introduction à la programmation VBA page 42/51 Introduction à la programmation Objet 20 Généralités Traditionnellement la programmation sépare le code (instructions) des données. Par exemple en Pascal, les données sont spécifiées dans des structures, et le code est regroupé en unités (les procédures et les fonctions). Les fonctions (ou procédures) et les structures ne sont pas formellement reliées dans les langages traditionnels, une fonction peut être utilisée sur différentes structures et une structure peur utiliser des fonctions différentes qui ne lui sont pas propres. Dans la programmation objet le code et les données sont rassemblés dans une entité appelée "Objet". Cet objet peut être considéré comme une boîte noire qui reçoit et envoie des messages à un autre objet ou à un programme ‘traditionnel’. Un objet est composé de données définissant ses caractéristiques (propriétés) et d'une interface permettant de traiter les messages reçus ou d'envoyer des messages, cette interface 2 Message Propriétés est composée de procédures, fonctions et réponses à des évènements, appelées méthodes. Seules les méthodes sont accessibles de l'extérieur de l'objet (Principe d'encapsulation des données). Les objets de même nature font partie d'une même classe, qui est la description abstraite des propriétés et méthodes des objets, l'équivalent en fait du type pour une variable. Cette classe est en fait un sous programme qui se suffit à lui-même, un utilisateur externe n'a pas besoin de connaître le contenu exact de ce programme mais seulement l'interface, ce qui permet la réutilisation des objets, sous forme compilée, dans différents programmes. La déclaration de cette classe comportera donc des variables correspondant aux propriétés et des procédures ou fonctions correspondant aux méthodes. Les variables correspondant aux propriétés ne doivent pas être directement accessibles à l'utilisateur, mais sont accessibles par de méthodes particulières. 20.1 Un exemple : l'objet nombre complexe. Les propriétés de cet objet peuvent être : Partie réelle Partie imaginaire Module Argument Les méthodes : G. Mauffrey Ecriture d'un nombre sous forme algébrique (x+iy) Ecriture d'un nombre sous forme géométrique (r,θ) Introduction à la programmation VBA page 43/51 Addition de deux nombres complexes Multiplication de deux nombres complexes Etc.. 20.2 Utilisation d'objets dans un programme Pour utiliser un objet dans un programme, il faut lui associer une variable qui a comme type le nom de la classe d'objets. Il faut ensuite réserver la place mémoire nécessaire au stockage des propriétés de cet objet, ceci se fait dans de nombreux langages et en VBA en particulier par la fonction New ( voir ci-dessous). Les propriétés et méthodes de l'objet sont appelées en indiquant nom_variable_objet.méthode ou nom_variable_objet.propriété 21 Définition d'une classe d'objets sous VBA Pour satisfaire les contraintes énoncées précédemment, la classe d'un objet doit être définie dans un module qui lui est propre, c'est ce que VBA appelle un module de classe. Pour créer un module de classe, utiliser le menu Insertion-Module de Classe, puis dans les propriétés du module de classe donner un nom à la classe ainsi créée. Les variables de stockage des propriétés seront déclarées comme Private, en revanche les méthodes accessibles à l'utilisateur seront déclarées comme Public. Remarque : dans un module de classe, il peut exister des procédures ou fonctions qui ne sont utilisées que par ce module et sont donc cachées à l'utilisateur, dans ce cas il faut bien sur les déclarer comme Private. 21.1 Déclaration des propriétés La déclaration des propriétés d'un objet se fait en deux temps : Déclaration d'un espace de stockage privé associé Déclaration de procédure de communication pour l'affectation de valeur aux propriétés ou la lecture de la valeur de la propriété par un utilisateur externe : Procédure Property Let pour l'affectation d'une valeur à un type non-objet Procédure Property Set pour l'affectation d'une valeur à une propriété objet Fonction Property Get pour la lecture de la valeur d'une propriété Remarque importante : C'est le nom associé aux procédures ou fonctions ‘property’ qui définissent le nom de la propriété, c'est à dire le nom connu des utilisateurs ; le nom des variables de stockage privées est évidemment ignoré de l'utilisateur et peuvent être quelconques. Il est recommandé de ne pas utiliser les noms des zones de stockage dans les méthodes (mis à part les procédure Property), mais le nom des propriétés. Par exemple pour la classe des nombres complexes, pour la propriété partie réelle on fera les déclarations suivantes : Private M_reel as double zone de stockage privée Public Property Let Reel (ByVal x as double) M_reel = x ‘(code complémentaire éventuel) End Property G. Mauffrey Fin de la procédure d'affectation Introduction à la programmation VBA page 44/51 Remarque : cette procédure est appelée d'un programme par l'instruction : (Dim Moncomplexe as complexe) Moncomplexe.Reel = unevaleur Où ‘moncomplexe’ est une variable objet de la classe des nombres complexes, la valeur une valeur est alors stockée dans la variable locale à la classe ‘M_reel’. Public Property Get Reel() as double Reel =M_reel End Property Fin de la fonction de lecture Remarque : cette fonction est appelée d'un programme par l'instruction Autreval = Moncomplexe.Reel La valeur de la variable locale (à la classe) M_reel est alors stockée dans la variable du programme appelant Autreval. Certaines propriétés peuvent n'être qu'en lecture, c'est à dire qu'un utilisateur n'aura pas le droit d'en changer directement la valeur, dans ce cas, il suffit de ne pas écrire dans la classe de procédure Property Let ou Property Set (ou mieux encore de l'écrire avec le mot clé Private), voir dans l'exemple le cas du module et de l'argument. 21.2 La procédure d'initialisation Pour chaque classe d'objet, il est nécessaire de créer une procédure d'initialisation qui est appelée par l'instruction New. Cette procédure initialise les variables de stockage de l'objet à des valeurs par défaut, et par ce fait réserve l'espace mémoire de l'objet. Cette procédure est privée, sans paramètre et a pour nom Class_Initialize Par exemple pour les nombres complexes, on pourrait avoir la procédure suivante : Private Sub Class_Initialize() reel = 0 imaginaire = 0 module=0 argument=0 End Sub Cette procédure sera appelée dans le programme principal par l'instruction : Set moncomplexe = New complexe Comme dans cette procédure les noms de propriétés ne sont pas précédées d'un "." Cela signifie que ces noms se rapportent à l'objet courant, c'est à dire l'objet qui a appelé la méthode. Remarque : dans certains cas, par exemple s'il existe un dessin associé à l'objet, il est nécessaire de faire certaines opérations quand l'objet est "détruit" par l'instruction : Set nom_objet = Nothing Il faut alors écrire une méthode privée appelée Class_terminate. G. Mauffrey Introduction à la programmation VBA page 45/51 21.3 Ecriture de méthodes L'écriture de méthodes est identique à l'écriture de procédure ou de fonction dans un programme "classique", simplement le nom donné à la procédure ou fonction est le nom de la méthode connue de l'utilisateur. Bien évidemment ces procédures doivent être déclarées comme Public. Exemples : a- Méthode mise à zéro d'un nombre complexe, cette méthode sera appelée par l'instruction : Moncomplexe.mis_a_0 Public Sub mis_a_0 () Reel = 0 Imaginaire=0 End Sub Remarque : comme Reel n'est pas précédée d'un . elle fait référence à l'objet appelant. b- Ecriture algébrique d'un nombre complexe, cette méthode retourne un "String" contenant l'écriture x+iy, elle est appelée par l'instruction : Chaine = Moncomplexe.ecrit_algeb Public Function ecrit_algeb () as String Ecrit_algeb=Cstr(Reel) & " + i " & Cstr(Imaginaire) End Function c- Terminons avec une méthode un peu plus délicate, la multiplication de deux nombres complexes, le résultat étant stocké dans un troisième. L'appel sera fait par l'instruction : comp3 = comp1.mult(comp2) où comp1, comp2 et comp3 sont des variables objet ‘complexe’. Dans cette méthode nous devons créer un nouvel objet qui recevra le résultat, ce qui est fait par l'instruction New, le reste du code est assez simple : Public Function Mult( autrec as complexe) as complexe Set Mult = New complexe 'crée l'objet With autrec Mult.Reel = .Reel*Reel -.Imaginaire*Imaginaire Mult.Imaginaire=.Reel*Imaginaire+.Imaginaire*Reel End With End Function 21.4 Enregistrement d'une classe Comme une classe est autosuffisante, il est bon de l'enregistrer en tant que module de classe indépendant réutilisable dans tous les programmes visual basic ; ceci se fait en exportant le module qui prend alors un nom d'extension ‘cls’. 21.5 Utilisation d'objets dans un programme Pour utiliser des objets dans un programme, il faut déclarer des variables du type de l'objet, par la déclaration Dim : G. Mauffrey Introduction à la programmation VBA page 46/51 Dim machin as nom_de_classe Réserver l'espace de stockage par l'instruction new : Set machin = new nom_de_classe Ensuite l'appel des méthodes se fait en utilisant le nom de la variable objet. le nom de la méthode, avec les conventions habituelles suivant que la méthode correspond à une fonction ou une procédure. Quand l'utilisateur, au moment de l’écriture de son programme, tape le point, il apparaît une fenêtre contextuelle, avec toutes les propriétés et méthodes de la classe d'objet. 22 Un exemple de module de classe : la classe des complexes Voici le début de la définition de la classe des complexes, les conventions suivantes ont été choisies : L’utilisateur peut lire et écrire les parties réelles et imaginaires d’un nombre complexe, en cas d’écriture le module et l’argument sont recalculés (procédure privée calmodarg) L’utilisateur ne peut que lire le module et l’argument de façon indépendante, il faudra créer une méthode de saisie du couple (cf. exercice1) Seules les méthodes de multiplication et d’écriture ont été implémentées Le fichier correspondant est accessible sur le site Web. Const pi As Double = 3.14159265358979 Dim m_reel As Double Dim m_imaginaire As Double Dim m_module As Double Dim m_argument As Double Public Property Let reel(ByVal p_reel As Double) m_reel = p_reel calmodarg End Property Public Property Get reel() As Double reel = m_reel End Property Public Property Let imaginaire(ByVal p_imaginaire As Double) m_imaginaire = p_imaginaire calmodarg End Property Public Property Get imaginaire() As Double imaginaire = m_imaginaire End Property G. Mauffrey Introduction à la programmation VBA page 47/51 Public Property Get module() As Double module = m_module End Property Private Property Let module(ByVal modu As Double) m_module = Abs(modu) End Property Public Property Get argument() As Double argument = m_argument End Property Private Property Let argument(ByVal angle As Double) m_argument = angle End Property Private Sub Class_Initialize() reel = 0 imaginaire = 0 calmodarg End Sub Private Sub calmodarg() module = reel ^ 2 + imaginaire ^ 2 module = Sqr(module) If module = 0 Then argument = 0 Else If reel = 0 Then argument = Sgn(imaginaire) * pi / 2 Else argument = Atn(imaginaire / reel) argument = (1 - Sgn(reel)) * pi / 2 + argument End If End If End Sub Public Function mult_compl(autrec As complexe) As complexe Set mult_compl = New complexe With autrec mult_compl.reel = reel * .reel - imaginaire * .imaginaire mult_compl.imaginaire = reel * .imaginaire + imaginaire * .reel G. Mauffrey Introduction à la programmation VBA page 48/51 End With End Function Public Function ecriture_cart() As String ecriture_cart = CStr(reel) & " + " & CStr(imaginaire) & "i" End Function Public Function ecriture_geom() As String ecriture_geom = module & " exp(" & argument & "i)" End Function Private Sub calmodarg() module = reel ^ 2 + imaginaire ^ 2 module = Sqr(module) If module = 0 Then argument = 0 Else If reel = 0 Then argument = Sgn(imaginaire) * pi / 2 Else argument = Atn(imaginaire / reel) argument = (1 - Sgn(reel)) * pi / 2 + argument End If End If End Sub Public Function mult (autrec As complexe) As complexe Set mult = New complexe With autrec mult.reel = reel * .reel - imaginaire * .imaginaire mult.imaginaire = reel * .imaginaire + imaginaire * .reel End With End Function Public Function ecriture_cart() As String ecriture_cart = CStr(reel) & " + i" & CStr(imaginaire) End Function Public Function ecriture_geom() As String ecriture_geom = module & " exp(i" & argument & ")" End Function G. Mauffrey Introduction à la programmation VBA page 49/51 23 Exercices 23.1 Compléter la classe des nombres complexes Ecrire les méthodes permettant de : Additionner deux nombres complexes Multiplier un nombre complexe par un nombre réel, le résultat étant stocké dans le nombre complexe initial (correspondrait à l’instruction "classique" z=λ*z) Saisir le module et l'argument d'un nombre complexe, la méthode doit alors calculer les parties réelle et imaginaire du nombre. Bien évidemment il vous faudra aussi écrire un programme permettant de tester ces nouvelles méthodes. 23.2 Relation entre deux tables On considère une liste d'entreprises (Table ‘Père’) avec leur localisation, chaque entreprise étant caractérisée par un code, et d'autre part une liste de contacts dans ces entreprises (Table ‘Fils’), contenant le nom de la personne, le code de la société à la quelle elle appartient, son service. Code Société Nom 12 LilleHaut 14 MegaSoft 15 Packard Adresse Roubaix Lyon Bordeaux Nom Dupond Durand Jules Germain Fortin Gremont Boudard Fonction Code Société Marketing 12 Finance 15 Compta 14 DRH 12 Informatique 15 Planification 11 Production 12 Construire un objet relation entre ses tables, cet objet doit mettre en relation le code société des deux tables et permettre : De vérifier qu'aucun code de la table fils n'est erroné D'afficher tous les contacts pour une entreprise donnée De supprimer une société et tous les contacts associés Indications : La relation sera définie comme une classe, dont les propriétés contiendront entre autres l'adresse des tables, l'adresse du code en relation L'affichage de tous les contacts pourra se faire par exemple en coloriant la zone correspondant à la société et les zones correspondant aux contacts, on pourra par exemple supposer que la société choisie correspond à la cellule active de la feuille. Exemple : G. Mauffrey Introduction à la programmation VBA page 50/51 Code Société Nom 12 LilleHaut 14 MegaSoft 15 Packard Adresse Roubaix Lyon Bordeaux Nom Dupond Durand Jules Germain Fortin Gremont Boudard Fonction Code Société Marketing 12 Finance 15 Compta 14 DRH 12 Informatique 15 Planification 11 Production 12 La cellule sélectionnée est associée en VBA à la variable objet de type Range : Selection. Le remplissage d'une cellule peut se faire avec l'instruction : Cells(i, j).Interior.Colorindex = n Où n est un entier compris entre 1 et 56 représentant la couleur de numéro n dans la palette, pour indiquer aucun remplissage on utilise la valeur xlColorIndexnone. Remarque : il faudra bien sûr prévoir une méthode remettant à blanc la sélection. Une autre façon de procéder pourrait consister à afficher les contacts d'une société quand l'utilisateur clique sur une cellule contenant le code d'une société, dans ce cas il faut utiliser la procédure Worksheet_SelectionChange(ByVal Target As Excel.Range) de la feuille de calcul contenant les tables, le code à écrire dans cette procédure consisterait à vérifier que la cellule sélectionnée (Target) est bien une cellule contenant un code, puis à sélectionner les contacts correspondant : On Error goTo Fin 'pour le cas où l'objet ‘ma relation’ n'est pas initialisé If marelation.contient(Target) then Marelation.Traitement End if Fin: 23.3 La classe triangle Construire une classe triangle, dont les propriétés sont les sommets, la couleur de remplissage, etc.., dont les méthodes sont entre autres : le dessin du triangle et certaines transformations géométriques (translation , homothétie par exemple) G. Mauffrey Introduction à la programmation VBA page 51/51