VISUAL BASIC & EXCEL
TP 1
Calendrier avec affichage des fêtes mobiles
Voici comment se présente le logiciel Excel 97 sur un PC :
Sur cet écran, la résolution est de 600x800 points, mais sur
votre Mac, elle peut être différente. Ceci explique que le nombre
de lignes ou de colonnes visibles ne soit pas identique.
L'année dernière, vous avez déjà travaillé avec le tableur Excel. Vous avez sans doute appris à manipuler les cellules d'une feuille de calcul grâce à des formules bien choisies. Vous savez sans doute également comment modifier la taille des cellules et leur aspect (bordures, trames de fond). Vous avez aussi appris à gérer les polices de caractères ainsi que les commandes du menu Edition (copier, couper coller). De plus, un document Excel peut comporter plusieurs feuilles de calcul : ces feuilles sont accessibles en cliquant sur les onglets en bas de l'écran.
Il s'agit cette année d'aller plus loin en ajoutant des commandes programmées par vous mêmes. Ces commandes seront capables d'exécuter des suites d'instructions plus ou moins complexes, avec des boucles, des structures conditionnelles, des appels à d'autres commandes. Pour réaliser ces commandes, nous utiliserons le langage de programmation intégré à Excel : Visual Basic.
1. Exemple de programme écrit en VBA (Visual Basic pour Application)
Ce premier programme va nous permettre de réaliser un calendrier. Lorsque vous l'aurez tapé et essayé, vous pourrez le modifier à votre goût.Choisir, la commande Outils/Macro/Vusual Basic Editor (le raccourci clavier sur PC est Alt-F11). On obtient alors l'écran suivant :
Effectuez un double-clic, à gauche, sur Feuil1(Feuil1), ou choisir la commande Affichage/Code afin d'obtenir une page blanche dans laquelle nous pourrons écrire notre programme. Ce programme sera associé à la feuille de calcul nommée Feuil1 (dont on pourra éventuellement changer le nom).Tapez le programme ci-dessous. Les lignes qui commencent par des apostrophes ( ' ), sont des commentaires. La présence de commentaires n'est pas obligatoire mais recommandée. Cela permet de mieux comprendre le texte du programme (si quelqu'un d'autre veut le modifier par exemple...)Remarques préliminaires : Visual Basic apporte une aide importante pendant la saisie. Ainsi, les mots du langage basic (comme sub, InputBox, For, BorderAround ) seront tapés entièrement en minuscules et, s'il n'y a pas d'erreur de frappe, les arguments éventuels seront proposés sous le curseur. Au moment du passage à la ligne, si tout est correct, des majuscules se mettent automatiquement. Bien entendu, comme dans tout éditeur de texte, vous pouvez utiliser les commandes habituelles du menu Edition (couper, copier, coller). Par ailleurs, certains mots s'affichent en couleur (les commentaires sont en vert, les mots-clés sont en bleu...).
'Macro Calendrier
'Réalisée par P. Rabiller le 04/02/2002Dim Année 'Déclaration d'une variable "Année" utilisable dans tout le programmeSub Calendrier() 'programme principal
SaisirAnnée
RéglerLargeurDesColonnes
AfficherTitre
AfficherNomsMois
AfficherJours
End SubSub SaisirAnnée() 'demande à l'utilisateur de taper une année
Année = InputBox("Tapez l'année :", "Calendrier")
End SubSub RéglerLargeurDesColonnes() 'chaque mois occupera 3 colonnes de largeurs 2, 2 et 15
For c = 1 To 12
Columns(3 * c - 2).ColumnWidth = 2
Columns(3 * c - 1).ColumnWidth = 2
Columns(3 * c).ColumnWidth = 15
Next c
End SubSub AfficherTitre()
For semestre = 1 To 2 'le calendrier sera imprimé sur 2 pages, une par semestre
Cells(1, 18 * semestre - 17) = "Année " & Année
Range(Cells(1, 18 * semestre - 17), Cells(1, 18 * semestre)).Select
With Selection
.HorizontalAlignment = xlHAlignCenterAcrossSelection
.VerticalAlignment = xlVAlignCenter
.Font.Name = Arial
.Font.Size = 20
.Font.Bold = True
.BorderAround Weight:=xlThick
.Interior.ColorIndex = 4
End With
Next semestre
End SubSub AfficherNomsMois() 'affichage des noms des 12 mois
For m = 1 To 12
ch = Format("1/" & m, "dd mmmm")
Cells(2, 3 * m - 2) = Mid(ch, 4, 10)
Range(Cells(2, 3 * m - 2), Cells(2, 3 * m)).Select
With Selection
.HorizontalAlignment = xlHAlignCenterAcrossSelection
.VerticalAlignment = xlVAlignCenter
.Font.Name = Arial
.Font.Size = 14
.Font.Bold = True
.BorderAround Weight:=xlThick
.Interior.ColorIndex = 15
End With
Next m
End SubSub AfficherJours() 'affichage des jours : 1ère lettre + rang du jour
For m = 1 To 12
For j = 1 To 31
ch = Format(j & "/" & m & "/" & Année, "dddd")
If IsDate(j & "/" & m & "/" & Année) Then
Cells(2 + j, 3 * m - 2) = Mid(ch, 1, 1)
Cells(2 + j, 3 * m - 1) = j
End If
Next j
Range(Cells(3, 3 * m - 2), Cells(33, 3 * m)).BorderAround Weight:=xlThick
Next m
End SubDès que le programme est tapé, il est prudent d'enregistrer le travail sous le nom Calendrier1 par exemple (les versions suivantes seront nommées calendrier 2, calendrier 3 etc...)Pour exécuter notre programme, il faut retourner à la feuille de calcul à l'aide de la commande Affichage/Objet ou Affichage/Microsoft Excel ou Alt-F11 puis choisir la commande Outils/Macro/Macros qui fait apparaître la fenêtre ci-contre :
Il suffit alors de choisir la macro " Feuil1.calendrier " et de cliquer sur le bouton " exécuter ".Modifier ensuite, les largeurs des colonnes, au besoin, afin de permettre une impression sur 2 pages en format paysage. Pour cela, utilisez la commande Fichier/Mise en page puis cliquez sur l'option paysage. Pour savoir si les largeurs sont bonnes, utiliser la commande Affichage/Aperçu des sauts de page. Dès que le calendrier est au point, enregistrez-le à nouveau . Ne pas lancer l'impression tout de suite, mais attendre d'avoir fait les modifications des paragraphes 3.1 et 3.2 plus loin...
L'exemple que nous avons tapé montre déjà quelques règles de programmation et de syntaxe que nous devrons respecter. Certaines règles sont obligatoires pour que la macro fonctionne, d'autres sont facultatives mais fortement recommandées. Parmi ces dernières, on peut citer :
la présence de commentaires. Il faut toujours indiquer le nom de l'auteur de la macro, si possible la date de sa création et l'usage qu'on peut en faire. l'indentation. Il s'agit d'un procédé qui consiste à écrire en retrait un groupe d'instructions de même niveau. L'indentation permet de mieux visualiser la structure d'un programme. Utilisez la touche de tabulation plutôt que la barre d'espacement. la décomposition de la tâche principale en sous-tâches spécialisées. Cette méthode permet de tester le programme par morceaux.Dim AnnéeCette instruction permet de déclarer la variable globale Année. Lorsqu'une même variable doit être utilisée dans plusieurs procédures, il est obligatoire de la déclarer en tête de programme. Faute de déclaration globale, chaque procédure utilisant la variable Année considérerait celle-ci comme une variable locale indépendante.Sub Calendrier()C'est la procédure principale du programme. Elle appelle successivement 5 procédures décrites plus loin dans le programme. C'est celà la décomposition en sous-tâches.Sub SaisirAnnée()C'est une procédure très courte qui fait appel à une boîte de dialogue standard portant le titre "Calendrier" et la question : "Taper l'année :".Sub RéglerLargeurDesColonnes()Dans cette procédure, il faut sans doute modifier les valeurs affectées aux largeurs en tenant compte de l'environnement Macintosh (encore une fois la macro a été réalisée sur un PC). Comme l'année se compose de 12 mois on utilise une structure Itérative (boucle) de type For ... Next. Pour chacune des valeurs entières de c (de 1 à 12) la valeur 3*c-2 correspond aux colonnes contenant le nom du jour, la valeur 3*c-1 correspond aux colonnes contenant le n° du jour et la valeur 3*c correspond aux colonnes libres. L'objet Columns() peut effectuer plusieurs opérations (appelées Méthodes) et a plusieurs propriétés parmi lesquelles :
ColumnWidth (permet de préciser la largeur d'une colonne) Font (permet de préciser la police de caractères pour la colonne) Count (donne le nombre de colonnes de la sélection)
Lorsqu'un objet doit effectuer une méthode, il faut indiquer l'objet, puis un point, puis la méthode.Sub AfficherTitre()Cette procédure affiche le titre : Année nnnn dans les cellules A1 (cellule(1,1)) et S1 (cellule(1,19)). Pour obtenir le titre complet Année 2002 (par exemple), on "ajoute" à la chaîne Année, la variable Année (telle qu'elle a été saisie dans la procédure SaisirAnnée). Pour coller deux chaînes de caractères l'une à la suite de l'autre, il faut utiliser l'opérateur de concaténation &. Dans cette instruction, la variable Année est considérée comme une chaîne de caractères. Une structure très intéressante est utilisée ici pour simplifier l'écriture : With ... End With. On aurait pu écrire directement :
Selection.HorizontalAlignment = xlHAlignCenterAcrossSelection
Selection.VerticalAlignment = xlVAlignCenter
Selection.Font.Name = Arial
Selection.Font.Size = 20
Selection.Font.Bold = True
Selection.BorderAround Weight:=xlThick
Selection.Interior.ColorIndex = 4
Mais à chaque fois, il faut répéter le mot " selection "...Sub AfficherNomsMois()On retrouve dans cette procédure la fonction Format. Cette fonction très puissante, permet de convertir, entre autres, des chaînes dates dans un format particulier. Ici, il s'agit d'obtenir le nom du mois en toutes lettres (mmmm) donc la chaîne "1/1" devient "01/janvier". Il est alors possible d'extraire (fonction Mid) de cette chaîne, les caractères à partir du 4è (1ère lettre du mois). Le fait de préciser 10 caractères à extraire permet d'appliquer la fonction à tous les mois de l'année car aucun nom de mois ne dépasse 10 caractères.
Sub AfficherJours()Nous retrouvons la fonction Format pour extraire ensuite la première lettre du nom du jour. La fonction la plus intéressante ici est la fonction IsDate. Cette fonction permet de savoir si la chaîne transmise en paramètre peut être comprise comme une date (en tenant compte, même, des années bissextiles). Grâce à cette fonction, on peut remplir de façon automatique tous les mois en tenant compte du nombre de jours de chaque mois.
3. Modifications du programme3.1. Mise en évidence des week ends.Le cycle le plus important dans un calendrier est la semaine. Il est intéressant de bien visualiser les semaines. La façon la plus simple consiste à mettre en évidence les samedis et les dimanches. Il suffit de modifier légèrement la procédure AfficherJours en rajoutant, après la ligne :Cells(2 + j,3 * m-1)=jle texte suivant :
If (Cells(2 + j, 3 * m - 2) = "s") Or (Cells(2 + j, 3 * m - 2) = "d") Then
Range(Cells(2 + j, 3 * m - 2), Cells(2 + j, 3 * m)).Select
Selection.Interior.ColorIndex = 3
End If3.2. Affichage des fêtes mobiles (calendrier liturgique catholique romain)L'une des difficultés majeures en matière de calendrier concerne le calcul de la date de Pâques. Celle-ci est fixée le premier dimanche qui suit la première pleine lune du printemps. Le calcul est très compliqué car il doit tenir compte à la fois du calendrier grégorien (basé sur la course de la terre autour du soleil), du cycle lunaire (la lunaison moyenne est de 29,530588 jours) et de la date de l'équinoxe du printemps.
Parmi les méthodes de calcul de la date de Pâques, nous allons utiliser l'algorithme qui a été découvert en 1876 et diffusé par l'astronome Jean Meeus :
Soit A l'année grégorienne (postérieure donc à 1582)
On calcule successivement les nombres suivants :
n : reste de la division de A par 19 (cycle de Méton),
c : quotient entier de la division de A par 100,
u : reste de la division de A par 100,
s : quotient entier de la division de c par 4,
t : reste de la division de c par 4,
p : quotient entier de la division de (c+8) par 25,
q : quotient entier de la division de (c-p+1) par 3,
e : reste de la division de (19n+ c - s - q + 15) par 30,
b : quotient entier de la division de u par 4,
d : reste de la division de u par 4 ,
l : reste de la division de (32 + 2t +2b - e - d) par 7,
h : quotient entier de la division de (n + 11e + 22 l) par 451,
m : quotient entier de la division de (e + l - 17h + 114) par 31,
j : reste de la division de (e + l - 17h + 114) par 31 augmenté de 1.
Lorsqu'on connaît la date de Pâques, on peut facilement en déduire les autres fêtes religieuses liées à Pâques selon le tableau suivant :
Cendres -46 Mercredi Carême (1er dimanche de) -42 Dimanche Triduum Pascal -3 Jeudi -2 Vendredi -1 Samedi Pâques 0 Dimanche Ascension +39 Jeudi Pentecôte +49 Dimanche Trinité +56 Dimanche Fête-Dieu +63 Dimanche Sacré-Coeur +68 Vendredi
Pour traduire tous ces calculs, voici la procédure à ajouter en fin de programme :
Sub AfficherFêtesMobiles()
n = Année Mod 19
c = Année \ 100 'taper Alt + / pour obtenir la barre \
u = Année Mod 100
s = c \ 4
t = c Mod 4
p = (c + 8) \ 25
q = (c - p + 1) \ 3
e = (19 * n + c - s - q + 15) Mod 30
b = u \ 4
d = u Mod 4
l = (32 + 2 * t + 2 * b - e - d) Mod 7
h = (n + 11 * e + 22 * l) \ 451
k = e + l - 17 * h + 114
m = k \ 31
j = k Mod 31 + 1
Cells(2 + j, 3 * m) = "Pâques"
ch = Format(j & "/" & m & "/" & Année, "0")
m = Month(ch - 46)
j = Day(ch - 46)
Cells(2 + j, 3 * m) = "Cendres"
m = Month(ch + 39)
j = Day(ch + 39)
Cells(2 + j, 3 * m) = "Ascension"
m = Month(ch + 49)
j = Day(ch + 49)
Cells(2 + j, 3 * m) = "Pentecôte"
m = Month(ch + 56)
j = Day(ch + 56)
Cells(2 + j, 3 * m) = "Trinité"
m = Month(ch + 63)
j = Day(ch + 63)
Cells(2 + j, 3 * m) = "Fête-Dieu"
m = Month(ch + 68)
j = Day(ch + 68)
Cells(2 + j, 3 * m) = "Sacré-Coeur"
End Sub
Il suffit alors de modifier le programme principal comme ceci :
Sub Calendrier() 'programme principal
SaisirAnnée
RéglerLargeurDesColonnes
AfficherTitre
AfficherNomsMois
AfficherJours
AfficherFêtesMobiles
End Sub3.3. Découpage de l'année en 4 trimestresReprendre le programme précédent et le modifier de façon que le calendrier sorte sur 4 pages à raison d'une page par trimestre.
Enregistrer ce nouveau programme sous le nom Calendrier 2.3.4. Impression sur une seule page.Reprendre le programme et le modifier de façon que le calendrier complet sorte sur une seule page. Il faudra sans doute revoir la disposition des mois sur la page ...
3.5. Un seul mois choisi par l'utilisateurCe programme devra demander à l'utilisateur de choisir non seulement une année mais aussi un mois. L'ordinateur devra afficher seulement le mlois choisi. On pourra l'enregistrer sous le nom Calendrier 3
4. Ajout d'une commande de menuIl est possible d'ajouter la nouvelle commande dans le menu outil. Il faut procéder de la façon suivante :
- Choisir la commande Outil/Macro
- Choisir la macro Calendrier et cliquer sur le bouton Options...On obtient alors la fenêtre permettant de préciser ces options :