Accueil
Rechercher:
sur developpez.com sur les forums
Forums | Tutoriels | F.A.Q's | Participez | Hébergement | Contacts
Club Emploi Blogs   TV   Dév. Web PHP XML Python Autres 2D-3D-Jeux Sécurité Windows Linux PC Mac
Accueil Conception Java DotNET Visual Basic  C  C++ Delphi Eclipse MS-Office SQL & SGBD Oracle  4D  Business Intelligence
FORUM OFFICE FAQs OFFICE TUTORIELS OFFICE LIVRES OFFICE SOURCES VBA ACCESS

Suppression, mises à jour, impression
des données d'un planning - Partie 2

Date de publication : 30/06/08

Par Jean BALLAT (Espace perso de jeannot45)
 

Cet article continue la progression de la gestion de planning (partie 1)
On y retrouvera la description des manipulations complémentaires à la gestion de nos données (suppression, mises à jour diverses, notification (envoi de mail), impression et double affichage des données.
Il a été coécrit avec Morgan Billy (Dolphy35) pour la partie Notification

I. INTRODUCTION
II. LE CAHIER DES CHARGES
II-A. Contenu du Cahier des Charges
II-B. Présentation des modifications
III. LE DOUBLE AFFICHAGE
III-A. Présentation
III-B. Le Code VBA associé
IV. LA MANIPULATION DES DONNEES
IV-A. Présentation
IV-B. Les contrôles dans le formulaire
IV-C. Les Boutons du Formulaire
IV-C-1. Supprimer (2)
IV-C-2. Salle (3)
IV-C-3. Date (4)
IV-C-4. Formateur (5)
V. IMPRIMER LES DONNEES
V-A. Présentation
V-B. Principe du Planning
V-C. Le sous-état SE_DetailFormation
V-D. Le sous-état SE_Planning
VI. LA NOTIFICATION
VI-A. Présentation
VI-A-1. Le Formulaire
VI-A-2. Fonctionnement du formulaire
VI-A-3. Structure du formulaire
VI-A-3-a. Description des contrôles
VI-A-3-b. Les propriétés des contrôles
VI-A-3-b-i. La zone de liste déroulante : lstSemaine
VI-A-3-b-ii. Zones de Texte : txtDu et txtAu
VI-A-3-b-iii. Zone de liste : lsFormateur
VI-B. Le Code VBA dans le formulaire
VII. CONCLUSION
VIII. TELECHARGEMENT
IX. REMERCIEMENTS


I. INTRODUCTION

Nous avions abordé lors de la partie 1, la génération du planning et la création de tous les formulaires nécessaires à la mise en place de celui-ci.
Dans cette seconde phase, nous allons manipuler nos données, c'est à dire les mettre à jour, les supprimer, les imprimer.
Comme dans la partie précédente, nous devrons bien sûr nous conformer aux exigences du Cahier des Charges. Cet article se décomposera en plusieurs étapes :
          - Le Cahier des Charges.
          - Le Double affichage (Formateurs/Salles).
          - La Manipulation des données.
          - L'Impression.
          - La Notification (envoi de mail).
On retrouvera la base exemple GestionPlanningV2 dans la Section "Téléchargement"


II. LE CAHIER DES CHARGES


II-A. Contenu du Cahier des Charges

Le double affichage :
Afin de rendre l'application plus conviviale, il sera possible d'afficher soit le planning des salles, soit le planning des formateurs.
Lorsque l'affichage sera du type "Formateur", une sécurité sera prévue en cas de clic sur une case du planning, empêchant tout utilisateur d'intervenir sur celui-ci.
Lorsque l'affichage sera de type "Salles", les cases du planning seront sensibles au clic et permettront alors de réserver (voir Gestion planning partie 1) ou de modifier une session.
La manipulation des données :
On entendra par manipulation des données :
          - Supprimer une formation.
          - Changer de formateur.
          - Changer de salle de formation.
          - Changer la date de la formation.
L'impression :
Celle-ci imprimera la partie graphique du planning et le détail des formations. Elle dépendra du type d'affichage.
          - Affichage Formateurs : Impression lancée en cliquant sur le nom du formateur.
          - Affichage Salles : Impression globale de la période affichée. Impression lancée à partir du bouton "Imprimer".
La notification :
On pourra sélectionner une période libre ou une semaine particulière et envoyer un mail aux formateurs disposant d'une adresse mail.
Le mail s'affichera afin de donner la possibilité d'ajouter un texte particulier.


II-B. Présentation des modifications


Chaque nouveauté a été matérialisée par un numéro sur l'image.
          1) Simulation des boutons "Bascule" avec l'animation décrite dans la gestion de planning (partie 1).
          2) Modification des données en cliquant sur une des cases occupées du planning.(Type d'affichage : Salles)
          3) Impression globale du planning des salles.
          4) La notification auprès des formateurs disposant d'une adresse mail.


III. LE DOUBLE AFFICHAGE


III-A. Présentation


Par le jeu de boutons "Bascule" personnalisés, on affiche soit le planning des formateurs soit le planning des salles.
On remarquera en mode "Création" sur le formulaire F_Planning, l'ajout de zones texte ("txtCode1"..."txtCode10") qui recevront soit le CodeFormateur, soit le CodeSalleFormation.
La récupération de cette information sera importante pour l'impression du planning du formateur.

info On aurait pu utiliser cette méthode dans la version 1 du planning pour récupérer également le nom de la salle de formation sélectionnée.

III-B. Le Code VBA associé

Il nous faut donc savoir quel bouton a été cliqué par l'utilisateur. Pour cela, j'ai déclaré une variable boolAffichePlanningSalle de portée "Public" et de type booléen. Par défaut, à l'ouverture du formulaire F_Planning, cette variable est positionnée sur "True".
En cliquant sur btnPlanningFormateurS et btnPlanningSalleS on affectera à celle-ci soit la valeur False soit la valeur True.
Voici le code associé au bouton btnPlanningSalleS sur l'évènement "sur souris relâchée":

Private Sub btnPlanningSalleS_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
    ' Désactive le bouton btnPlanningSalle
    Call BasculerBouton("btnPlanningFormateurC", "btnPlanningFormateurR")
    
    ' initialisation des variables
    boolAffichePlanningSalle = True
    lngRecordDepart = 0
    lngCouleurfond = 8454016
    lngCodeFormateur = 0
    intDefilementSalle = 0
    boolEOF = False

    ' Mise en place du planning
    RecuperationEntetesLignes
    GenerationPlanningSalles
End Sub
warning On remarquera l'appel à deux routines :
          - "RecuperationEntetesLignes" qui affiche soit les salles soit les formateurs.
          - "GenerationPlanningSalles" qui est la routine déjà présentée dans la partie 1
Voici le code associé au bouton btnPlanningFormateurS sur l'évènement "sur souris relâchée":

Private Sub btnPlanningFormateurS_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
    ' Désactive le bouton btnPlanningSalle
    Call BasculerBouton("btnPlanningSalleC", "btnPlanningSalleR")
    
    ' Initialisation des variables
    boolAffichePlanningSalle = False
    lngRecordDepart = 0
    lngCouleurfond = 8454016
    intDefilementSalle = 0
    boolEOF = False

    ' Mise en place du planning
    RecuperationEntetesLignes
    GenerationPlanningFormateurs
End Sub
warning On remarquera l'appel à deux routines :
          - "RecuperationEntetesLignes" qui affiche soit les salles soit les formateurs.
          - "GenerationPlanningFormateurs". J'ai préféré pour plus de clarté, réécrire la routine plutôt que de combiner les
           instructions dans la routine "GenerationPlanningSalles"
L'objet de cette routine est triple :
          - Récupérer les infos pour renseigner les étiquettes sur le côté gauche du planning.
          - Récupérer les codes Formateurs pour renseigner les contrôles invisibles dans le formulaire (Ceux-ci seront nécessaires pour l'impression du planning du formateur).
          - Créer la chaîne de critères utilisée dans l'extraction des données du planning. Voyons cette routine.

Sub RecuperationEntetesLignes()
	' Test du type d'affichage sélectionné
    If boolAffichePlanningSalle = True Then
        ' Réinitialisation des variables
        intCompteur = 1
        strSallesConcernees = ""
        
        ' Récupération du jeu d'enregistrements
        Set rsSalles = CurrentDb.OpenRecordset(cstSalles)
        ' Relecture du jeu de rsSalles pour créer la chaîne qui permettra l'extraction des données
		' correspondantes dans rsPlanning
        With rsSalles
            ' Retour au début du jeu d'enregistrement
            .MoveFirst
            ' Saute au premier enregistrement concerné
            ' Rappel : lngRecordDepart permet de repositionner le pointeur suivant le nombre de clics sur les 
            ' boutons de défilement vers le haut ou vers le bas
            .Move lngRecordDepart
            ' Boucle jusqu'à la fin du jeu d'enregistrements
            Do While Not .EOF
                Me.Controls("lblNomSalle" & intCompteur).Caption = .Fields(1)
                Me.Controls("txtCode" & intCompteur) = .Fields(0)
                ' Génération de la chaîne de critères qui sera utilisée avec l'opérateur IN
                strSallesConcernees = strSallesConcernees & "," & Chr(34) & .Fields(1) & Chr(34)
                intCompteur = intCompteur + 1
                ' Valeur limite pour sortir de la boucle
                If intCompteur > 10 Then
                    Exit Do
                Else
                    .MoveNext
                End If
            Loop
            ' Initialisation de la variable de fin de fichier
            If .EOF Then
                boolEOF = True
            End If
        End With
        
        ' enlève la virgule
        strSallesConcernees = Right(strSallesConcernees, Len(strSallesConcernees) - 1)
    Else
        ' Réinitialisation des variables
        intCompteur = 1
        strFormateursConcernes = ""
        
        ' Récupération du jeu d'enregistrements
        Set rsFormateurs = CurrentDb.OpenRecordset(cstFormateurs)
        ' Relecture du jeu de rsFormateurs pour créer la chaîne qui permettra 
		'l'extraction des données correspondantes dans rsPlanning
        With rsFormateurs
            ' Retour au début du jeu d'enregistrement
            .MoveFirst
            ' Saute au premier enregistrement concerné
            ' Rappel : lngRecordDepart permet de repositionner le pointeur suivant le nombre de clics sur les 
            ' boutons de défilement vers le haut ou vers le bas
            .Move lngRecordDepart
            ' Boucle jusqu'à la fin du jeu d'enregistrements
            For intCompteur = 1 To 10
                If .EOF Then
	            	' Initialisation de la variable de fin de fichier
                    boolEOF = True
                    Me.Controls("lblNomSalle" & intCompteur).Caption = " "
                    Me.Controls("txtCode" & intCompteur) = 0
                Else
                    Me.Controls("lblNomSalle" & intCompteur).Caption = .Fields(1)
                    Me.Controls("txtCode" & intCompteur) = .Fields(0)
	                ' Génération de la chaîne de critères qui sera utilisée avec l'opérateur IN
	                strFormateursConcernes = strFormateursConcernes & "," & .Fields(0)
                    .MoveNext
	            End If
            Next
        End With
        
        ' enlève la virgule
        strFormateursConcernes = Right(strFormateursConcernes, Len(strFormateursConcernes) - 1)
    End If
End Sub
warning On remarque que dans la boucle, on renseigne les champs "lblNomSalle" avec les noms des salles ou des formateurs et "txtCode" avec le CodeFormateur ou le CodeSalleFormation. Le codeFormateur servira lors de l'impression du planning du formateur.
Rien d'autre de particulier dans cette procédure, si ce n'est que le test de la variable boolAffichePlanningSalle dirige tout.

IV. LA MANIPULATION DES DONNEES


IV-A. Présentation

La manipulation des données n'est accessible qu'à partir du mode d'affichage "Salles".
Ainsi en cliquant sur une plage colorée, l'utilisateur se verra avertir par une boite de dialogue que la zone est déjà occupée et que s'il le souhaite, il pourra intervenir sur la session en cours.

./images/PopBasculeAffichage.jpg Cependant, si l'utilisateur clique sur une zone du planning en mode "Formateurs", une boite de dialogue proposera de basculer en mode "Salles" afin de pouvoir faire des modifications ou une réservation.
Ci-dessous le code VBA associé.

Sub Reservation()
    ' teste le type d'affichage
    If boolAffichePlanningSalle = False Then
        intReponse = MsgBox("La réservation ou la modification n'est possible qu'en mode affichage ""Planning Salles""" & vbCrLf & _
                            "Souhaitez vous basculer dans ce mode d'affichage", vbQuestion + vbYesNo, cstDVP)
        ' Test de la réponse de l'utilisateur
		If intReponse = vbYes Then
			' Active le bouton "Salles" au lieu du bouton "Formateurs"
            Call BasculerBouton("btnPlanningFormateurC", "btnPlanningFormateurR")
            If btnPlanningSalleS.Visible = True Then
                Call BasculerBouton("btnPlanningSalleS", "btnPlanningSalleC")
            Else
                Call BasculerBouton("btnPlanningSalleR", "btnPlanningSalleC")
            End If
            ' Réinitialisation de la variable booléenne
            boolAffichePlanningSalle = True
            ' Régénération du planning
            RecuperationEntetesLignes
            GenerationPlanningSalles
        End If
    Else
        ' Récupère le nom et le  de code de la salle cliquée
        RecuperationSalle
        ' Vérifie si la date sélectionnée n'est pas un WeekEnd et si la salle n'est pas déjà occupée
        ControleDispoSalle
        ' Redessine le Planning
        If boolReservationPossible = True Then
            GenerationPlanningSalles
        End If
    End If
End Sub
L'affichage est donc repositionné en mode "Salles". Un clic sur une plage blanche génère alors la création d'une nouvelle réservation.
C'est en cliquant sur une des cases réservées d'une salle que le process de modification se met en route. Ce clic entraîne l'affichage du formulaire ci dessous.

Ce formulaire se décompose en deux parties :
          - à gauche : les commandes.
          - dans l'ardoise, les infos disponibles.

Par infos disponibles, j'entends les infos affichées en fonction du bouton choisi :
          - bouton "Salle" : Liste les salles disponibles pour la période réservée de la formation.
          - bouton "Date" : Affiche un calendrier afin de choisir le début de la nouvelle période.
          - bouton "Formateur" : Liste les formateurs compétents et disponibles pour la période de la formation.

Lors de l'ouverture du formulaire, une procédure est lancée afin de reconnaître la formation concernée par la modification.

Private Sub Form_Open(Cancel As Integer)
    Dim rsFormationConcernee As DAO.Recordset
    Dim strSqlFormationConcernee As String
    
    
    Set frmActif = Me
    
    ' Charge les images
    btnFermerR.Picture = CurrentProject.Path & "\image\btnFermerR.jpg"
    btnFermerS.Picture = CurrentProject.Path & "\image\btnFermerS.jpg"
    btnFermerC.Picture = CurrentProject.Path & "\image\btnFermerC.jpg"
    btnSupprimerR.Picture = CurrentProject.Path & "\image\btnSupprimerR.jpg"
    btnSupprimerS.Picture = CurrentProject.Path & "\image\btnSupprimerS.jpg"
    btnSupprimerC.Picture = CurrentProject.Path & "\image\btnSupprimerC.jpg"
    btnModifSalleR.Picture = CurrentProject.Path & "\image\btnModifSalleR.jpg"
    btnModifSalleS.Picture = CurrentProject.Path & "\image\btnModifSalleS.jpg"
    btnModifSalleC.Picture = CurrentProject.Path & "\image\btnModifSalleC.jpg"
    btnModifDateR.Picture = CurrentProject.Path & "\image\btnModifDateR.jpg"
    btnModifDateS.Picture = CurrentProject.Path & "\image\btnModifDateS.jpg"
    btnModifDateC.Picture = CurrentProject.Path & "\image\btnModifDateC.jpg"
    btnModifFormateurR.Picture = CurrentProject.Path & "\image\btnModifFormateurR.jpg"
    btnModifFormateurS.Picture = CurrentProject.Path & "\image\btnModifFormateurS.jpg"
    btnModifFormateurC.Picture = CurrentProject.Path & "\image\btnModifFormateurC.jpg"
    
    
    ' récupération des informations de la formation
    strSqlFormationConcernee = "SELECT T_Stages.CodeStage, T_Stages.DateStageDebut, T_Catalogue.DureeStage, " _
                                            & "T_NiveauFormation.LibelleNiveau, T_Catalogue.IntituleStage, " _
                                            & "[NomFormateur] & "" "" & [PrenomFormateur] AS Formateur, T_Produits.CodeProduit, " _
                                            & "T_NiveauFormation.CodeNiveau " _
                                            & "FROM T_NiveauFormation " _
                                            & "INNER JOIN (T_Produits " _
                                            & "INNER JOIN (T_Catalogue " _
                                            & "INNER JOIN (T_Formateur " _
                                            & "INNER JOIN (T_SalleFormation " _
                                            & "INNER JOIN T_Stages " _
                                            & "ON T_SalleFormation.CodeSalleFormation = T_Stages.CodeSalleFormation) " _
                                            & "ON T_Formateur.CodeFormateur = T_Stages.CodeFormateur) " _
                                            & "ON T_Catalogue.CodeCatalogue = T_Stages.CodeCatalogue) " _
                                            & "ON T_Produits.CodeProduit = T_Catalogue.CodeProduit) " _
                                            & "ON T_NiveauFormation.CodeNiveau = T_Catalogue.CodeNiveau " _
                                            & "WHERE T_Stages.CodeStage = " & lngCodeStage
                                            
    ' Inititalisation du jeu d'enregistrements
	Set rsFormationConcernee = CurrentDb.OpenRecordset(strSqlFormationConcernee)
    
    With rsFormationConcernee
        ' récupération de la durée de la formation
        bytDureeFormation = .Fields(2)
        ' Récupération du produit concerné
        lngCodeProduit = .Fields(6)
        ' Récupération du Niveau de formation
        lngNiveau = .Fields(7)
        ' préparation du message affiché dans l'ardoise
        lblMessage.Caption = "Formation  : " & lngCodeStage & vbCrLf _
                                        & "Intitule : " & .Fields(4) & vbCrLf _
                                        & "Durée : " & IIf(bytDureeFormation = 1, bytDureeFormation _
										& " jour", bytDureeFormation & " jours") & vbCrLf _
                                        & "Début le : " & .Fields(1) & vbCrLf _
                                        & "Formateur : " & .Fields(5)
                                        
    varDateDebutFormation = .Fields(1)
    varDateFinFormation = DateAdd("d", bytDureeFormation - 1, varDateDebutFormation)
    End With
End Sub
Etant donné que les boutons "Salle", "Date", "Formateur" sont encadrés, il faut également envisager une procédure pour l'animation des boutons. Celle-ci est affectée à l'évènement "sur souris déplacée" du contrôle "objEncadrementBoutons". On remarquera que cette procédure fait appel à la procédure évènementielle "sur souris déplacée" de la zone Détail.

Private Sub objEncadrementBoutons_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
    ' appel de la routine permettant de gérer l'animation des boutons
    Call Détail_MouseMove(Button, Shift, X, Y)
End Sub

Private Sub Détail_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
    ' Réinitialisation des images
    btnFermerR.Visible = True
    btnFermerS.Visible = False
    btnFermerC.Visible = False
    btnSupprimerR.Visible = True
    btnSupprimerS.Visible = False
    btnSupprimerC.Visible = False
    btnModifSalleR.Visible = True
    btnModifSalleS.Visible = False
    btnModifSalleC.Visible = False
    btnModifDateR.Visible = True
    btnModifDateS.Visible = False
    btnModifDateC.Visible = False
    btnModifFormateurR.Visible = True
    btnModifFormateurS.Visible = False
    btnModifFormateurC.Visible = False
End Sub

IV-B. Les contrôles dans le formulaire

Hormis les boutons donc l'explication sur l'animation peut-être consultée dans la partie 1 de l'article, ce formulaire contient dans l'ardoise, 3 autres contrôles superposés (1).
          - Une étiquette (lblMessage) qui affiche les infos sur la formation en cours de modification.
          - Un contrôle calendrier (objCalendrier) qui permettra de sélectionner une nouvelle date (4).
          - Une zone de liste (lstElementDispo) qui permettra d'afficher soit les salles (3) disponibles soit les formateurs (5) compétents et disponibles.

warning Les numéros entre parenthèses indiquent le bouton utilisé (cf image du formulaire)

IV-C. Les Boutons du Formulaire


IV-C-1. Supprimer (2)

Le rôle de ce bouton est de supprimer la formation sélectionnée. Lors de la suppression de la formation, tous les enregistrements attachés de la table T_Planning seront également supprimés.
(propriété de l'intégrité référentielle : Effacer en cascade les enregistrements correspondants).

Private Sub btnSupprimerS_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
    ' Déclaration variable locale
    Dim strDeleteStage As String
    
    ' Initialisation de la syntaxe SQL nécessaire à la suppression
    strDeleteStage = "DELETE CodeStage FROM T_Stages WHERE CodeStage = " & lngCodeStage

    ' annule l'affichage des messages système
    DoCmd.SetWarnings False
    ' interrogation de l'utilisateur
    intReponse = MsgBox("Vous allez supprimer définitivement une formation !" _
                        & vbCrLf & "Souhaitez-vous continuer ?", vbQuestion + vbYesNo, cstDVP)
                                    
    ' Traitement de la réponse de l'utilisateur
    ' Confirmation de la suppression
    If intReponse = vbYes Then
        ' Exécute la requete de suppression
        DoCmd.RunSQL strDeleteStage
    Else
        ' Annule la suppression des enregistrements
        MsgBox "La demande de suppression de la formation a été annulée !", vbInformation, cstDVP
    End If
    
    ' Réactivation des messages système
    DoCmd.SetWarnings True
    
    Set frmActif = Forms("F_Planning").Form
    
    ' Fermeture du formulaire
    DoCmd.Close
    
    ' Redessine le planning
    GenerationPlanningSalles
End Sub

IV-C-2. Salle (3)

Le changement de salle nous amène à proposer à l'utilisateur une nouvelle salle à la condition qu'elle soit disponible pour la période demandée.
La procédure affiche alors toutes les salles disponibles pour la période de la formation concernée par la modification.
Pour faire une modification de salle, deux procédures seront nécessaires. Une première pour récupérer les salles disponibles qui se lance dès que je relâche le bouton et une seconde qui relance le planning après avoir choisi une salle dans la liste (sur l'évènement "Après MAJ" de la liste lstElementDispo). Ci dessous le code de la procédure du bouton btnModifSalleS sur l'évènement "sur souris relâchée".

Private Sub btnModifSalleS_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
    Dim strSqlSallesReservees As String, strSallesOccupees As String
    
    ' Préparation de la récupération des codes salles occupées
    strSqlSallesReservees = "SELECT T_Stages.CodeStage, T_SalleFormation.CodeSalleFormation, T_Stages.DateStageDebut " _
                                        & "FROM T_SalleFormation INNER JOIN T_Stages " _
                                        & "ON T_SalleFormation.CodeSalleFormation = T_Stages.CodeSalleFormation " _
                                        & "WHERE T_Stages.DateStageDebut Between #" & Format(varDateDebutFormation, "mm/dd/yy") _
                                        & "# And #" & Format(varDateFinFormation, "mm/dd/yy") & "#"
    
    ' Récupération du jeu d'enregistrements
    Set rsSallesReservees = CurrentDb.OpenRecordset(strSqlSallesReservees)
    
    ' Création de la chaîne des salles occupées (qui seront exclues de l'extraction)
    With rsSallesReservees
        Do While Not .EOF
            strSallesOccupees = strSallesOccupees & "," & .Fields(1)
            .MoveNext
        Loop
    End With
                  
    ' Suppression de la virgule en fin de chaine
    strSallesOccupees = Right(strSallesOccupees, Len(strSallesOccupees) - 1)
    
    ' initialisation de la variable qui sera la source de la zone de liste
    strSqlSallesReservees = "SELECT * FROM T_SalleFormation WHERE CodeSalleFormation NOT IN (" & strSallesOccupees & ")"
    
    ' Alimentation de la liste lstElementDispo
    With lstElementDispo
        .RowSourceType = "Table/Query"
        .RowSource = strSqlSallesReservees
    End With
    
    ' Changement de l'intitulé de l'ardoise
    lblFormationModif1.Caption = "Choisir une Salle"
    lblFormationModif2.Caption = "Choisir une Salle"
    
    ' Masque le message de la formation concernée et le calendrier pour afficher la liste des salles disponibles
    lblMessage.Visible = False
    objCalendrier.Visible = False
    lstElementDispo.Visible = True
    
    ' Permet d'utiliser le même objet pour deux sources différentes. (Salles ou Formateurs)
    boolModifFormateur = False

End Sub
Voici le code associé à l'évènement "Après MAJ" de la liste lstElementDispo :

Private Sub lstElementDispo_AfterUpdate()
    Dim strElementMAJ As String
    
    ' Désactivation des messages systéme
    DoCmd.SetWarnings False
    
        ' test sur le type d'info à mettre à jour
                ' (boolModifFormateur = False -> Modif Salles)
                ' (boolModifFormateur = True -> Modif Formateur)
        If boolModifFormateur = False Then
            ' Mise à jour du CodeSalleFormation
            strElementMAJ = "CodeSalleFormation"
        Else
            ' Mise à jour du CodeFormateur
            strElementMAJ = "CodeFormateur"
        End If
    
        ' Préparation de la requete MAJ
        strSQLMajStage = "UPDATE T_Stages SET " & strElementMAJ & " = " & lstElementDispo & _
                                   " WHERE CodeStage = " & lngCodeStage
                                   
        DoCmd.RunSQL strSQLMajStage
    
    ' réactivation des messages système
    DoCmd.SetWarnings True
    
    ' redessine le planning
    GenerationPlanningSalles
    ' Ferme le formulaire