Créer un bouton animé pour la sélection d'enregistrements dans un formulaire Access

Ce document a pour but de vous montrer comment créer un bouton animé (qui change de taille) en fonction d'un contexte particulier en amont et faisant apparaître une liste d'enregistrements à sélectionner pour continuer...
Vous devez être relativement à l'aise avec Microsoft Access et connaître la conception de formulaires mais également avoir des notions du langage Visual Basic for Application afin mettre en pratique cet exemple.

Commentez Donner une note à l'article (5)

Article lu   fois.

L'auteur

Profil ProSite personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

1. Avant propos

Ce document a pour but de vous montrer comment créer un bouton animé (qui change de taille) en fonction d'un contexte particulier en amont et faisant apparaître une liste d'enregistrements à sélectionner pour continuer...


Vous devez être relativement à l'aise avec Microsoft Access et connaître la conception de formulaires mais également avoir des notions du langage Visual Basic for Application afin mettre en pratique cet exemple.

1-1. Niveau

Ce tutoriel s'adresse à toutes personnes connaissant l'environnement de développement Access et notamment la gestion des événements avec Visual Basic sur Microsoft Access

1-2. Contact

Pour tous renseignements complémentaires, veuillez me contacter directement (Argyronet) par MP.

 

2. Préambule

Dans le cadre du développement d'un projet pour un client, j'ai été amené à réaliser une application d'aide à la décision et de reporting.
Le principe était basé sur l'absorption de fichiers Excel en base où des lignes étaient à valider avec différents cas selon leur contenu.

Tant qu'un classeur n'était pas validé, e.g. toutes les lignes n'étaient pas confirmées par une validation, il n'était pas possible de travailler avec un autre classeur et donc le bouton principal de validation sur le Menu principal voyait son initulé changer en fonction de ce constat défini par une fonction idoine qui examinait la situation.

Pour parfaire l'effet, j'ai eu l'idée d'animer ce bouton dès que le classeur en cours était terminé et que d'autres classeurs étaient disponibles

Image non disponible
Menu principal de l'application évoquée



J'ai alors décidé de vous faire profiter de ce petit embellissement, ma foi assez sympathique et presque utile...

3. Présentation du projet

Pour mettre en application ce tutoriel, j'ai transformé l'objectif du projet source en situation de gestion de commandes où ces derneières sont censées être saisies avec ou sans statut en instance.

La base de données exemple contient donc une table de commandes et une table de clients.

Je précise qu'aucun peaufinage n'est mis en application dans la conception de ce projet du fait que l'objectif se limite à la compréhension du phénomène d'animation du bouton selon 3 situations, à savoir :

  1. Visualisation des commandes (aucun effet)
  2. Saisie d'une nouvelle commande (effet + liste des clients)
  3. Validation d'une commande en cours (effet + liste des commandes concernées)

En mode démo, un appel de la fonction MsgBox() remplace l'ouverture effective du formulaire ciblé.

Note:

Ce tutoriel peut, dans son ensemble, être mis en application pour toutes les versions d'Access (Ici sur Windows XP / Seven et Access 2007).
Toutefois, certaines méthodes seront à adapter selon les versions (antérieures).

4. Mise en oeuvre du projet

4-1. Création du formulaire

Partant de l'idée que vous allez certainement mettre en application ce tutoriel sur un projet existant, je considère que vous possédez tous les éléments de base pour commencer.

Sur le principe, il est idéal que ce(s) bouton(s) soi(en)t posé(s) sur le formulaire représentant le Menu Principal...

Si tel n'était pas le cas et que vous souhaitez reproduire disons fidèlement cet exemple, créez un nouveau formulaire d'environ 14 x 10 cm et posez-y 5 contrôles :

  • 1 - Un contrôle Cadre d'options nommé fraDemo avec 3 options (dûment intitulées) ;
  • 2 - Un contrôle Label nommé lblQuestionAction justifié à droite avec une police type Calibri 12 gras-italique ;
  • 3 - Un contrôle Rectangle nommé shpDropList ;
  • 4|5 - Deux contrôles Zone de Liste déroulante superposés et respectivement nommés cboOrders et cboCustomers (Détails spécifiés après) ;
  • 6 - Un contrôle Bouton de commande nommé cmdGo.
Image non disponible
Les contrôles dans le formulaire

Il est important de bien nommer les contrôles pour le succès de l'opération d'une part et pour une meilleure lisibilité du code d'autre part...

En parallèle, la disposition et la taille de certains contrôles jouent un rôle primordial.

Rappel:

Pour plus d'information sur la convention de nommage des objets, vous pouvez lire ce tutoriel.

4-1-1. Détail sur les contrôles

Le cadre d'option fraDemo

Le cadre d'options possède 3 options dont les intitulés sont les suivants :
- Consulter les commandes
- Créer une nouvelle commande
- Valider les commandes en cours

Ce cadre est uniquement voué à la démonstration.
Dans la réalité et donc dans votre projet, l'état et l'intitulé du bouton change en fonction d'une fonction idoine qui supervise la priorité.
Ainsi que je l'ai précisé ci-avant, dans mon projet initial, le bouton possédait 2 intitulés d'une part et déclenchait 3 appels de procédure selon 3 circonstances spécifiques...

L'étiquette lblQuestionAction

Cette étiquette ne sert qu'à afficher un petit message de choix du client ou de la commande selon le cas...
Sa largeur est égale à celle du bouton de commande.

Le Rectangle shpDropList

Ce rectangle ne sert qu'à embellir le contour de chaque liste déroulante de manière à s'immiscer avec la hauteur du bouton. Il est en relief 3 D relevé.

Détails :

  • Largeur : 2,672cm
  • Hauteur : 1,173cm
  • haut : 4,566cm
  • Gauche : 9,734cm
  • Transparent : Oui
  • Plan : Arrière (4)

Les listes cboOrders et cboCustomers

Ces listes contiennent respectivement la liste des commandes en instance et la liste des clients et établies avec les clauses SQL ci-après...
Elles apparaissent selon l'intitulé du bouton et se déroulent...

Détails :

cboOrders
  • Largeur : 2,249cm
  • Hauteur : 0,688cm
  • haut : 4,808cm
  • Gauche : 9,998cm
  • Plan : Arrière (3)
  • Nombre de colonne : 2
  • Largeur colonnes : 0,702cm;5cm
  • Largeur liste : 6cm
  • Colonne liée : 1
  • Contenu :
 
Sélectionnez

SELECT TBLOrders.OrderID, " " & Format([OrderID],"000") & " du " & Format([OrderDate],"d mmm yyyy") AS OrderInfo
FROM TBLOrders
WHERE (((TBLOrders.IsValidated)=False))
ORDER BY " " & Format([OrderID],"000") & " du " & Format([OrderDate],"d mmm yyyy");
cboCustomers
  • Taille et position : idem
  • Plan : Arrière (2)
  • Nombre de colonne : 2
  • Largeur colonnes : 0cm;6cm
  • Largeur liste : 6cm
  • Colonne liée : 1
  • Contenu :
 
Sélectionnez

SELECT TBLCustomers.CustomerID, TBLCustomers.CompanyName FROM TBLCustomers;

Le bouton cmdGo

C'est le bouton principal... Il bénéficie des effets d'animation régis par le code.

Détails :

  • Largeur : 11,429cm
  • Hauteur : 1,323cm
  • haut : 4,524cm
  • Gauche : 1,032cm
  • Plan : Premier (1)
  • Légende : ""

4-1-2. Le formulaire finalisé

Une fois le formulaire et ses contrôles agencés, vous devez obtenir quelque chose comme ceci :

Image non disponible
Formulaire fini en mode création

4-2. Mise en place du code événement

4-2-1. Entête de module (Déclarations)

Le formulaire utilise pour ses contrôles, des constantes déclarées dans l'en-tête du module de classe de ce dernier.

  • Les constantes de largeur du bouton définissent la largeur mini et maxi de celui-ci
  • Les constantes d'intitulés sont utilisées au gré du choix de l'option cliquée pour le bouton
  • Une énumération est déclarée en en-tête pour faciliter la transposition des différents cas du cadre d'options

La constante MODE_DEMO sert à passer en mode démo pour éviter d'exécuter le code d'appel qui pourrait survenir lors de l'ouverture des formulaires...
Elle est définie à True dans ce cas

Entête de module (Déclarations)
Sélectionnez

Option Compare Database
Option Explicit

''' Longueur du bouton agrandi et réduit
Private Const CMD_MAX_WIDTH                  As Long = 6615
Private Const CMD_MIN_WIDTH                  As Long = 5100
''' Légende du bouton
Private Const CPT_CMD_CREATE_NEW_ORDER       As String = "&Saisir une nouvelle commande"
Private Const CPT_CMD_CONSULT_ORDERS         As String = "&Consulter les commandes"
Private Const CPT_CMD_VALIDATE_ORDERS        As String = "&Valider des commandes"
Private Const CPT_CMD_ORDERS                 As String = "&Gestion des commandes"

''' Enumération des états
Private Enum m_eOrdersButton
    eShowOrders = 1
    eNewOrder = 2
    eOrdersToValidate = 3
End Enum

''' Mettre False pour l'usage fonctionnel
Const MODE_DEMO                              As Boolean = True

4-2-2. Événement lors du chargement du formulaire

- Au chargement du formulaire, on initialise le cadre d'option avec la valeur 0 pour qu'aucune option ne soit sélectionnée ;

- Le bouton reçoit sa légende par défaut ;

- Les autres contrôles sont cachés (même s'ils sont en arrière plan pour certains).

Événement lors du chargement du formulaire
Sélectionnez

Private Sub Form_Load()
''' Intialise les contrôles pour la démonstration
    fraDemo = 0
    cmdGo.Caption = CPT_CMD_ORDERS
    shpDropList.Visible = False
    cboCustomers.Visible = False
    cboOrders.Visible = False
    lblQuestionAction.Visible = False
End Sub

4-2-3. Événement AprèsMaj de la liste des clients

L'ouverture du formulaire permettant de générer une nouvelle commande est régi par l'événement AprèsMaj de la zone de liste des clients, obligeant ainsi l'utilisateur à générer une commande pour un client donné...

La valeur issue de la sélection dans cette liste est passée à l'argument OpenArgs de la méthode OpenForm de l'objet DoCmd, précédée du nom du champ concerné et séparée par un point-virgule...
Il est évident que l'argument de la clause WHERE n'aurait pu être exploité ici du fait que la commande n'existe pas.
=> Vous aurez alors à mettre en oeuvre la gestion de la propriété OpenArgs de la méthode OpenForm ayant ouvert le formulaire.

Événement AprèsMaj de la liste des clients
Sélectionnez

Private Sub cboCustomers_AfterUpdate()
    If MODE_DEMO Then
        MsgBox "On ouvre le formulaire de création d'une commande pour le client :" _
		& vbCrLf & Me!cboCustomers.Column(1), , "Mode démonstration"
    Else
        '''Ouvre le formulaire de création d'une commande pour le client sélectionné
        DoCmd.OpenForm "frmCreateNewOrder", , , , acFormAdd, acWindowNormal, "CustomerID;" & Me.cboCustomers
    End If
End Sub

4-2-4. Événement AprèsMaj de la liste des commandes

L'ouverture du formulaire permettant d'ouvrir une commande n'ayant pas été validée (dans le schéma fonctionnel biensûr) est régi par l'événement AprèsMaj de la zone de liste des commandes, obligeant ainsi l'utilisateur à ouvrir la commande concernée...

La valeur issue de la sélection dans cette liste est passée à l'argument WhereCondition de la méthode OpenForm de l'objet DoCmd, précédée du nom du champ concerné...
Il est précisé ici que la clause WHERE est exploitée du fait que la commande existe déjà.

Événement AprèsMaj de la liste des commandes
Sélectionnez


Private Sub cboOrders_AfterUpdate()
    If MODE_DEMO Then
        MsgBox "On ouvre le formulaire permettant de valider la commande " _
		& Me!cboOrders.Column(1), , "Mode démonstration"
    Else
        ''' Ouvre le formulaire listant les commandes en restant à valider
        DoCmd.OpenForm "frmShowOrderToValidate", , , "[OrderID]=" & Me.cboOrders, acFormAdd, acWindowNormal
    End If
End Sub

4-2-5. Événement Clic du bouton de commande

C'est le bloc de code le plus riche, et pour cause, c'est le centre d'intérêt du tutoriel...

Le principe est fondé sur la propriété Caption du bouton qui possède 3 intitulés définis par le choix du cadre d'option et des constantes déclarées en en-tête..
Il est bien entendu possible d'exploiter un tout autre type de cas voire même la propriété Tag, si le coeur vous en dit.

Pour les cas de Validation d'une commande ou de Génération d'une nouvelle commande (toujours dans le contexte fonctionnel), le bouton voit sa taille affectée* pour faire apparaître la Zone de liste déroulante correspondante :

  • pour une nouvelle commande : la liste des clients
  • pour une validation de commande : la liste des commandes non validées

Enfin et surtout, le bouton de commande lui-même perd son Focus et devient désactivé (Enabled = False)

Pour le troisième intitulé, le bouton ne change pas d'état et exécute directement le code souhaité à savoir, l'ouverture du formulaire contenant toutes les commandes en cours...

D'un point de vue propriétés des contrôles...

  • Ceux qui étaient définis à Visible = False passent à True
  • L'étiquette voit sa propriété Caption affectée ou non
  • etc. (voir code et commentaires)

La constante MODE_DEMO est utilisée ici aussi afin de faire apparaître un MsgBox() au lieu d'ouvrir le formulaire...


* La valeur de 40 définie le pas de rétrécissement... Vous pouvez l'augmenter pour le ralentir.

Événement Clic du bouton de commande
Sélectionnez


Private Sub cmdGo_Click()
    Dim lngCountDemands                      As Long
    Dim lngWidth                             As Long
    Dim L                                    As Long

    ''' Selon l'intitulé du bouton...
    Select Case cmdGo.Caption
    
    ''' Validation de commandes
    Case CPT_CMD_VALIDATE_ORDERS
        lngWidth = cmdGo.Width
        ''' Réduction de la taille
        For L = lngWidth To 0 Step -40
            cmdGo.Width = L
            If L <= CMD_MIN_WIDTH Then Exit For
            DoEvents
        Next
        cmdGo.SetFocus
        shpDropList.Visible = True
        ''' Affectation de l'état des liste...
        With cboOrders
            .Visible = True
            .SetFocus
            .Dropdown
        End With
        With cboCustomers
            .Visible = False
        End With
        With lblQuestionAction
            .Visible = True
            .Caption = "Pour quelle commande ?"
        End With
        cmdGo.Enabled = False
        MoveMouseToControl Me, "cboOrders", 170, 24

    ''' Nouvelle commande
    Case CPT_CMD_CREATE_NEW_ORDER
        lngWidth = cmdGo.Width
        ''' Réduction de la taille
        For L = lngWidth To 0 Step -40
            cmdGo.Width = L
            If L <= CMD_MIN_WIDTH Then Exit For
            DoEvents
        Next
        cmdGo.SetFocus
        shpDropList.Visible = True
        ''' Affectation de l'état des liste...
        With cboOrders
            .Visible = False
        End With
        With cboCustomers
            .Visible = True
            .SetFocus
            .Dropdown
        End With
        With lblQuestionAction
            .Visible = True
            .Caption = "Pour quel client ?"
        End With
        cmdGo.Enabled = False
        MoveMouseToControl Me, "cboCustomers", 170, 24

    ''' Liste des commandes
    Case CPT_CMD_CONSULT_ORDERS
        lngCountDemands = DCount("OrderID", "TBLOrders")
        If lngCountDemands Then
            ''' Ouvre le formulaire listant les commandes en cours
            If MODE_DEMO Then
                MsgBox "On ouvre le formulaire listant les commandes en cours", , "Mode démonstration"
            Else
                DoCmd.OpenForm "frmShowOrderList", , , , acFormAdd, acWindowNormal, "CustomerID;" & Me.cboCustomers 
            End If
        Else
            MsgBox "Il n'existe aucune commande à consulter actuellement.", 16, "Information"
        End If
    End Select
End Sub

4-2-6. Événement AprèsMaj du cadre d'options

Comme précisé ci-avant, le cadre d'option n'a pour rôle que d'appliquer le coté théorique de ce tutoriel.
Il vous appartient de mettre en oeuvre le code ad-hoc afin que le bouton voit sa propriété Caption affectée en fonction de telle ou telle circonstance...

Ici, son rôle se limite à :

  1. réinitialiser la taille du bouton,
  2. de lui donner le Focus,
  3. d'affecter sa propriété Caption
  4. et à masquer certains contrôles.

Rappel :
Un cadre d'option sous Access renvoie la valeur correspondante de l'élément coché ou cliqué (1,2,n...) si peu que vous ayez énuméré ces éléments chronologiquement ou la valeur correspondante dans le cas contraire...

Paradoxalement, en VBA (pour Excel, Word et PowerPoint...) dans un UserForm, c'est l'élément coché ou cliqué qui prend la valeur True et les autres False, le cadre ne servant qu'à délimiter le périmètre des boutons d'option qu'il contient. Tout bouton d'option externe au cadre n'est pas concerné.

Événement AprèsMaj du cadre d'options
Sélectionnez

Private Sub fraDemo_AfterUpdate()
''' Une fonction gère l'état et le Caption du bouton à l'ouverture du formulaire
    With Me.cmdGo
        Select Case fraDemo
        Case eShowOrders
            .Caption = CPT_CMD_CONSULT_ORDERS
            .ControlTipText = "Permet d'afficher la liste des toutes les commandes"
        Case eNewOrder
            .Caption = CPT_CMD_CREATE_NEW_ORDER
            .ControlTipText = "Permet d'enregistrer une nouvelle commande"
        Case eOrdersToValidate
            .Caption = CPT_CMD_VALIDATE_ORDERS
            .ControlTipText = "Permet d'afficher la liste des commandes à valider"
        End Select
        .Enabled = True
        .Width = CMD_MAX_WIDTH
        .SetFocus
    End With
    ''' Masque les autres contrôles
    shpDropList.Visible = False
    cboCustomers.Visible = False
    cboOrders.Visible = False
    lblQuestionAction.Visible = False
End Sub

4-3. La procédure MoveMouseToControl()

Le petit plus qui rend l'effet encore plus sympathique est de forcer la position du pointeur de la souris sur la liste déroulante après avoir cliqué sur le bouton...

Le principe consiste à utiliser l'API SetCursorPosPage MSDN couplée à la fonction non documentée accLocation().

Code avec accLocation (non opération sous 2007)
Sélectionnez

Private Declare Function apiSetCursorPos 
        Lib "user32" Alias "SetCursorPos" (ByVal X As Long, ByVal Y As Long) As Long
 
Private Sub MoveMouseToControl (ByRef F As Access.Form, _
                              ByVal ControlName As String, _
                              ByVal GoToRight As Long, _
                              ByVal GoToBottom As Long)
    Dim lx As Long, ly As Long, lw As Long, lh As Long
    ' *** Pour la version 2007 un 5ème paramètre est requis
    Call F.Controls(ControlName).accLocation(lx, ly, lw, lh, 0&)
    apiSetCursorPos lx + lw / 2 + GoToRight, ly + lh / 2 + GoToBottom
End Sub

Du fait que la fonction accLocation() ne s'exploite pas sous la version 2007 d'Access comme sous les versions précédentes, vous pouvez :

  • soit inscrire, quoi qu'il en soit, le 5ème argument 0&, que vous utilisiez la version 2007 ou une version antérieure.
  • soit utiliser l'exemple stipulé ci-après.

Sous Access 2007, si vous omettez le 5ème argument - celui-ci étant facultatif dans les versions antérieures à 2007 - cela se traduira par une erreur 5 et bien entendu, aucune aide contextuelle n'est consultable...

Image non disponible


Dans ce tutoriel, j'ai exploité et adapté la code de la fonction alternative issue de la FAQ et écrite par Arkham46 et Cafeine que vous trouvez à cette page...

Vous ajoutez ainsi un module à votre projet que vous nommez par exemple basApplication et vous y recopiez le code suivant :

 
Sélectionnez

'---------------------------------------------------------------------------------------
' Module     : basApplication
' Author     : Arkham46, Cafeine
' Adaptation : Argyronet
' Date       : 06/04/2010
' Purpose    : Permet de positionner la souris sur un contrôle donné
' Source     : Developpez.com (http://access.developpez.com/faq/?page=Ctrl#DeplacerMouseControl)
'---------------------------------------------------------------------------------------

Option Compare Database
Option Explicit

Private Type RECT
    Left                                     As Long
    Top                                      As Long
    Right                                    As Long
    Bottom                                   As Long
End Type

Private Declare Function apiSetCursorPos _
        Lib "user32" Alias "SetCursorPos" (ByVal X As Long, ByVal Y As Long) As Long
Private Declare Function GetWindowRect _
        Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long
Private Declare Function apiGetFocus _
        Lib "user32" Alias "GetFocus" () As Long

'---------------------------------------------------------------------------------------
' Procedure : MoveMouseToControl
' Author    : Arkham46, Cafeine
' Updated   : JP AMBROSINO
' Date      : 06/04/2010
'--------------------------------
' Parameters:
' F = Objet formulaire
' ControlName = Nom du contrôle
' GoToRight = Valeur de décalage (vers le la droite)
' GoToBottom = Valeur de décalage (vers le bas)
'---------------------------------------------------------------------------------------
'
Public Sub MoveMouseToControl(ByRef F As Access.Form, _
                              ByVal ControlName As String, _
                              ByVal GoToRight As Long, _
                              ByVal GoToBottom As Long)
    Dim oCtl                                 As Control
    Dim hCtl                                 As Long
    Dim tRect                                As RECT

    For Each oCtl In F.Controls
        If oCtl.Name = ControlName Then
            oCtl.SetFocus
            hCtl = apiGetFocus
            GetWindowRect hCtl, tRect
            apiSetCursorPos tRect.Left + (tRect.Right - tRect.Left) / 2 + GoToRight, _
            tRect.Top + (tRect.Bottom - tRect.Top) / 2 + GoToBottom
            Exit For
        End If
    Next oCtl
    Set oCtl = Nothing
End Sub

4-3-1. Mais au fait... Pourquoi 170 et 24 ?

Effectivement, vous êtes en droit de vous poser la question...
J'ai inscrit ces valeurs respectivement pour le décalage droit et bas en convertissant les valeurs du contrôle de Zone de liste exprimées en centimètres une fois déroulé à concurrence de 75% de sa valeur et convertie en Pixels...
Ces paramètres permettent au pointeur se loger suffisamment à droite et en dessous du texte...

5. Mise en exécution

Une fois cette étape terminée, vous basculez de nouveau sur votre formulaire (Alt+Tab) ou bien vous quittez l'éditeur Visual Basic Editor depuis le menu Fichier.

Vous enregistrez de manière à ne pas perdre votre travail et vous passez en Mode Formulaire.

Image non disponible

À cet instant, lorsque vous cochez une option puis vous cliquez sur le bouton, l'événement correspondant s'applique...

Lorsque l'on souhaite générer une nouvelle commande...

Image non disponible

Lorsque l'on souhaite valider une commande en instance...

Image non disponible



Voici la vidéo représentant le résultat de l'utilisation du bouton en question


Cliquez pour lire la vidéo



6. Conclusion

Ce petit tutoriel relativement simple permettra aux personnes désireuses d'agrémenter leurs formulaires de mettre en place cette routine ma fois amusante et peu orthodoxe.

D'autres idées peuvent découler de ce tutoriel, en tout cas je vous le souhaite...

7. Remerciements

Je tiens à remercier toutes celles et ceux qui ont participé à la relecture de ce document en y incluant leurs remarques et en particulier :

Arkham46, Pierre Fauconnier et Tofalu pour leurs points de vue et pixelomilcouleurs pour sa relecture approfonfie.

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

Ce document est issu de http://www.developpez.com et reste la propriété exclusive de son auteur. La copie, modification et/ou distribution par quelque moyen que ce soit est soumise à l'obtention préalable de l'autorisation de l'auteur.