Utiliser des images dans un Planning

Image non disponible

Souvent nous rencontrons sur le forum des questions concernant l'implantation d'images dans un formulaire de type continu.
On pourra trouver un premier tuto de Dolphy35 : Implantation d'images dans un formulaire continu.
Pour compléter cet article, je vous présente comment implanter, dans un planning, des images représentant des situations ou des activités. (Ne concerne que les versions Access 2007 et supérieures.)


Vos commentaires : 11 commentaires Donner une note à l'article (5)

Article lu   fois.

L'auteur

Profil ProSite personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Contexte

Cette petite application est une extraction d'une base plus globale qui gère le personnel et les chiffres d'une petite entreprise familiale. Les tables, utilisées ici, ne reprennent que les informations utiles à la génération du planning. Je n'aborderai pas la validation du planning qui avait pour but de modifier directement les données de la table T_TempsTravail qui contient les temps de travail des employés. Par contre, en lieu et place du bouton de validation du planning, j'ai ajouté dans le formulaire un bouton qui donnera la possibilité d'ajouter un salarié afin de voir comment la table T_PlanningPreparation est alimentée.

II. Les tables

Pour bien appréhender la base, je vais vous présenter les différentes tables qui entrent en jeu.

II-A. T_Employes

Reprend les informations basiques du salarié.

Nom du Champ Type Description
Matricule NuméroAuto Clé Primaire
NomEmploye Texte Reprend le patronyme de l'employé
PrenomEmploye Texte Reprend le prénom de l'employé

Pour les débutants : on pourra remarquer que dans les noms de champs, je n'utilise ni accent, ni espace.

II-B. T_Activite

Reprend les informations des différents types d'activités ou de situations pouvant être affectées à l'employé dans l'entreprise.

Nom du Champ Type de Données Description
CodeActivite NuméroAuto Clé Primaire
LibelActivite Texte Intitulé de l'activité ou de la situation
ImageActivite Texte Contient le chemin des images liées à l'activité ou à la situation d'un employé

II-C. T_Contrats

Reprend les informations relatives au contrat du salarié. Cette table a été très simplifiée par rapport à l'application originale.

Nom du Champ Type de Données Description
CodeContrat NuméroAuto Clé Primaire
Matricule Numérique En relation avec la table T_Employes
TypeContrat Texte Indique s'il s'agit d'un CDI, CDD, Extra, Apprenti
DebutContrat Date Date du Début du Contrat
FinContrat Date Date de Fin de Contrat
DebutAmContractuel Numérique Heure de début de travail service du Midi (Théorique)
FinAmContractuel Numérique Heure de fin de travail service du Midi (Théorique)
DebutPmContractuel Numérique Heure de début de travail service du soir (Théorique)
FinPmContractuel Numérique Heure de fin de travail service du soir (Théorique)

Afin de faciliter la saisie, des valeurs par défaut seront implantées :
     - DebutAmContractuel = 10.00 ;
     - FinAmContractuel = 14.30 ;
     - DebutPmContractuel = 18.30 ;
     - FinPmContractuel = 22.00 ;
     - CodeActivite = 1 (Travail).

II-D. T_PlanningPreparation

C'est la table qui reprend toute l'activité du salarié.

Nom du Champ Type de Données Description
CodeContrat Numérique Est en relation avec la table des contrats
MoisPlanning Numérique Contient le quantième du mois. Il y aura autant d'enregistrements dans la table que de mois correspondant à la durée du contrat
AnneePlanning Numérique Contient l'année
Activite1 Numérique Contient le code d'activité du salarié (1 = Travail (par défaut)) pour le 1er jour du mois
....    
Activite31 Numérique Contient le code d'activité du salarié (1 = Travail (par défaut))

Il y a 31 champs "Activité". Chaque champ représente un jour du mois. On considère que tous les mois ont 31 jours. Le traitement en arrière-plan ne fera apparaître, dans le planning, que les jours correspondant au mois en cours.

Ne pas oublier que cette table ne sert que pour la préparation des plannings et que les données seront ensuite stockées dans la table T_TempsTravail.

II-E. T_TempsTravail

Je vous présente cette table par rapport à la modélisation de l'application. En effet, la table T_PlanningPréparation, de par sa structure, ne répond pas aux règles de normalisation d'une base de données (cf : la suite des champs Activite1 à Activite31).
Cette table contient toutes les données de travail des employés. Elle est modifiée :
     1. lors de la validation du planning ;
     2. lors de la saisie des temps de travail des employés ;
     3. lors de la saisie d'une observation pour une date donnée et un salarié particulier.

Ces traitements ne seront pas abordés car ils débordent du sujet de ce tutoriel.

Nom du Champ Type de Données Description
CodeContrat Numérique Contient le Numéro de contrat du salarié
JourTravail Date/Heure Contient la date du jour de travail
CodeActivite Numérique Contient le Code de l'activité assurée par l'employé
HeureDebutAm Numérique Contient l'heure de début du service du midi (Format : Fixe)
HeureFinAm Numérique Contient l'heure de fin du service du midi (Format : Fixe)
HeureDebutPm Numérique Contient l'heure de début du service du soir (Format : Fixe)
HeureFinPm Numérique Contient l'heure de fin du service du soir (Format : Fixe)
Observation Texte Contient toute remarque afférente à la journée de travail du salarié

II-F. T_Mois

Petite table d'information permettant d'avoir les libellés des mois dans différentes situations (Liste déroulante, Impression ...).

Nom du Champ Type de Données Description
CodeMois Numérique Contient le Quantième du mois de l'année
LibelleMois Texte Continent le nom du mois

II-G. Le modèle relationnel

Image non disponible

On remarquera l'absence de relation entre T_Activite et T_PlanningPréparation. Celle-ci sera établie lors de la génération des requêtes pour afficher les images dans le planning.

III. Présentation du Planning

Image non disponible

Dans l'image ci-dessus, nous avons une vue d'ensemble du formulaire servant à la préparation du planning.
     1. Les différents boutons de gestion (navigation par semaine, nouvelle saisie, impression).
     2. Les étiquettes et les dates à mettre à jour pour chaque changement de semaine.
     3. La liste des situations ou activités liées à une image.

IV. Les différents formulaires

IV-A. Le choix du Planning

IV-A-1. Implantation de la liste et de la zone de texte

Image non disponible Petit formulaire simple permettant à l'utilisateur de sélectionner le mois sur lequel il souhaite intervenir :
     - soit pour la préparation ;
     - soit pour imprimer le planning.

Ce formulaire contient une liste déroulante basée sur la table T_Mois et une zone de texte pour y saisir l'année concernée.
Nous modifierons les propriétés Nom des deux objets :
     - pour la liste déroulante : cboMois ;
     - pour la zone de texte : txtAnneeConcernee.

IV-A-2. Implantation du bouton "Ouvrir Planning"

Image non disponible Avant d'implanter les boutons, désactivez l'assistant contrôle comme indiqué dans l'image ci-contre.
Cliquez sur l'outil Bouton puis cliquez sur le formulaire pour déposer l'objet.
Dans le volet des propriétés du bouton :
     - onglet Autres : changez le nom de l'objet (btnOuvrirPlanning) ;
     - onglet Format : saisissez la légende (Ouvrir le planning) ;
     - onglet Évènements : sur clic, choisissez Procédure évènementielle.

IV-A-3. Le code dans ce formulaire

Image non disponible Nous aurons besoin de passer des informations d'un formulaire à un autre (le mois et l'année du planning).
Pour faciliter le transit de celles-ci, nous allons utiliser des Variables Publiques. Il faut les déclarer dans un module spécial.
1. Ouvrez la fenêtre de l'éditeur VBA (Alt F11).
2. Cliquez sur l'outil Ajouter un module.
3. Dans le volet des propriétés, changez le nom du module en saisissant : Déclaration Globale.

Nous allons déclarer les deux variables nécessaires :

Variables pour la préparation du planning
Sélectionnez
' Récupèrera le mois choisi dans la liste déroulante : cboMois
Public p_intMoisPlanning As Integer
' Récupèrera l'année saisie dans la zone de texte : txtAnneeConcernee
Public p_intAnneePlanning As Integer

IV-B. Création du Formulaire du Planning

IV-B-1. Section Détail

Image non disponible

Cette première phase permettra de créer les différents objets du planning c'est-à-dire :
     - une zone de texte pour afficher le n° de contrat ;
     - une zone de texte pour afficher le nom du salarié ;
     - sept contrôles "Image" pour afficher les images des différentes situations ou activités ;
     - sept listes déroulantes qui afficheront les choix possibles issus de la table T_Activite.
Ces différents éléments seront alimentés par une requête affectée au formulaire :
     - soit à l'ouverture du formulaire ;
     - soit à l'utilisation des boutons de navigation.
C'est dans cet objectif que nous affecterons une Source contrôle à chaque objet dont le nom sera repris dans chaque requête.

IV-B-1-a. Les deux zones de texte

Image non disponible Pour ces deux contrôles, pas de difficultés particulières.
Dans un formulaire indépendant en mode création :
     1. Cliquez sur l'outil "ab" ;
     2. Placez vos contrôles ;
     3. Affichez les propriétés ;
     4. Dans l'onglet : Données, propriété : Source conctrôle, saisissez les intitulés suivants :
           - CodeContrat ;
           - idEmploye.

IV-B-1-b. Les contrôles "Image"

Image non disponible Pour cette série de sept contrôles, plusieurs propriétés seront à modifier.
Nous allons créer totalement un objet avec toutes ses propriétés et nous allons ensuite le recopier six fois.
     1. Cliquez sur l'outil : Cadre d'objet indépendant.
     2. Placez le contrôle sur le formulaire.

Image non disponible La fenêtre des Propriétés étant affichée, il nous faut maintenant modifier les propriétés suivantes (après avoir cliqué sur l'onglet Toutes) :
     - Nom : imgAct1 ;
     - Source contrôle : srcImage1 ;
     - Mode affichage : Echelle ;
     - Largeur : 2,152cm ;
     - Hauteur : 1,201cm.

Vous allez maintenant recopier ce contrôle six fois puis modifier les propriétés Nom et Source Contrôle des nouveaux objets en respectant bien l'ordre :
      - Nom : imgAct2, imgAct3, [...], imgAct7
      - Source contrôle : srcImage2, srcImage3, [...], srcImage7

IV-B-1-c. Les listes déroulantes

Image non disponible Comme précédemment, nous allons créer une liste déroulante et la recopier six fois.
Cliquez sur l'outil : Liste Déroulante :
      - Étape 1 : les données sont issues d'une table ;
      - Étape 2 : choisissez la table T_Activite ;
      - Étape 3 : sélectionnez les deux premiers champs ;
      - Étape 4 : comme bon vous semble, vous pouvez trier les données de la liste ;
      - Étape 5 : vous ajusterez la largeur de la colonne (même principe que dans Excel) ;
      - Étape 6 : vous pouvez laisser l'intitulé de l'étiquette par défaut, celle-ci sera supprimée.
Image non disponible Il nous faut maintenant modifier l'identité, la source et les dimensions de notre contrôle.
Affichez les propriétés de la liste déroulante et cliquez sur l'onglet : Toutes
      - Nom : cboActivite1 ;
      - Source contrôle : cboActivite1 ;
      - Largeur : 0,451cm ;
      - Hauteur : 0,423cm.

Après avoir supprimé l'étiquette, il nous suffit de recopier ce contrôle six fois puis de modifier les propriétés Nom et Source contrôle des nouveaux objets en respectant bien l'ordre :
      - Nom : cboActivite2, cboActivite3, [...], cboActivite7 ;
      - Source contrôle : cboActivite2, cboActivite3, [...], cboActivite7.

Positionnez les contrôles pour obtenir la disposition du modèle.

IV-B-1-d. Le code attaché aux listes déroulantes

Le code placé sur l'évènement Après MAJ concerne le statut de l'apprenti. En effet, celui-ci suit sa formation au CFA.
J'ai donc pensé qu'en affectant l'activité "CFA", il était intéressant d'agir sur l'ensemble de la semaine. La procédure permet donc à l'utilisateur du planning d'implanter l'activité automatiquement à partir de n'importe quel jour avec mise en place de la récupération le samedi et le dimanche qui suivent la semaine de formation.

Le principe est de rechercher la position du lundi par rapport à la position du jour de la semaine modifié.
Voici le code :

Recherche du jour concernant la modif
Sélectionnez
l_intJourModif = Weekday(l_dteDateModif)
        Select Case l_intJourModif
            ' Cas du Lundi
            Case Is = 2
                l_sngCompteurJourSem = 0
            ' Cas du Mardi
            Case Is = 3
                l_sngCompteurJourSem = -1
            ' Cas du Mercredi
            Case Is = 4
                l_sngCompteurJourSem = -2
            ' Cas du Jeudi
            Case Is = 5
                l_sngCompteurJourSem = -3
            ' Cas du Vendredi
            Case Is = 6
                l_sngCompteurJourSem = -4
            ' Cas du Samedi ou du Dimanche
            Case Else
            Me.ActiveControl = 1
            MsgBox "Impossibilité de placer des journées de CFA un Week-End." & vbCrLf & "Opération annulée", vbInformation, "Préparation du Planning - DVP"
            Exit Sub           
        End Select


Dans un second temps, par une boucle il faut réécrire les nouvelles valeurs dans l'enregistrement correspondant.
La boucle s'interrompt si la fin de mois est atteinte.
Voici le code :

Modification de l'enregistrement
Sélectionnez
' Récupération des données du planning de l'employé afin de modifier les CodeActivité sur toute la semaine
        strSqlPlanning = "SELECT * FROM T_PlanningPreparation WHERE CodeContrat = " & Me.CodeContrat & " AND MoisPlanning = " _
		& p_intMoisPlanning & " AND AnneePlanning = " & p_intAnneePlanning
        Set m_rsPlanning = CurrentDb.OpenRecordset(strSqlPlanning)
        With m_rsPlanning
            For l_intBoucleCfa = 0 To 6
            	' Contrôle de la fin de mois
                If intChampActiviteConcerne + (sngCompteurJourSem + intBoucleCfa) > m_intFinMois Then
                    Exit For
                Else
                .Edit
	                    If l_intBoucleCfa <= 4 Then
	                        ' Implantation du code CFA sur tous les jours du Lundi au Vendredi
	                        .Fields("Activite" & l_intChampActiviteConcerne + (l_sngCompteurJourSem + l_intBoucleCfa)) = 5
	                    Else
	                        ' Implantation du code ReposJournée pour les Samedi et Dimanche de la semaine
	                        .Fields("Activite" & l_intChampActiviteConcerne + (l_sngCompteurJourSem + l_intBoucleCfa)) = 4
	                    End If
	                .Update
                End If
            Next
        End With


Une procédure est affectée à l'ensemble des listes déroulantes du formulaire.

 
Sélectionnez
Private Sub cboActivite1_AfterUpdate()
    Call SauvegardeEnregistrement
End Sub


On remarquera dans cette procédure l'appel à la routine SauvegardeEnregistrement.

Sub SauvegardeEnregistrement()
Sélectionnez
' Déclaration des variables locales
' utilisables uniquement dans cette procédure
Dim l_rsContrat As DAO.Recordset
Dim l_intJourModif As Integer, l_intBoucleCfa As Integer, l_intChampActiviteConcerne As Integer
Dim l_strSqlContrat As String
Dim l_dteDateModif As Date
Dim l_sngCompteurJourSem As Single
 
    ' Sauvegarde de l'enregistrement modifé
    DoCmd.RunCommand acCmdSaveRecord
 
    ' Automatisation de la gestion de l'indicatif CFA
    If Me.ActiveControl = 5 Then
        ' Contrôle du type de Contrat du salarié
        l_strSqlContrat = "SELECT TypeContrat FROM T_Contrats WHERE CodeContrat = " & Me.CodeContrat
        Set l_rsContrat = CurrentDb.OpenRecordset(l_strSqlContrat)
 
        If l_rsContrat.Fields(0) <> "Apprentissage" Then
            'Repositionnement sur la valeur par défaut (travail)
            Me.ActiveControl = 1
            MsgBox "L'employé modifié n'est pas un apprenti !!!" & vbCrLf & "La modification du planning a été annulée.", vbExclamation, "Préparation du Planning - Forum DVP"
            Exit Sub
        End If
        ' Récupération de la date concernée
        l_dteDateModif = CDate(Me.Controls("lblJour" & Right(Me.ActiveControl.Name, 1)).Caption)
        l_intChampActiviteConcerne = Day(l_dteDateModif)
 
        ' Recherche du jour concernant la modif
        l_intJourModif = Weekday(l_dteDateModif)
        Select Case l_intJourModif
            ' Cas du Lundi
            Case Is = 2
                l_sngCompteurJourSem = 0
            ' Cas du Mardi
            Case Is = 3
                l_sngCompteurJourSem = -1
            ' Cas du Mercredi
            Case Is = 4
                l_sngCompteurJourSem = -2
            ' Cas du Jeudi
            Case Is = 5
                l_sngCompteurJourSem = -3
            ' Cas du Vendredi
            Case Is = 6
                l_sngCompteurJourSem = -4
            Case Else
            Me.ActiveControl = 1
            MsgBox "Impossibilité de placer des journées de CFA un Week-End." & vbCrLf & "Opération annulée", vbInformation, "Préparation du Planning - DVP"
            Exit Sub  
        End Select
        ' Récupération des données du planning de l'employé afin de modifier les CodeActivité sur toute la semaine
        strSqlPlanning = "SELECT * FROM T_PlanningPreparation WHERE CodeContrat = " & Me.CodeContrat & " AND MoisPlanning = " _
						 & p_intMoisPlanning & " AND AnneePlanning = " & p_intAnneePlanning
        Set m_rsPlanning = CurrentDb.OpenRecordset(strSqlPlanning)
        With m_rsPlanning
            For l_intBoucleCfa = 0 To 6
            	' Contrôle de la fin de mois
                If intChampActiviteConcerne + (sngCompteurJourSem + intBoucleCfa) > m_intFinMois Then
                    Exit For
                Else
	                .Edit
	                    If l_intBoucleCfa <= 4 Then
	                        ' Implantation du code CFA sur tous les jours du Lundi au Vendredi
	                        .Fields("Activite" & l_intChampActiviteConcerne + (l_sngCompteurJourSem + l_intBoucleCfa)) = 5
	                    Else
	                        ' Implantation du code ReposJournée pour les Samedi et Dimanche de la Semaine
	                        .Fields("Activite" & l_intChampActiviteConcerne + (l_sngCompteurJourSem + l_intBoucleCfa)) = 4
	                    End If
	                .Update
                End If
            Next
        End With
    End If
End Sub

IV-B-2. Section En-tête de Formulaire

Image non disponible

Durant cette phase, nous allons implanter les étiquettes affichant les dates et les jours de la semaine puis les différents boutons (Navigation, Ajout de salarié, Impression).

IV-B-2-a. Les étiquettes du planning

Image non disponible Pour afficher l'en-tête et le pied de formulaire :
     1. cliquez droit dans la section Détail ;
     2. cliquez sur la commande En-tête et Pied de Formulaire ;
     3. réduisez la section Pied de Formulaire qui ne sera pas utilisée.


Image non disponible Nous allons préparer les deux premières étiquettes puis comme précédemment faire une recopie des deux éléments :
     1. cliquez sur l'outil "Aa" (étiquette) ;
     2. cliquez dans la section En-tête de Formulaire ;
     3. saisissez un espace pour "valider" l'objet dessiné.


Image non disponible Nous allons maintenant modifier les propriétés de l'étiquette :
     1. cliquez sur l'onglet Toutes de la fenêtre des propriétés ;
     2. modifiez les deux propriétés suivantes :
          - Nom : lblJourSem1,
          - Largeur : 2,619cm.

Il nous suffit de recopier cette étiquette treize fois en renommant :
     - les six premières : lblJourSem2, lblJourSem3..., lblJourSem7 ;
     - les sept suivantes : lblJour1, lblJour2..., lblJour7.

Il nous reste à les disposer comme sur le modèle.

IV-B-2-b. Le Code du Formulaire

IV-B-2-b-i. Une petite fonction pour la requête

Notre formulaire étant indépendant, il nous faudra lui amener une source de données lors de l'ouverture afin que celui-ci affiche des informations.
Nous utiliserons pour cela un jeu de requêtes paramétrées.
Dans notre formulaire, le N° de contrat, l'identité du salarié concaténée, le mois et l'année du planning ainsi que deux informations, répétées sept fois, sont affichées :
     - une valeur dans la liste déroulante représentant le code de l'activité ou de la situation du salarié ;
     - une image associée à la valeur de la liste déroulante.
Ce qui nous donne l'image de la requête ci-dessous :

Image non disponible


Remarquez la répétition de la table T_Activite pour chaque champ Activite de la table T_PreparationPlanning.
Il nous faut maintenant associer l'image d'une activité à chaque CodeActivite de T_PreparationPlanning. Or, le champ ImageActivite contient une partie du chemin de stockage du fichier image (exemple : images\imgTravail.jpg).
L'accès complet à l'image étant tributaire de l'organisation des fichiers de chacun, il nous faudra écrire une petite fonction qui nous permettra de récupérer le chemin complet de l'image par rapport à son emplacement sur votre disque :
     1. ouvrez la fenêtre VBA (Alt F11) ;
     2. insérez un nouveau Module ;
     3. renommez ce module : Fonctions Globales ;
     4. saisissez ou copiez le code ci-dessous.

 
Sélectionnez
Public Function fncCheminImage(pRelativePath As String) As String
    'Concaténation du chemin de la base et de l'image
    fncCheminImage = CurrentProject.Path & "\" & pRelativePath
End Function
IV-B-2-b-ii. La structure de la requête

Cette requête, que nous avons dessinée précédemment, devra être évolutive puisqu'elle n'affichera que sept jours à la fois. Nous serons donc amené à la manipuler via le Code VBA.
Reprenons la requête précédente et ajoutons les champs nécessaires :
     - CodeContrat ;
     - IdSalarie représentant l'identité du salarié par concaténation des deux champs NomEmploye et PrenomEmploye ;
     - MoisPlanning ;
     - AnneePlanning ;
     - Activite1 ;
     - srcImage1 représentant le chemin de l'image (utilisation de la fonction personnalisée créée ci-dessus) ;
- Ces deux derniers champs seront répétés sept fois (avec les champs Activite2 à Activite7).
Nous obtenons l'image suivante :

Image non disponible

Cette requête devra alimenter notre formulaire dès son ouverture. Cliquez dans le volet des propriétés du formulaire sur l'onglet Évènements et recherchez l'évènement sur Ouverture puis choisissez Procédure évènementielle.
Comme nous devrons paramétrer notre requête, nous allons commencer par déclarer des variables de portée Module, ainsi elles seront reconnues de toutes les procédures du module attaché à notre formulaire.
     1. ouvrez la fenêtre de VBA (Alt F11).
1. Dans la zone de Déclarations, Access affiche la ligne Option Compare Database,
     2. saisissez : Option explicit. Cette option a pour but d'obliger la déclaration des variables avant utilisation. Le code en sera plus performant.

Voici les variables à déclarer :

Déclarations des variables de portée module
Sélectionnez
' Déclaration des variables de portée Module
' Ces variables ne sont utilisables que dans ce module
 
' Variable qui récupère les enregistrements sélectionnés
Dim m_rsPlanning As DAO.Recordset
' Variable qui contient la syntaxe SQL source du formulaire
Dim m_strSqlPrepaPlanning As String
' Variable contenant la partie de la syntaxe SQL contenant les critères de sélection
Dim m_strSqlWHERE As String
' Divers compteurs
Dim m_intCompteurSemaine As Integer, m_intCompteurJour As Integer
' Variable de gestion de la fin de mois
Dim m_boolFinMois As Boolean
IV-B-2-b-iii. Le code à l'ouverture du formulaire

Lors de l'ouverture de la fenêtre VBA, une procédure était déjà prête à être complétée. Access l'a préparée lorsque nous avons demandé une procédure évènementielle sur ouverture du formulaire.
Positionnez-vous avant l'instruction End Sub et saisissez votre code :

Private Sub Form_Open(Cancel As Integer)
Sélectionnez
' Variable pour gérer la boucle de création des étiquettes de planning
    Dim l_intCompteur As Integer
    ' Variable pour gérer les dates des étiquettes de planning
    Dim l_dteDatePlanning As Date
 
    ' initialisation des variables de portée Module
    m_intCompteurSemaine = 1
    m_intCompteurJour = 0
 
    ' Appel de la routine de création de la source du formulaire
    Call ChangementSourcePlanning
 
    ' Création des étiquettes calendrier
    For l_intCompteur = 1 To 7
        l_dteDatePlanning = CDate(Format(l_intCompteur, "00") & "/" & Format(p_intMoisPlanning, "00") & "/" & Format(p_intAnneePlanning, "00"))
        Me.Controls("lblJourSem" & l_intCompteur).Caption = Format(l_dteDatePlanning, "dddd")
        Me.Controls("lblJour" & l_intCompteur).Caption = Format(l_dteDatePlanning, "dd/mm/yyyy")
    Next
 
End Sub

Remarquez l'appel à la routine ChangementSourcePlanning. C'est dans cette procédure que nous sélectionnerons la syntaxe SQL qui servira de source à notre planning.
Quelques remarques sur le code :

La requete source
Sélectionnez
m_strSqlPrepaPlanning = 
"SELECT T_PlanningPreparation.CodeContrat, [PrenomEmploye] & ' ' & [NomEmploye] AS IdEmploye, " _
	& "T_PlanningPreparation.Activite" & 1 + m_intCompteurJour & " AS cboActivite1, T_PlanningPreparation.Activite" & 2 + m_intCompteurJour & " AS cboActivite2, " _
	& "T_PlanningPreparation.Activite" & 3 + m_intCompteurJour & " AS cboActivite3, T_PlanningPreparation.Activite" & 4 + m_intCompteurJour & " AS cboActivite4, " _
	& "T_PlanningPreparation.Activite" & 5 + m_intCompteurJour & " AS cboActivite5, T_PlanningPreparation.Activite" & 6 + m_intCompteurJour & " AS cboActivite6, " _
	& "T_PlanningPreparation.Activite" & 7 + m_intCompteurJour & " AS cboActivite7, T_PlanningPreparation.MoisPlanning, T_PlanningPreparation.AnneePlanning, " _
	& "fncCheminImage([T_Activite].[ImageActivite]) AS srcImage1, fncCheminImage([T_Activite_1].[ImageActivite]) AS srcImage2, " _
	& "fncCheminImage([T_Activite_2].[ImageActivite]) AS srcImage3, fncCheminImage([T_Activite_3].[ImageActivite]) AS srcImage4, " _
	& "fncCheminImage([T_Activite_4].[ImageActivite]) AS srcImage5, fncCheminImage([T_Activite_5].[ImageActivite]) AS srcImage6, " _
	& "fncCheminImage([T_Activite_6].[ImageActivite]) AS srcImage7 " _
	& "FROM T_Activite AS T_Activite_6 " _
	& "INNER JOIN (T_Activite AS T_Activite_5 " _
	& "INNER JOIN (T_Activite AS T_Activite_4 " _
	& "INNER JOIN (T_Activite AS T_Activite_3 " _
	& "INNER JOIN (T_Activite AS T_Activite_2 " _
	& "INNER JOIN (T_Activite AS T_Activite_1 " _
	& "INNER JOIN (T_Activite INNER JOIN ((T_PlanningPreparation INNER JOIN T_Contrats " _
	& "ON T_PlanningPreparation.CodeContrat = T_Contrats.CodeContrat) " _
	& "INNER JOIN T_Employes ON T_Contrats.Matricule = T_Employes.Matricule) " _
	& "ON T_Activite.CodeActivite = T_PlanningPreparation.Activite" & 1 + m_intCompteurJour & ") " _
	& "ON T_Activite_1.CodeActivite = T_PlanningPreparation.Activite" & 2 + m_intCompteurJour & ") " _
	& "ON T_Activite_2.CodeActivite = T_PlanningPreparation.Activite" & 3 + m_intCompteurJour & ") " _
	& "ON T_Activite_3.CodeActivite = T_PlanningPreparation.Activite" & 4 + m_intCompteurJour & ") " _
	& "ON T_Activite_4.CodeActivite = T_PlanningPreparation.Activite" & 5 + m_intCompteurJour & ") " _
	& "ON T_Activite_5.CodeActivite = T_PlanningPreparation.Activite" & 6 + m_intCompteurJour & ") " _
	& "ON T_Activite_6.CodeActivite = T_PlanningPreparation.Activite" & 7 + m_intCompteurJour

J'ai géré la modularité du planning en utilisant le compteur m_intCompteurJour :

exemple
Sélectionnez
"T_PlanningPreparation.Activite" & 1 + m_intCompteurJour & " AS cboActivite1

Dans la concaténation du nom et du prénom de l'employé, j'ai remplacé les "" par de simples quotes, cela facilite la gestion des "".

Concaténation du champ idEmploye
Sélectionnez
"...[PrenomEmploye] & ' ' & [NomEmploye] AS IdEmploye,..."

Il nous faut maintenant récupérer dans la clause WHERE les critères saisis dans le formulaire F_ChoixPlanning. Je rappelle qu'ils "transitent" par des variables publiques.

Clause WHERE
Sélectionnez
' Création de la clause WHERE
    m_strSqlWHERE = " WHERE MoisPlanning = " & p_intMoisPlanning & " AND AnneePlanning = " & p_intAnneePlanning _
                             & " ORDER BY T_Employes.NomEmploye, T_Employes.PrenomEmploye "

Pour terminer, il faut affecter notre nouvelle source à notre formulaire :

Affectation de la source
Sélectionnez
' Initialisation de la Source du formulaire
    Me.RecordSource = m_strSqlPrepaPlanning & m_strSqlWHERE

Dans le reste de la procédure, on retrouvera le même type de syntaxe pour la gestion des fins de mois.
Voici ci-dessous la procédure complète :

Procédure complète
Sélectionnez
Sub ChangementSourcePlanning(Optional intFinMois As Integer)
        ' Récupération de la syntaxe SQL pour les jours de la semaine
        If m_boolFinMois = False Then
            m_strSqlPrepaPlanning = "SELECT T_PlanningPreparation.CodeContrat, [PrenomEmploye] & ' ' & [NomEmploye] AS IdEmploye, " _
                & "T_PlanningPreparation.Activite" & 1 + m_intCompteurJour & " AS cboActivite1, T_PlanningPreparation.Activite" & 2 + m_intCompteurJour & " AS cboActivite2, " _
                & "T_PlanningPreparation.Activite" & 3 + m_intCompteurJour & " AS cboActivite3, T_PlanningPreparation.Activite" & 4 + m_intCompteurJour & " AS cboActivite4, " _
                & "T_PlanningPreparation.Activite" & 5 + m_intCompteurJour & " AS cboActivite5, T_PlanningPreparation.Activite" & 6 + m_intCompteurJour & " AS cboActivite6, " _
                & "T_PlanningPreparation.Activite" & 7 + m_intCompteurJour & " AS cboActivite7, T_PlanningPreparation.MoisPlanning, T_PlanningPreparation.AnneePlanning, " _
                & "fncCheminImage([T_Activite].[ImageActivite]) AS srcImage1, fncCheminImage([T_Activite_1].[ImageActivite]) AS srcImage2, " _
                & "fncCheminImage([T_Activite_2].[ImageActivite]) AS srcImage3, fncCheminImage([T_Activite_3].[ImageActivite]) AS srcImage4, " _
                & "fncCheminImage([T_Activite_4].[ImageActivite]) AS srcImage5, fncCheminImage([T_Activite_5].[ImageActivite]) AS srcImage6, " _
                & "fncCheminImage([T_Activite_6].[ImageActivite]) AS srcImage7 " _
                & "FROM T_Activite AS T_Activite_6 " _
                & "INNER JOIN (T_Activite AS T_Activite_5 " _
                & "INNER JOIN (T_Activite AS T_Activite_4 " _
                & "INNER JOIN (T_Activite AS T_Activite_3 " _
                & "INNER JOIN (T_Activite AS T_Activite_2 " _
                & "INNER JOIN (T_Activite AS T_Activite_1 " _
                & "INNER JOIN (T_Activite INNER JOIN ((T_PlanningPreparation INNER JOIN T_Contrats " _
                & "ON T_PlanningPreparation.CodeContrat = T_Contrats.CodeContrat) " _
                & "INNER JOIN T_Employes ON T_Contrats.Matricule = T_Employes.Matricule) " _
                & "ON T_Activite.CodeActivite = T_PlanningPreparation.Activite" & 1 + m_intCompteurJour & ") " _
                & "ON T_Activite_1.CodeActivite = T_PlanningPreparation.Activite" & 2 + m_intCompteurJour & ") " _
                & "ON T_Activite_2.CodeActivite = T_PlanningPreparation.Activite" & 3 + m_intCompteurJour & ") " _
                & "ON T_Activite_3.CodeActivite = T_PlanningPreparation.Activite" & 4 + m_intCompteurJour & ") " _
                & "ON T_Activite_4.CodeActivite = T_PlanningPreparation.Activite" & 5 + m_intCompteurJour & ") " _
                & "ON T_Activite_5.CodeActivite = T_PlanningPreparation.Activite" & 6 + m_intCompteurJour & ") " _
                & "ON T_Activite_6.CodeActivite = T_PlanningPreparation.Activite" & 7 + m_intCompteurJour
 
        Else
            Select Case intFinMois
                ' Récupération de la syntaxe SQL pour la fin de mois
                ' Année bissextile
                Case Is = 29
                    m_strSqlPrepaPlanning = "SELECT T_PlanningPreparation.CodeContrat, [PrenomEmploye] & ' ' & [NomEmploye] AS IdEmploye, " & _
                         "T_PlanningPreparation.Activite29 AS cboActivite1, T_PlanningPreparation.MoisPlanning, T_PlanningPreparation.AnneePlanning, " & _
                         "fncCheminImage([T_Activite].[ImageActivite]) AS srcImage1 " & _
                         "FROM T_Activite INNER JOIN (T_Employes INNER JOIN (T_PlanningPreparation INNER JOIN T_Contrats " & _
                         "ON T_PlanningPreparation.CodeContrat = T_Contrats.CodeContrat) ON T_Employes.Matricule = T_Contrats.Matricule) " & _
                         "ON T_Activite.CodeActivite = T_PlanningPreparation.Activite29 "
                ' Mois à 30 jours
                Case Is = 30
                    m_strSqlPrepaPlanning = "SELECT T_PlanningPreparation.CodeContrat, [PrenomEmploye] & ' ' & [NomEmploye] AS IdEmploye, " & _
                         "T_PlanningPreparation.Activite29 AS cboActivite1,T_PlanningPreparation.Activite30 AS cboActivite2, T_PlanningPreparation.MoisPlanning, T_PlanningPreparation.AnneePlanning, " & _
                         "fncCheminImage([T_Activite].[ImageActivite]) AS srcImage1, fncCheminImage([T_Activite1].[ImageActivite]) AS srcImage2 " & _
                         "FROM (T_Activite INNER JOIN (T_Employes " & _
                         "INNER JOIN (T_PlanningPreparation INNER JOIN T_Contrats " & _
                         "ON T_PlanningPreparation.CodeContrat = T_Contrats.CodeContrat) ON T_Employes.Matricule = T_Contrats.Matricule) " & _
                         "ON T_Activite.CodeActivite = T_PlanningPreparation.Activite29) INNER JOIN T_Activite AS T_Activite1 ON T_PlanningPreparation.Activite30 = T_Activite1.CodeActivite "
                ' Mois à 31 jours
                Case Is = 31
                    m_strSqlPrepaPlanning = "SELECT T_PlanningPreparation.CodeContrat, [PrenomEmploye] & ' ' & [NomEmploye] AS IdEmploye, " & _
                         "T_PlanningPreparation.Activite29 AS cboActivite1, T_PlanningPreparation.Activite30 AS cboActivite2, T_PlanningPreparation.Activite31 AS cboActivite3, " & _
                         "T_PlanningPreparation.MoisPlanning, T_PlanningPreparation.AnneePlanning, " & _
                         "fncCheminImage([T_Activite].[ImageActivite]) AS srcImage1, fncCheminImage([T_Activite1].[ImageActivite]) AS srcImage2, " & _
                         "fncCheminImage([T_Activite2].[ImageActivite]) AS srcImage3 " & _
                         "FROM T_Activite AS T_Activite2 " & _
                         "INNER JOIN (T_Activite AS T_Activite1 " & _
                         "INNER JOIN (T_Activite INNER JOIN ((T_PlanningPreparation INNER JOIN T_Contrats " & _
                         "ON T_PlanningPreparation.CodeContrat = T_Contrats.CodeContrat) INNER JOIN T_Employes " & _
                         "ON T_Contrats.Matricule = T_Employes.Matricule) " & _
                         "ON T_Activite.CodeActivite = T_PlanningPreparation.Activite29) " & _
                         "ON T_Activite1.CodeActivite = T_PlanningPreparation.Activite30) " & _
                         "ON T_Activite2.CodeActivite = T_PlanningPreparation.Activite31"
 
            End Select
        End If
 
    ' Création de la clause WHERE
    m_strSqlWHERE = " WHERE MoisPlanning = " & p_intMoisPlanning & " AND AnneePlanning = " & p_intAnneePlanning _
                             & " ORDER BY T_Employes.NomEmploye, T_Employes.PrenomEmploye "
 
    ' Initialisation de la Source du formulaire
    Me.RecordSource = m_strSqlPrepaPlanning & m_strSqlWHERE
End Sub

IV-B-2-c. Les boutons de commande

Image non disponible
IV-B-2-c-i. Le bouton "Semaine Précédente"

L'assistant étant inactif, cliquez sur l'outil Bouton et implantez celui-ci sur le formulaire.
Nous allons dans un premier temps modifier ses propriétés :
     - onglet Format :
Image : cliquez sur l'outil à droite de la propriété et allez rechercher une image représentant une flèche gauche.
     - onglet Données :
Activé : choisissez Non.
     - onglet Autres :
Nom : saisissez btnSemainePrecedente.
Texte info-bulle : tapez Semaine précédente.

Pour ajouter le code du bouton, cliquez dans l'onglet Évènements puis sur l'évènement sur clic, choisissez Procédure évènementielle.

Private Sub btnSemainePrecedente_Click()
Sélectionnez
' Variable locale de comptage de la boucle
    Dim l_intCompteur As Integer
 
    m_intCompteurSemaine = m_intCompteurSemaine - 1
 
    If m_intCompteurSemaine = 0 Then
        m_intCompteurSemaine = 1
    Else
        ' Récupération de la requête source
        Select Case m_intCompteurSemaine
            Case Is = 1
                m_intCompteurJour = 0
                ' Atteindre le bouton Semaine Suivante pour...
                DoCmd.GoToControl "btnSemaineSuivante"
                ' ... Désactivation du bouton Semaine Précedente.
               Me.btnSemainePrecedente.Enabled = False
            Case Is = 2
                m_intCompteurJour = 7
            Case Is = 3
                m_intCompteurJour = 14
                ' Réactivation du bouton Semaine Suivante si le mois à 28 jours
                Me.btnSemaineSuivante.Enabled = True
                m_boolFinMois = False
            Case Is = 4
                m_intCompteurJour = 21
                ' Réactivation du bouton Semaine Suivante si le mois à + de 28 jours
                Me.btnSemaineSuivante.Enabled = True
                m_boolFinMois = False
            Case Is = 5
                m_intCompteurJour = 28
        End Select
 
        ' Récupération de la source
        Call ChangementSourcePlanning
 
            ' Boucle de génération des différentes étiquettes de la zone En-tête de Formulaire
            For l_intCompteur = 1 To 7
                Me.Controls("lblJour" & l_intCompteur).Caption = Format(m_intCompteurJour + l_intCompteur, "00") & "/" & Format(p_intMoisPlanning, "00") & "/" & Format(p_intAnneePlanning, "00")
                Me.Controls("lblJourSem" & l_intCompteur).Caption = Format(CDate(Me.Controls("lblJour" & l_intCompteur).Caption), "dddd")
            Next
    End If
End Sub
IV-B-2-c-ii. Le bouton "Semaine Suivante"

Procédez comme ci-dessus pour implanter le nouveau bouton et modifiez les mêmes propriétés :
     - onglet Format :
Image : cliquez sur l'outil à droite de la propriété et allez rechercher une image représentant une flèche droite.
     - onglet Autres :
Nom : saisissez btnSemaineSuivante.
Texte info-bulle : tapez Semaine suivante.

Pour ajouter le code du bouton, cliquez dans l'onglet Évènements puis sur l'évènement sur clic, choisissez Procédure évènementielle.

Private Sub btnSemaineSuivante_Click()
Sélectionnez
' Variable pour calculer le quantième du jour
    Dim l_intCompteur As Integer
    ' Variable qui récupère le quantième correspondant à la fin de mois
    Dim l_intFinMois As Integer
 
        ' Compteur du page du planning (1semaine = 1 page)
        m_intCompteurSemaine = m_intCompteurSemaine + 1
        ' Récupération de la requête source
        Select Case m_intCompteurSemaine
            Case Is = 1
                m_intCompteurJour = 0
            Case Is = 2
                m_intCompteurJour = 7
                ' Réactivation du bouton semaine précédente (nous sommes en semaine 2)
                Me.btnSemainePrecedente.Enabled = True
            Case Is = 3
                m_intCompteurJour = 14
            Case Is = 4
                m_intCompteurJour = 21
                ' Cas du mois de février à 28 jours
                If l_intFinMois = 28 Then
                    ' Atteindre le bouton Semaine Précédente pour...
                    DoCmd.GoToControl "btnSemainePrecedente"
                    ' ... Désactivation du bouton Semaine Suivante.
                    Me.btnSemaineSuivante.Enabled = False
                End If
            Case Is = 5
                    ' Semaine 5 : Semaine de toutes les fins de mois  29 j, 30 j ou 31 j)
                    m_intCompteurJour = 28
                    ' Activation de la variable booléenne qui permettra de retrouver la structure Sql correspondant au nombre de jours du mois
                    m_boolFinMois = True
                    ' Atteindre le bouton Semaine Suivante pour...
                    DoCmd.GoToControl "btnSemainePrecedente"
                    ' ... Désactivation du bouton Semaine Suivante.
                    Me.btnSemaineSuivante.Enabled = False
        End Select
 
        ' Récupération de la source
       Call ChangementSourcePlanning(l_intFinMois)
 
          ' Boucle d'initialisation
          For l_intCompteur = 1 To 7
                ' Contrôle la fin de mois
                If m_intCompteurJour + l_intCompteur > l_intFinMois Then
                    ' Mise à Blanc des contrôles supérieurs à la date de fin de mois
                    Me.Controls("lblJour" & l_intCompteur).Caption = " "
                    Me.Controls("lblJourSem" & l_intCompteur).Caption = " "
                Else
                    ' Génération des étiquettes des dates du jour
                    Me.Controls("lblJour" & l_intCompteur).Caption = Format(m_intCompteurJour + l_intCompteur, "00") & "/" & Format(p_intMoisPlanning, "00") & "/" & Format(p_intAnneePlanning, "00")
                    Me.Controls("lblJourSem" & l_intCompteur).Caption = Format(CDate(Me.Controls("lblJour" & l_intCompteur).Caption), "dddd")
                End If
            Next
End Sub
IV-B-2-c-iii. Le bouton "Imprimer le Planning"

Implantez le bouton comme nous l'avons fait précédemment et modifiez les propriétés suivantes :
     - onglet Autres :
          - Nom : btnImprimerLePlanning.
     - onglet Format :
          - Image : recherchez une image évocatrice de l'impression.

Pour ajouter le code du bouton, cliquez dans l'onglet Évènements puis sur l'évènement sur clic, choisissez Procédure évènementielle.

 
Sélectionnez
Private Sub btnImprimerLePlanning_Click()
    DoCmd.OpenForm "F_ChoixEtendueImpression"
End Sub

Pour lire la partie concernant l'impression, cliquez ici : Détail de l'impression

IV-B-2-c-iv. Le bouton "Nouveau Salarié"

Bien que ne faisant pas partie de l'objet de l'article, j'ai voulu détailler ce chapitre pour montrer comment la table T_PlanningPreparation est alimentée.
Cela suppose donc la création d'un formulaire. Pour lire la partie concernant la création du formulaire, cliquez ici : Création du formulaire de saisie d'un nouveau salarié

IV-C-3. Les propriétés du formulaire F_PreparationPlanning

Image non disponible Nous allons maintenant modifier les propriétés de notre formulaire.
Affichez le volet des propriétés et cliquez sur l'onglet Format ;
     - Affichage par défaut : Formulaires continus ;
- (tous les enregistrements s'affichent les uns dessous des autres) ;
     - Autoriser le mode Formulaire : Oui ;
     - Autres modes d'affichage : mettre Non partout ;
- (évite un autre type d'affichage) ;
     - Auto centrer : Oui ;
- (place automatiquement notre formulaire au centre de notre écran) ;
     - Diviseur d'enregistrement : Non ;
- (empêche l'affichage d'une ligne entre chaque enregistrement) ;
     - Barre de défilement : Aucune ;
- (sauf si nous traitons beaucoup d'enregistrements, auquel cas on pourrait laisser l'option : Verticale) ;
     - Boîte contrôle : Non ;
     - Bouton Fermer : Non ;
- (Nous gérerons le bouton) ;
     - Boutons Min/Max : Non ;
- (la fenêtre ne pourra pas être réduite) ;

IV-C. Création d'un nouveau salarié

 

IV-C-1. Le formulaire de saisie

Image non disponible

Ce formulaire a été simplifié au strict minimum. Il contient :
     - une liste déroulante basée sur la table T_Employes ;
- celle-ci représente le champ Père du formulaire.
- J'en ai profité pour rappeler comment alimenter une liste déroulante (Voir la FAQ) ;
     - un sous-formulaire qui reprend l'essentiel du contrat.

IV-C-1-a. La liste déroulante et son code

Dans un formulaire indépendant en mode création (indépendant = rattaché à aucune source de données), implantez une liste déroulante en suivant les diverses étapes de la création :
     Étape 1 : la source est une table ou une requête ;
     Étape 2 : sélectionnez la table T_Employes ;
     Étape 3 : choisissez les premiers champs (Matricule, NomEmploye).
Étape 3 : Le prénom sera ajouté par concaténation lors de la modification de la requête source ;
     Étape 4 : positionnez un tri sur le NomEmploye ;
     Étape 5 : ne changez rien à la largeur de la colonne ;
     Étape 6 : saisissez l'étiquette : Choisir dans la liste.

Image non disponible Nous allons maintenant modifier les propriétés de la liste. Dans le volet des propriétés :
     - cliquez sur l'onglet Données
Contenu : Ouvrez la requête en cliquant sur l'outil à droite du volet ;
Contenu : Modifiez le champ NomEmploye en créant un champ calculé (idEmploye) ;
Contenu : Ajoutez une seconde fois le champ NomEmploye et placez-y le tri en désactivant l'option d'affichage ;
Contenu : Fermer la fenêtre du générateur de requête et validez.
     - cliquez sur l'onglet Format
Nbre Colonnes : 2 ;
Largeurs colonnes : 0cm, 5cm.
     - cliquez sur l'onglet Autres
Nom : cboEmploye.
     - cliquez onglet Évènements
Sur absence dans liste : Choisir procédure évènementielle.

En cliquant sur l'outil à droite de la procédure évènementielle, on entre dans l'environnement du code.
Au préalable quelques remarques sur le code :

Utilisation de la fonction Split(expression,séparateur) qui permet d'éclater la chaîne de caractères saisie dans un tableau :
     - L'argument "Expression" représente la chaîne à traiter ;
     - L'argument "Séparateur" représente le caractère séparant les éléments de la chaîne à éclater.

Utilisation de la fonction Split
Sélectionnez
' Eclatement de la chaîne saisie dans un tableau
    l_tabTrav = Split(NewData, " ")
 
    ' Récupération des données dans les variables
    l_strNom = l_tabTrav(1)
    l_strPrenom = l_tabTrav(0)

Exécution d'une requête Ajout pour implanter les valeurs dans la table source de la liste

 
Sélectionnez
' Génération et exécution de la chaine SQL pour ajouter les infos à la table
    l_strSqlEmploye = "INSERT INTO T_Employes ( NomEmploye, PrenomEmploye)" _
                      & " SELECT  '" & l_strNom & "','" & l_strPrenom & "' ;"
 
    With DoCmd
        ' Désactivation Message système
        .SetWarnings False
        ' Exécution de la requête Ajout
        .RunSQL l_strSqlEmploye
        ' Réactivation des messages système
        .SetWarnings True
    End With

Voici, ci-dessous, le code complet de la procédure :

Alimenter la liste avec une nouvelle valeur
Sélectionnez
Private Sub cboEmploye_NotInList(NewData As String, Response As Integer)
	Dim l_strSqlEmploye As String
    Dim l_strNom As String, l_strPrenom As String
    Dim l_tabTrav() As String
 
    ' Eclatement de la chaine saisie dans un tableau
    l_tabTrav = Split(NewData, " ")
 
    ' Récupération des données dans les variables
    l_strNom = l_tabTrav(1)
    l_strPrenom = l_tabTrav(0)
 
    ' Génération et exécution de la chaine SQL pour ajouter les infos à la table
    l_strSqlEmploye = "INSERT INTO T_Employes ( NomEmploye, PrenomEmploye)" _
                                  & " SELECT  '" & l_strNom & "','" & l_strPrenom & "' ;"
 
    With DoCmd
        ' Désactivation Message système
        .SetWarnings False
        ' Exécution de la requête Ajout
        .RunSQL l_strSqlEmploye
        ' Réactivation des messages système
        .SetWarnings True
    End With
 
    ' Mise à jour du contenu de la liste
    Response = acDataErrAdded
End Sub

IV-C-1-b. Le sous-formulaire

Image non disponible Créez un nouveau formulaire basé sur la table T_Contrats :
     1. affichez l'entête de formulaire ;
     2. placez les étiquettes dans la section Entête de formulaire ;
     3. placez les zones de texte dans la section Détail ;
     4. vérifiez vos alignements ;
     5. modifiez les propriétés du formulaire comme ci-dessous :


Onglet Format Onglet Données
Image non disponible Image non disponible

Pour en terminer avec le sous formulaire, il faut implanter une procédure sur les deux zones de texte DebutContrat et FinContrat. Ce code sera placé sur l'évènement "après mise à jour" du contrôle.
Son objectif : récupérer les valeurs du formulaire nécessaires à la création des enregistrements de T_PlanningPréparation

DebutContrat
Sélectionnez
Private Sub DebutContrat_AfterUpdate()
    p_dteDebutContrat = Me.DebutContrat
End Sub
FinContrat
Sélectionnez
Private Sub FinContrat_AfterUpdate()
    p_dteFinContrat = Me.FinContrat
    p_lngCodeContrat = Me.CodeContrat
    DoCmd.GoToControl "btnFermer"
End Sub

Je n'ai pas fait de contrôle de saisie pour vérifier la cohérence des dates, ce n'est pas l'objet du tuto.

IV-C-1-c. Implanter le sous-formulaire

Image non disponible Image non disponible

Ouvrez le formulaire principal de saisie des contrats puis cliquez en laissant appuyé sur le nom du sous-formulaire et glissez-le dans le formulaire à l'endroit souhaité.
Modifiez les propriétés Champ Père et Champ Fils comme ci-dessus.

IV-C-2. Le code de génération des enregistrements

Lors de la création d'un contrat, la table T_PlanningPreparation est alimentée d'un enregistrement par mois de contrat et la table T_TempsTravail est alimentée d'un enregistrement par jour de travail.
Le code s'exécute sur la fermeture du formulaire de saisie du contrat.

Dans un premier temps, on alimente la table T_PreparationPlanning :

Alimentation de T_PreparationPlanning
Sélectionnez
Private Sub btnFermer_Click()
    ' Déclaration des variables locales
    Dim l_rsPrepaPlanning As DAO.Recordset
    Dim l_strSqlPrepaPlanning As String
    Dim l_intCompteur As Integer
 
    ' Initialisation des variables de travail
    l_strSqlPrepaPlanning = "SELECT * FROM T_PlanningPreparation"
    Set l_rsPrepaPlanning = CurrentDb.OpenRecordset(l_strSqlPrepaPlanning)
 
    'Ajout des enregistrements pour les mois du contrat
    For l_intCompteur = Month(p_dteDebutContrat) To Month(p_dteFinContrat)
        With l_rsPrepaPlanning
            .AddNew
                .Fields!CodeContrat = p_lngCodeContrat
                .Fields!MoisPlanning = l_intCompteur
                ' Remarque : le planning est régénéré tous les ans,
                ' si un employé est embauché lors de la génération du premier planning,
                ' l'année planning correspond à l'année de la date d'embauche.
                .Fields!AnneePlanning = Year(p_dteDebutContrat)
            .Update
        End With
    Next

Dans un second temps, on alimente T_TempsTravail :

Alimentation de T_TempsTravail
Sélectionnez
' Initialisation des variables de travail
        l_strSqlPrepaPlanning = "SELECT * FROM  T_TempsTravail"
        Set l_rsPrepaPlanning = CurrentDb.OpenRecordset(l_strSqlPrepaPlanning)
 
        'Ajout des enregistrements pour les jours travaillés du contrat
        For l_intCompteur = p_dteDebutContrat To p_dteFinContrat
            With l_rsPrepaPlanning
                .AddNew
                    .Fields!CodeContrat = p_lngCodeContrat
                    .Fields!JourTravail = l_intCompteur
                .Update
            End With
        Next

Voici donc le code complet de la procédure évènementielle "sur Clic" du bouton de fermeture du formulaire :

Procédure complète
Sélectionnez
Private Sub btnFermer_Click()
    Dim l_rsPrepaPlanning As DAO.Recordset
    Dim l_strSqlPrepaPlanning As String
    Dim l_varCompteur As Variant
 
    If Me.cboEmploye > "" Then
        ' Alimentation de T_PreparationPlanning
        '-----------------------------------------------
        ' Initialisation des variables de travail
        l_strSqlPrepaPlanning = "SELECT * FROM T_PlanningPreparation"
        Set l_rsPrepaPlanning = CurrentDb.OpenRecordset(l_strSqlPrepaPlanning)
 
        'Ajout des enregistrements pour les mois du contrat
        For l_varCompteur = Month(p_dteDebutContrat) To Month(p_dteFinContrat)
            With l_rsPrepaPlanning
                .AddNew
                    .Fields!CodeContrat = p_lngCodeContrat
                    .Fields!MoisPlanning = l_varCompteur
                    ' Remarque : le planning est régénéré tous les ans,
                    ' si un employé est embauché lors de la génération du premier planning,
                    ' l'année planning correspond à l'année de la date d'embauche.
                    .Fields!AnneePlanning = Year(p_dteDebutContrat)
                .Update
            End With
        Next
 
        ' Alimentation de T_TempsTravail
        ' --------------------------------------
        ' Initialisation des variables de travail
        l_strSqlPrepaPlanning = "SELECT * FROM  T_TempsTravail"
        Set l_rsPrepaPlanning = CurrentDb.OpenRecordset(l_strSqlPrepaPlanning)
 
        'Ajout des enregistrements pour les jours travaillés du contrat
        For l_varCompteur = p_dteDebutContrat To p_dteFinContrat
            With l_rsPrepaPlanning
                .AddNew
                    .Fields!CodeContrat = p_lngCodeContrat
                    .Fields!jourtravail = l_varCompteur
                .Update
            End With
        Next
 
        ' Réactualisation du Planning
        Forms!F_PreparationPlanning.Requery
    End If
    DoCmd.Close acForm, "F_SaisieContrats"
End Sub

IV-D. L'impression

Image non disponible Image non disponible

L'impression est lancée à partir du bouton btnImprimerLePlanning. L'ouverture du formulaire ci-dessus à gauche permettra de choisir l'étendue de l'impression tandis que l'image de droite nous montre le résultat obtenu.
On remarquera que les intitulés des Week-End sont affichés en rouge.

IV-D-1. Le formulaire du choix de l'impression

IV-D-1-a. La liste déroulante

Image non disponible Dans un nouveau formulaire indépendant, implantez une liste déroulante et suivez les diverses étapes de l'assistant :
     Étape 1 : choisissez l'option "Je taperai les valeurs souhaitées" ;
     Étape 2 : choisissez le nombre de colonne : 2 ;
Étape 2 : saisissez les valeurs à afficher dans la liste :
          1ère Quinzaine,
          2ème Quinzaine,
          Le mois complet ;
     Étape 3 : saisissez l'étiquette à associer à la liste.

IV-D-1-b. Le bouton d'impression et son code

Il ne reste plus qu'à implanter un bouton qui lancera le processus d'impression.

 
Sélectionnez
Private Sub btnImprimerPlanning_Click()
 
    ' Selection de l'impression
    Select Case Me.cboChoixImprimer
        Case Is = 1
            ' Impression Quinzaine 1
            p_intCompteurImpressDeb = 1
            DoCmd.OpenReport "E_ImpressionPlanning", acViewNormal, , "MoisPlanning = " & p_intMoisPlanning & " AND AnneePlanning = " & p_intAnneePlanning
        Case Is = 2
            ' Impression Quinzaine 2
            p_intCompteurImpressDeb = 17
            DoCmd.OpenReport "E_ImpressionPlanning", acViewNormal, , "MoisPlanning = " & p_intMoisPlanning & " AND AnneePlanning = " & p_intAnneePlanning
        Case Else
            ' Impression Quinzaine 1
            p_intCompteurImpressDeb = 1
            DoCmd.OpenReport "E_ImpressionPlanning", acViewNormal, , "MoisPlanning = " & p_intMoisPlanning & " AND AnneePlanning = " & p_intAnneePlanning
            ' Impression Quinzaine 2
            p_intCompteurImpressDeb = 17
            DoCmd.OpenReport "E_ImpressionPlanning", acViewNormal, , "MoisPlanning = " & p_intMoisPlanning & " AND AnneePlanning = " & p_intAnneePlanning
    End Select
 
    ' Fermeture du formulaire de lancement
    DoCmd.Close acForm, "F_ChoixEtendueImpression"
End Sub

IV-D-2. Le Planning

IV-D-2-a. Le structure de l'état

Image non disponible
IV-D-2-a-i. La section En-tête d'état

Cette section contient une étiquette qui affichera le titre de l'état :
     1. cliquez sur l'outil Aa ;
     2. tapez un espace pour mettre un contenu à l'étiquette ;
     3. changez les propriétés :
          - Nom : lblTitre,
          - Largeur : 18.794cm.

On implantera également quinze étiquettes pour les jours de planning. Comme plus haut, on créera une étiquette que l'on recopiera quinze fois.
     1. cliquez sur l'outil Aa ;
     2. tapez Date1 pour mettre un contenu à l'étiquette ;
     3. changez les propriétés :
          - Nom : lblDate1,
          - Largeur : 1.492cm,
          - Hauteur : 0.503cm ;

Recopiez cette étiquette quinze fois en prenant soin de modifier la propriété Nom (onglet : Autres) comme ci-dessous :
lblDate2, lblDate3, [...], lblDate16.

IV-D-2-a-ii. La section Détail

Nous positionnerons dans cette section, une zone de texte et seize contrôles Image indépendants. Ceux-ci seront alimentés par le code.
Pour la zone de texte :
     1. cliquez sur l'outil ab puis cliquez dans la section Détail ;
     2. changez les propriétés :
          - Nom : Employe,
          - Source Contrôle : Employe,
          - Largeur : 3cm.
Pour les contrôle image, nous agirons comme ci-dessus en créant un contrôle et en le recopiant.
     1. cliquez sur l'outil : Cadre d'objet indépendant ;
     2. modifiez les propriétés :
          - Nom : img1,
          - Largeur : 1.492cm,
          - Hauteur : 0.804cm,
          - Mode d'affichage : Echelle.
Recopiez cette étiquette quinze fois en prenant soin de modifier la propriété Nom (onglet : Autres) comme ci-dessous :
img2, img3, [...], img16.

IV-D-2-b. Le code attaché à l'état

IV-D-2-b-i. À l'ouverture de l'état

Durant cette procédure, nous allons :

1. générer la source de l'état :

Source de l'état
Sélectionnez
' Déclaration de la variable
    Dim strSqlPrepaImpress As String
 
    ' Création de la requête source
    strSqlPrepaImpress = "SELECT [PrenomEmploye] & ' ' & [NomEmploye] AS Employe, T_PlanningPreparation.CodeContrat, T_Mois.LibelleMois, MoisPlanning, AnneePlanning, " _
        & "Activite1, Activite2, Activite3, Activite4, Activite5, Activite6, Activite7,  Activite8, Activite9, Activite10, Activite11, " _
		& "Activite12, Activite13, Activite14, Activite15, Activite16, " _
        & "Activite17, Activite18, Activite19, Activite20, Activite21, Activite22, Activite23, Activite24, Activite25, Activite26, " _
		& "Activite27 , Activite28, Activite29, Activite30, Activite31 " _
        & "FROM T_Employes INNER JOIN ((T_PlanningPreparation " _
        & "INNER JOIN T_Contrats ON T_PlanningPreparation.CodeContrat = T_Contrats.CodeContrat) " _
        & "INNER JOIN T_Mois ON T_PlanningPreparation.MoisPlanning = T_Mois.CodeMois) ON T_Employes.Matricule = T_Contrats.Matricule " _
        & "WHERE MoisPlanning = " & p_intMoisPlanning & " AND AnneePlanning = " & p_intAnneePlanning
 
    ' Affectation de la source
    Me.RecordSource = strSqlPrepaImpress

2. rechercher la fin de mois pour gérer les étiquettes vierges :

Récupération de la fin de Mois
Sélectionnez
' Recherche fin de mois
    If p_intMoisPlanning = 12 Then
        intFinMois = Day(DateSerial(p_intAnneePlanning + 1, p_intMoisPlanning + 1, 1) - 1)
    Else
        intFinMois = Day(DateSerial(p_intAnneePlanning, p_intMoisPlanning + 1, 1) - 1)
    End If

3. générer les étiquettes des dates de planning par rapport à la plage à imprimer :

Création des étiquettes du planning
Sélectionnez
'Récupération du Jeu d'enregistrements
    Set rsImpressPlanning = CurrentDb.OpenRecordset(strSqlPrepaImpress)
 
    ' Génération des étiquettes
    With rsImpressPlanning
        ' Génération du titre
        Me.lblTitre.Caption = "Planning de l'équipe pour " & .Fields(2) & " " & .Fields(4)
        For intCompteur = 0 To 15
            ' Gestion de la fin de mois
            If intCompteur + p_intCompteurImpressDeb > intFinMois Then
                Me.ZoneEntêtePage.Controls("lblDate" & intCompteur + 1).Caption = ""
            Else
                ' Implantation de la date
                Me.ZoneEntêtePage.Controls("lblDate" & intCompteur + 1).Caption = Format(DateSerial(.Fields("AnneePlanning"), _
				.Fields("MoisPlanning"), intCompteur + p_intCompteurImpressDeb), "dddd dd")
                ' Modification de la couleur en fonction du jour de la semaine
                If Left(Me.ZoneEntêtePage.Controls("lblDate" & intCompteur + 1).Caption, 1) = "S" Or _
					Left(Me.ZoneEntêtePage.Controls("lblDate" & intCompteur + 1).Caption, 1) = "D" Then
                    Me.ZoneEntêtePage.Controls("lblDate" & intCompteur + 1).ForeColor = 255
                Else
                    Me.ZoneEntêtePage.Controls("lblDate" & intCompteur + 1).ForeColor = 0
                End If
            End If
        Next
    End With

Voici donc le code complet à placer dans l'évènement "A l'ouverture" de l'état :

 
Sélectionnez
Private Sub Report_Open(Cancel As Integer)
     ' Déclaration de la variable
    Dim strSqlPrepaImpress As String
 
    ' Création de la requête source
    strSqlPrepaImpress = "SELECT [PrenomEmploye] & ' ' & [NomEmploye] AS Employe, T_PlanningPreparation.CodeContrat, T_Mois.LibelleMois, MoisPlanning, AnneePlanning, " _
	    & "Activite1, Activite2, Activite3, Activite4, Activite5, Activite6, Activite7, "  _
		& "Activite8, Activite9, Activite10, Activite11, " _
		& "Activite12, Activite13, Activite14, Activite15, Activite16, " _
	    & "Activite17, Activite18, Activite19, Activite20, Activite21, Activite22, " _
		& "Activite23, Activite24, Activite25, Activite26, " _
		& "Activite27 , Activite28, Activite29, Activite30, Activite31 " _
	    & "FROM T_Employes INNER JOIN ((T_PlanningPreparation " _
	    & "INNER JOIN T_Contrats ON T_PlanningPreparation.CodeContrat = T_Contrats.CodeContrat) " _
	    & "INNER JOIN T_Mois ON T_PlanningPreparation.MoisPlanning = T_Mois.CodeMois) ON T_Employes.Matricule = T_Contrats.Matricule " _
	    & "WHERE MoisPlanning = " & p_intMoisPlanning & " AND AnneePlanning = " & p_intAnneePlanning
 
    ' Affectation de la source
    Me.RecordSource = strSqlPrepaImpress
 
    ' Recherche fin de mois
    If p_intMoisPlanning = 12 Then
        intFinMois = Day(DateSerial(p_intAnneePlanning + 1, p_intMoisPlanning + 1, 1) - 1)
    Else
        intFinMois = Day(DateSerial(p_intAnneePlanning, p_intMoisPlanning + 1, 1) - 1)
    End If
 
    'Récupération du Jeu d'enregistrements
    Set rsImpressPlanning = CurrentDb.OpenRecordset(strSqlPrepaImpress)
 
    ' Génération des étiquettes
    With rsImpressPlanning
        ' Génération du titre
        Me.lblTitre.Caption = "Planning de l'équipe pour " & .Fields(2) & " " & .Fields(4)
        For intCompteur = 0 To 15
        ' Gestion de la fin de mois
        If intCompteur + p_intCompteurImpressDeb > intFinMois Then
            Me.ZoneEntêtePage.Controls("lblDate" & intCompteur + 1).Caption = ""
        Else
            ' Implantation de la date
            Me.ZoneEntêtePage.Controls("lblDate" & intCompteur + 1).Caption = Format(DateSerial(.Fields("AnneePlanning"), _
			.Fields("MoisPlanning"), intCompteur + p_intCompteurImpressDeb), "dddd dd")
            ' Modification de la couleur en fonction du jour de la semaine
            If Left(Me.ZoneEntêtePage.Controls("lblDate" & intCompteur + 1).Caption, 1) = "S" _
			Or Left(Me.ZoneEntêtePage.Controls("lblDate" & intCompteur + 1).Caption, 1) = "D" Then
                Me.ZoneEntêtePage.Controls("lblDate" & intCompteur + 1).ForeColor = 255
            Else
                Me.ZoneEntêtePage.Controls("lblDate" & intCompteur + 1).ForeColor = 0
            End If
        End If
        Next
    End With
End Sub
IV-D-2-b-ii. Au formatage de la section détail

Dans cette procédure, il nous faut gérer les images.
Cette procédure lit le code Activité de chaque champ et recherche le chemin de l'image afin de créer la source pour chaque objet image de la section Détail.

Création du chemin de l'image
Sélectionnez
For intCompteur = 0 To 15
            ' Gestion de la fin de mois
            If intCompteur + p_intCompteurImpressDeb > intFinMois Then
                        strPathImage = "/Images/imgVierge.jpg"
            Else
                ' Ajout de 4 au compteur d'impression parce qu'il y a 4 champs dans la requête source avant le premier champ Activité
                Select Case .Fields(intCompteur + p_intCompteurImpressDeb + 4)
                   Case Is = 1
                        strPathImage = "\Images\imgTravail.jpg"
                    Case Is = 2
                        strPathImage = "\Images\imgReposM.jpg"
                    Case Is = 3
                        strPathImage = "\Images\imgReposS.jpg"
                    Case Is = 4
                        strPathImage = "\Images\imgReposJ.jpg"
                    Case Is = 5
                        strPathImage = "\Images\imgCFA.jpg"
                    Case Is = 6
                        strPathImage = "\Images\imgAbsenceJ.jpg"
                    Case Is = 7
                        strPathImage = "\Images\imgAbsenceNJ.jpg"
                    Case Is = 8
                        strPathImage = "\Images\imgRecupM.jpg"
                    Case Is = 9
                        strPathImage = "\Images\imgRecupS.jpg"
                    Case Is = 10
                        strPathImage = "\Images\imgRecupJ.jpg"
                    Case Is = 11
                        strPathImage = "\Images\imgRecupMReposS.jpg"
                    Case Is = 12
                        strPathImage = "\Images\imgReposMRecupS.jpg"
                    Case Is = 13
                        strPathImage = "\Images\imgVacances.jpg"
                    Case Is = 14
                        strPathImage = "\Images\imgMaladie.jpg"
                    Case Is = 15
                        strPathImage = "\Images\imgRupture.jpg"
                End Select
            End If
            ' Implantation de l'image dans le contrôle
            Me.Controls("img" & intCompteur + 1).Picture = CurrentProject.Path & strPathImage
            Next

Cette partie de procédure est incluse dans la lecture de tous les enregistrements du jeu sélectionné.

 
Sélectionnez
' Boucle de lecture des enregistrements sélectionnés
    With rsImpressPlanning
        ' Boucle pour sélectionner l'image à imprimer
		' ...
        ' Lecture de l'enregistrement suivant
    	.MoveNext
    End With

Voici donc le code complet affecté à l'évènement "Sur Formatage" de la section Détail :

 
Sélectionnez
Private Sub Détail_Format(Cancel As Integer, FormatCount As Integer)
    ' Déclaration de la variable
    Dim strPathImage As String
 
    ' Boucle de lecture des enregistrements sélectionnés
    With rsImpressPlanning
        ' Boucle pour sélectionner l'image à imprimer
        For intCompteur = 0 To 15
            ' Gestion de la fin de mois
            If intCompteur + p_intCompteurImpressDeb > intFinMois Then
                        strPathImage = "/Images/imgVierge.jpg"
            Else
                ' Ajout de 4 au compteur d'impression parce qu'il y a 4 champs dans la requête source avant le premier champ Activité
                Select Case .Fields(intCompteur + p_intCompteurImpressDeb + 4)
                   Case Is = 1
                        strPathImage = "\Images\imgTravail.jpg"
                    Case Is = 2
                        strPathImage = "\Images\imgReposM.jpg"
                    Case Is = 3
                        strPathImage = "\Images\imgReposS.jpg"
                    Case Is = 4
                        strPathImage = "\Images\imgReposJ.jpg"
                    Case Is = 5
                        strPathImage = "\Images\imgCFA.jpg"
                    Case Is = 6
                        strPathImage = "\Images\imgAbsenceJ.jpg"
                    Case Is = 7
                        strPathImage = "\Images\imgAbsenceNJ.jpg"
                    Case Is = 8
                        strPathImage = "\Images\imgRecupM.jpg"
                    Case Is = 9
                        strPathImage = "\Images\imgRecupS.jpg"
                    Case Is = 10
                        strPathImage = "\Images\imgRecupJ.jpg"
                    Case Is = 11
                        strPathImage = "\Images\imgRecupMReposS.jpg"
                    Case Is = 12
                        strPathImage = "\Images\imgReposMRecupS.jpg"
                    Case Is = 13
                        strPathImage = "\Images\imgVacances.jpg"
                    Case Is = 14
                        strPathImage = "\Images\imgMaladie.jpg"
                    Case Is = 15
                        strPathImage = "\Images\imgRupture.jpg"
                End Select
            End If
            ' Implantation de l'image dans le contrôle
            Me.Controls("img" & intCompteur + 1).Picture = CurrentProject.Path & strPathImage
            Next
            ' Lecture de l'enregistrement suivant
            .MoveNext
        End With
End Sub

V. Conclusion

Voilà donc comment placer des images dans vos formulaires en mode continu (à partir de la version 2007) ou dans un état. Ceci n'est qu'un exemple, à vous de vous lancer maintenant.

VI. Remerciements

Merci à Arkham46 pour ses conseils techniques éclairés.
Merci à blade159 et jacques-jean pour leur relecture et leurs conseils orthographiques.
Je remercie également toute l'équipe Office de DVP qui est toujours présente lors de l'élaboration et la finalisation d'un nouveau projet (en particulier : Tofalu, Philippe JOCHMANS et User)

VII. Téléchargement

Téléchargement : Préparation d'un planning

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+