XII. Création du menu : affichage et choix dans le menu▲
Le résultat du premier test de l'écran n'était pas impressionnant mais nous a permis de valider le fonctionnement de l'interface d'écran clScreen
Il faut maintenant lui ajouter de l'affichage et répondre aux commandes de l'utilisateur pour faire un choix dans le menu.
Le code qui suit s'écrit dans le module clScreenMenu.
XII-A. Minuterie▲
N'oublions pas de mettre en place la minuterie !
Dans la procédure ClScreen_ScreenWait, ajoutez l'appel à la méthode Wait de l'objet clGdiplus.
Pour un menu, 10 images par seconde suffisent.
Cette méthode Wait n'est pas bloquante. DoEvents est déclenché dès que nécessaire pour traiter la file de message de l'application et permettre à l'utilisateur d'interagir.
'------------------------------------------------------------------------
' Minuterie d'attente
'------------------------------------------------------------------------
Private Function ClScreen_ScreenWait() As Boolean
' Attente de 1000 / 10 = 100 ms pour affichage de 10 images/s
oGdi.Wait 100
End FunctionMaintenant nous pouvons tester en affichant le UserForm FormGame.
Il ne s'affiche qu'un UserForm vide.
XII-B. Affichage du menu▲
Pour pouvoir dessiner, il faut créer avec gdi+ une image en mémoire.
La création de l'image se fait avec la fonction CreateBitmapForControl de l'objet clGdiplus de l'écran.
L'image créée est de la même taille (en pixels) que le contrôle image Img que nous avions créé sur le formulaire FormGame.
Nous créons cette image à l'initialisation de l'écran de menu dans l'événement Initialize.
With oGdi
' Nouveau bitmap pour dessiner
.CreateBitmapForControl FormGame
End WithEnsuite il faut créer le contenu statique du menu, c'est-à-dire le fond (uni) et le texte des options.
Ce contenu est dessiné une seule fois à l'initialisation de l'écran, puis sauvegardé pour pouvoir être restauré à la demande.
En effet la mise à jour de l'écran dans la fonction UpdateScreen devra :
- recharger le contenu statique du menu ;
- dessiner le contenu dynamique du menu : encadrement de l'entrée sélectionnée, autres animations si nécessaire…
Dans l'événement Initialize nous allons :
- Remplir le fond de gris avec la fonction Clear.
- Écrire le nom du jeu en haut de l'image avec la fonction DrawText.
- Écrire texte de chacune des options avec la fonction DrawText.
Commençons par les deux premières étapes.
' Dessin du contenu statique
With oGdi
' Nouveau bitmap pour dessiner
.CreateBitmapForControl FormGame
' Rempli l'image de gris
.Clear RGB(150, 150, 150)
' Ecrit le nom du jeu en haut
.DrawText "PacMan en VBA", 35, "Arial", 0, 10, _
.ImageWidth, 10 + 50, 1, 0, vbBlue, , vbYellow
End WithLe code ci dessus rempli l'image de noir puis affiche le texte « Pacman en VBA » en haut et en bleu sur fond jaune.
Pour tester l'affichage, il faut gérer la fonction ClScreen_DisplayScreen.
Utilisons la fonction Repaint de clGdiplus pour dessiner l'image dans le contrôle du formulaire.
'------------------------------------------------------------------------
' Affichage de l'écran
'------------------------------------------------------------------------
Private Function ClScreen_DisplayScreen() As Boolean
' Dessine l'image sur le formulaire
oGdi.Repaint FormGame.Img
End FunctionAffichez le formulaire avec F5 ou dans le menu Exécution => Exécuter Sub/Userform.
On obtient notre première image.

Ajoutons l'affichage des options :
Pour éviter d'écrire plusieurs fois le même code, on crée une petite procédure d'affichage d'une option.
En paramètre de cette procédure : le numéro de l'option et son texte.
'------------------------------------------------------------------------
' Affichage de l'option numéro pNum avec le texte pText
'------------------------------------------------------------------------
Private Sub DisplayOption(pNum As Long, pText As String)
' Position verticale de la première option
Const cPos As Long = 140
With oGdi
' Dessine un rectangle de fond en jaune pâle
.DrawRectangle 150, cPos + (pNum - 1) * 60, 600, cPos + (pNum - 1) * 60 + 50, _
RGB(255, 255, 200), , , , , "menu" & pNum
' Dessine le texte de l'option en bleu
.DrawText pText, 50, "Arial", 150, cPos + (pNum - 1) * 60, _
600, cPos + (pNum - 1) * 60 + 50, , , vbBlue
End With
End SubLe dessin d'une option se fait en deux étapes :
- Dessin d'un rectangle de fond.
- Dessin du texte.
Il faut ajuster les paramètres de position en pixels pour centrer les options.
On pense également à ajouter une région correspondant au rectangle et ayant pour identifiant « menu1 », « menu2 »…
La fonction DrawRectangle permet d'ajout cette région (paramètre pRegion).
Cette région nous servira ensuite à déterminer la région survolée par la souris.
On appelle ensuite cette fonction dans Class_Initialize pour chaque option.
A la fin du dessin du contenu statique, on le sauvegarde en mémoire comme prévu (pour pouvoir restaurer le contenu statique dans la fonction ClScreen_UpdateScreen).
[...]
' Affichage des options
DisplayOption 1, "Commencer le jeu"
DisplayOption 2, "Options"
DisplayOption 3, "Scores"
DisplayOption 4, "Crédits"
DisplayOption 5, "Quitter"
' Sauvegarde l'image en mémoire
.ImageKeep
End WithAffichez le formulaire pour voir le résultat.

XII-C. Encadrement de l'entrée de menu sélectionnée▲
Pour l'instant on n'a pas encore travaillé sur la gestion des commandes.
On ne connait pas les touches définies par l'utilisateur, nous le verrons lors de la création de l'écran des options.
Nous allons dans un premier temps gérer les choix d'option de menu à la souris.
Lors du survol ou du click sur l'image, un événement est envoyé au contrôle du formulaire.
Pour récupérer cet événement, il nous faut dans notre module clScreenMenu un objet image qui recevra les événéments.
On déclare donc une variable de type Image, avec le mot-clé WithEvents qui permet de recevoir les événéments.
' Contrôle image pour événements
Private WithEvents oImg As MSForms.imageIl faut également initialiser l'objet à la création de l'écran.
[...]
Private Sub Class_Initialize()
' Affectation de l'image pour événements
Set oImg = FormGame.Img
[...]Pour générer le code événément correspondant à un survol de l'image, sélectionnez dans la liste déroulante en haut à gauche l'objet oImg puis dans la liste déroulante à droite sélectionnez MouseMove.
Lors du survol de l'image, la procédure oImg_MouseMove sera exécutée.
Dans cette procédure, nous allons lire (avec RegionGetXY) la région située sous la souris, puis l'affecter à une variable.
Nous pourrons ensuite encadrer cette région dans la fonction ClScreen_UpdateScreen.
On commence par déclarer la variable en en-tête de module :
' Nom de l'option sélectionnée
Private gOption As StringEt ensuite on modifie cette variable au survol de la souris.
'------------------------------------------------------------------------
' Sur déplacement de la souris
'------------------------------------------------------------------------
Private Sub oImg_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
Dim lRegion As String
With oGdi
' Région aux coordonnées X et Y
' Les valeurs de X et Y étant des coordonnées prises sur le contrôle,
' on passe ce contrôle en cinquième paramètre
lRegion = .RegionGetXY(X, Y, , , oImg)
If lRegion <> "" Then
gOption = lRegion
End If
End With
End SubEt enfin dans la fonction ClScreen_UpdateScreen, on restaure le contenu statique et on encadre l'option sélectionnée.
'------------------------------------------------------------------------
' Mise à jour de l'écran
'------------------------------------------------------------------------
Private Function ClScreen_UpdateScreen() As Boolean
With oGdi
' Recharge l'image de la mémoire
.ImageReset
' Encadre en rouge l'entrée de menu sélectionnée
.RegionFrame gOption, vbRed, 4
End With
End FunctionSi on affiche le formulaire, l'option de menu survolée s'encadre en rouge.
Mais on a oublié de sélectionner une option par défaut à l'initialisation de l'écran.
'------------------------------------------------------------------------
' Initialisation de l'écran
'------------------------------------------------------------------------
Private Sub Class_Initialize()
' Option sélectionnée par défaut
gOption = "menu1"
[...]Deux petits soucis à ce stade de la programmation du menu :
- Si on clique sur le formulaire, l'image ne change plus ensuite.
- L'affichage « clignote » et ça fait mal aux yeux.
Pour le premier problème, on peut forcer le formulaire à se redessiner avec un appel à la méthode Repaint du formulaire.
Pour le second problème, on peut augmenter le paramètre DrawBuffer du formulaire jusqu'à ce que les clignotements disparaissent (valeur maxi = 1048576).
Sinon une autre solution plus simple qui règle les deux problèmes : utilisez la méthode RepaintNoFormRepaint.
Cette méthode dessine l'image directement sur l'écran et évite ainsi tout problème d'affichage.
'------------------------------------------------------------------------
' Affichage de l'écran
'------------------------------------------------------------------------
Private Function ClScreen_DisplayScreen() As Boolean
' Dessine l'image sur le formulaire
oGdi.RepaintNoFormRepaint FormGame.Img
End FunctionXII-D. Sélection d'une option de menu▲
Toujours à la souris, on va choisir l'option de menu désirée en cliquant sur l'image.
Créez le code événementiel sur souris appuyée MouseDown.
'------------------------------------------------------------------------
' Sur click de la souris
'------------------------------------------------------------------------
Private Sub oImg_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
Call MenuSelect
End SubOn garde en tête qu'on souhaitera plus tard gérer le choix des options au clavier, donc on appelle une fonction MenuSelect qui pourra ensuite servir au clavier.
En fonction du contenu de gOption, on défini le nom de l'écran suivant et on demande le changement d'écran en donnant la valeur Vrai à gChangeScreen.
'------------------------------------------------------------------------
' Sélection dans le menu
'------------------------------------------------------------------------
Private Sub MenuSelect()
Select Case gOption
Case "menu1"
gNextScreen = "game"
gChangeScreen = True
Case "menu2"
gNextScreen = "options"
gChangeScreen = True
Case "menu3"
gNextScreen = "scores"
gChangeScreen = True
Case "menu4"
gNextScreen = "credits"
gChangeScreen = True
Case "menu5"
gNextScreen = "quit"
gChangeScreen = True
End Select
End SubSi vous testez le click sur une option de menu, le formulaire se ferme quelque soit l'option choisie.
C'est normal car nous allons ensuite gérer l'enchaînement des écrans dans GameChangeScreen du module clGame au fur et à mesure de leur création.


