I. 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.
I-A. 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.
I-B. Contact▲
Pour tous renseignements complémentaires, veuillez me contacter directement (Argyronet) par MP.
II. 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 intitulé 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
J'ai alors décidé de vous faire profiter de ce petit embellissement, ma foi assez sympathique et presque utile…
III. 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 derniè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 trois situations, à savoir :
- Visualisation des commandes (aucun effet) ;
- Saisie d'une nouvelle commande (effet + liste des clients) ;
- 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).
IV. Mise en œuvre du projet▲
IV-A. 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 cinq contrôles :
- 1 - Un contrôle Cadre d'options nommé fraDemo avec trois 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.
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.
IV-A-1. Détail sur les contrôles▲
Le cadre d'option fraDemo
Le cadre d'options possède trois 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 changent 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 deux intitulés d'une part et déclenchait trois appels de procédure selon trois 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 sont é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 colonnes : 2
- Largeur colonnes : 0,702cm;5cm
- Largeur liste : 6cm
- Colonne liée : 1
- Contenu :
SELECT
TBLOrders.OrderID, "N° "
&
Format
(
[OrderID]
,"000"
)
&
" du "
&
Format
(
[OrderDate]
,"d mmm yyyy"
)
AS
OrderInfo
FROM
TBLOrders
WHERE
(((
TBLOrders.IsValidated)=
False
))
ORDER
BY
"N° "
&
Format
(
[OrderID]
,"000"
)
&
" du "
&
Format
(
[OrderDate]
,"d mmm yyyy"
)
;
cboCustomers
- Taille et position : idem
- Plan : Arrière (2)
- Nombre de colonnes : 2
- Largeur colonnes : 0cm;6cm
- Largeur liste : 6cm
- Colonne liée : 1
- Contenu :
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 : ""
IV-A-2. Le formulaire finalisé▲
Une fois le formulaire et ses contrôles agencés, vous devez obtenir quelque chose comme ceci :
IV-B. Mise en place du code événement▲
IV-B-1. En-tê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
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"
''' Énumé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
IV-B-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).
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
IV-B-3. Événement AprèsMaj de la liste des clients▲
L'ouverture du formulaire permettant de générer une nouvelle commande est régie 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 œuvre la gestion de la propriété OpenArgs de la méthode OpenForm ayant ouvert le formulaire.
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
IV-B-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 bien sûr) est régie 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à.
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
IV-B-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 trois 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 la propriété Tag, si le cœur 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éfinit le pas de rétrécissement… Vous pouvez l'augmenter pour le ralentir.
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 listes...
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 listes...
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
IV-B-6. Événement Après Maj du cadre d'options▲
Comme précisé ci-avant, le cadre d'option n'a pour rôle que d'appliquer le côté théorique de ce tutoriel.
Il vous appartient de mettre en œuvre le code ad hoc afin que le bouton voie sa propriété Caption affectée en fonction de telle ou telle circonstance…
Ici, son rôle se limite à :
- Réinitialiser la taille du bouton ;
- Lui donner le Focus ;
- Affecter sa propriété Caption ;
- 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é.
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
IV-C. 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().
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 5e 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 5e 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 5e 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…
Dans ce tutoriel, j'ai exploité et adapté le 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 :
'---------------------------------------------------------------------------------------
' 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
IV-C-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 de se loger suffisamment à droite et en dessous du texte…
V. 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.
À 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…
Lorsque l'on souhaite valider une commande en instance…
Voici la vidéo représentant le résultat de l'utilisation du bouton en question
VI. Conclusion▲
Ce petit tutoriel relativement simple permettra aux personnes désireuses d'agrémenter leurs formulaires de mettre en place cette routine ma foi amusante et peu orthodoxe.
D'autres idées peuvent découler de ce tutoriel, en tout cas je vous le souhaite…
VII. Remerciements▲
Je tiens à remercier toutes celles et tous 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 approfondie.