Pour partager cette vidéo sur les réseaux sociaux ou sur un site, voici son url :
Sujets que vous pourriez aussi aimer :
Corriger le défaut des listes liées
Dans cette
formation VBA Access , nous livrons une solution intéressante pour corriger un défaut concernant les
listes déroulantes liées entre elles . Nous avions développé un
formulaire Access pour synthétiser et relier les données . Et sur ce
formulaire , nous avions fait interagir deux
listes déroulantes , grâce à une
requête au critère dynamique . Le choix dans la liste parent restreint naturellement les possibilités dans la liste enfant.
Cependant, la valeur précédente dans la liste enfant est conservée en mémoire, malgré le changement dans la liste parent. Elle reste proposée bien qu'elle n'appartienne plus aux choix offerts. Ce défaut est à la fois déroutant et dangereux. En effet, cette donnée peut très bien être enregistrée dans la
base de données , bien qu'incohérente.
Dans l'extrait de la capture ci-dessus, le modèle de la marque Renault reste proposé parmi les modèles de la marque Peugeot.
Nous avions d'ailleurs noté le même souci au travers de la
formation Excel pour relier des listes déroulantes par calculs . Mais dans l'un et l'autre cas, l'objectif était d'apporter la solution pour des
listes en cascade sans l'appui du
code VBA . Et nous y étions parvenus.
Sources et présentation de la problématique
Pour apporter cette correction, nous proposons de récupérer la petite
base de données Access reliant ces listes déroulantes.
Après un téléchargement, ce fichier est considéré comme inconnu. Il s'agit d'une mesure de précaution de la part des logiciels de la gamme Office.
Dans le volet des objets Access sur la gauche, double cliquer sur la table Parc ,
Nous affichons ainsi son contenu en mode feuille de données. Comme vous le constatez, l'entreprise gère un parc d'automobiles d'occasion en transit.
Maintenant que les présentations sont faites, nous souhaitons vérifier le fonctionnement des
listes déroulantes .
Fermer la table Parc en cliquant sur la croix de son onglet,
Dans le volet des objets Access sur la gauche de l'écran, double cliquer sur le formulaire Parc ,
Nous commandons ainsi son exécution. Comme vous le remarquez, le gestionnaire peut visionner les véhicules indépendamment et les modifier. Un changement de Marque dans la première liste déroulante, impose un changement de contenu dans la seconde liste, celle des modèles. Ce fonctionnement est tout à fait logique. Ces deux
listes déroulantes sont donc bien reliées entre elles.
Dans la première liste déroulante, choisir la marque VOLKSWAGEN à la place de Renault,
Dans la foulée, déployer la liste enfant des modèles,
Comme vous le remarquez, deux modèles appartenant à la
marque Volkswagen sont effectivement proposés. La seconde
liste déroulante s'est remplie en fonction du choix émis dans la première liste. Cependant, et cela ne vous a sans doute pas échappé, le modèle précédemment sélectionné est toujours proposé. Et ce modèle (Modus) appartient à la marque Renault et non Volkswagen. Sur la capture d'écran, il s'agit du modèle 207 SW. Des manipulations supplémentaires ont été réalisées. Les symptômes sont cependant bien les mêmes.
Comme nous le disions en préambule, il ne s'agit pas d'un défaut de liaison entre les listes déroulantes mais du fonctionnement normal. Le précédent choix est conservé en mémoire.
Et malheureusement, si nous changions d'enregistrement, ce choix incohérent serait sauvegardé. Est-il nécessaire de le rappeler, une base de données écrit en temps réel sur le disque dur.
Listes liées sans code VBA
Pour pallier ce souci dans la liaison, nous proposons d'accéder aux requêtes qui établissent la relation. Nous comprendrons mieux comment le corriger.
Dans le ruban Accueil, cliquer sur la flèche du bouton Affichage ,
Dans la liste, choisir Mode création pour accéder au formulaire en conception,
Cliquer sur la première liste déroulante pour la sélectionner,
Dans le ruban Création, cliquer sur le bouton Feuille de propriétés s'il elle n'est pas visible,
En consultant sa feuille de propriétés, nous constatons que cette liste déroulante se nomme
Marque .
Activer l'onglet Données de cette feuille,
Comme l'indique la
propriété Contenu , la source de cette liste est la
requête nommée
R_Marques .
Double cliquer sur son nom dans le volet des objets Access sur la gauche de l'écran,
Ainsi nous l'exécutons. Nous constatons qu'elle liste en effet les marques de façon unique.
Dans le ruban Accueil, cliquer sur la flèche du bouton Affichage ,
Dans la liste, choisir Mode SQL ,
Nous remarquons la présence d'une
clause Distinct dans sa syntaxe. Nous l'avions mise en oeuvre pour éliminer les doublons :
SELECT DISTINCT Marque FROM Parc;
Fermer cette requête en cliquant sur la croix de son onglet,
De retour sur le formulaire en conception, sélectionner la seconde liste déroulante,
Elle se nomme donc
Modèle et sa source est la
requête R_Modeles comme l'indique la
propriété Contenu dans l'onglet Données de sa feuille de propriétés.
Dans le volet des objets Access, double cliquer sur son nom pour l'exécuter,
Et comme vous le remarquez, elle n'affiche rien. Ce phénomène est tout à fait logique. Il s'agit d'une
requête dynamique . Elle attend le choix émis dans la première
liste déroulante , celle des marques, pour effectuer la sélection et remplir son contenu en conséquence.
Dans le ruban Accueil, cliquer sur la flèche du bouton Affichage puis choisir le mode Création ,
Et comme vous le constatez, la sélection des modèles pour le champ conservé visible dans la grille de requête, dépend du choix de la marque effectué depuis la
liste déroulante Marque sur le
formulaire .
Cette liaison est donc très intéressante et fonctionnelle. C'est elle qui articule les listes déroulantes. Désormais, la question est :
Comment corriger ce problème de valeur mémorisée, au changement dans la liste parent ?
Contrôler la liaison des listes par le code VBA
Ce sont quelques très simples instructions
Visual Basic qui vont permettre de corriger le défaut.
Fermer la requête R_Modeles en cliquant sur la croix de son onglet,
Sur le formulaire, sélectionner de nouveau la liste déroulante parent nommée Marque,
Puis, activer l'onglet Evènement de sa feuille de propriétés,
Nous remarquons qu'une
macro est associée à son
évènement Sur changement . En effet, elle a pour objectif d'imposer le recalcul pour que la liste déroulante enfant se charge en conséquence. C'est l'astuce intéressante que nous avions mise en oeuvre pour contourner VBA. Nous proposons de le constater.
Cliquer sur le petit bouton situé sur la droite de la ligne de l'évènement,
Nous basculons ainsi dans l'
éditeur de macros Access . Et comme vous le voyez, l'astuce est triviale. Nous nous sommes contentés de choisir l'
action ActualiserEnregistrement . Comme cette opération se déclenche au changement détecté dans la première liste déroulante, le contenu de la seconde s'actualise automatiquement. Mais aucune action de
macro ne permet de préciser que nous ne souhaitons pas conserver la précédente valeur mémorisée.
Nous allons donc remplacer cette
macro par un code VBA Access. Lui aussi doit se déclencher sur évènement, cela va de soi.
Fermer l'éditeur de macros,
De retour sur le formulaire Access, supprimer la macro incorporée associée à son évènement Sur changement , depuis sa feuille de propriétés,
Puis, cliquer de nouveau sur le bouton situé en regard,
Dans la boîte de dialogue, choisir Générateur de code ,
De fait, et comme nous l'avons appris au travers des
formations VBA Access , nous basculons dans l'éditeur de
code VBA , entre les bornes de la
procédure évènementielle Marque_Change . Les instructions que nous y ajouterons se déclencheront au changement de valeur détecté dans la liste parent.
Deux lignes suffisent. Il s'agit d'effacer la valeur sélectionnée dans la liste Modèle puis d'imposer l'actualisation des enregistrements pour établir la liaison avec la liste parent.
Ajouter les instructions VBA suivantes :
Private Sub Marque_Change()
Modèle.Value = ''
Modèle.Requery
End Sub
Tout d'abord, la
propriété value du
contrôle de liste déroulante Modèle permet d'accéder à son contenu. Nous l'affectons sur une chaîne vide. Ainsi, nous effaçons cette fameuse proposition mémorisée et dangereuse. Puis, nous exploitons sa
méthode Requery pour imposer le recalcul, en l'occurrence ici l'
actualisation des enregistrements . L'objectif est que le contenu de cette liste enfant réagisse en fonction du choix dans la liste parent, pour se remplir en conséquence, comme l'impose la
requête dynamique qui est définie en source de données.
Remarque : l'emploi des accents n'est jamais judicieux en programmation. Nous aurions dû nommer cette liste : Modele. Mais jusqu'alors cette application ne faisait pas appel au code VBA.
Enregistrer les modifications (CTRL + S) et revenir sur le formulaire,
L'exécuter en enfonçant la touche F5 du clavier,
Changer de marque à l'aide de la première liste déroulante,
Cette fois en effet, nous constatons que la proposition précédente n'est plus suggérée. Seuls les modèles correspondant à la marque choisie dans la liste parente sont disponibles. C'est ce qu'illustre la capture ci-dessous.
En revanche, un problème surprenant subsiste.
Si nous changeons d'enregistrement, ce ne sont pas les modèles de la marque active qui sont proposés dans la liste déroulante enfant. Il s'agit des modèles de la précédente marque, celle de l'enregistrement précédent.
Access considère qu'aucun changement n'a été opéré dans la liste déroulante parente. En conséquence, il ne réactualise par le contenu de la liste enfant. Pour pallier le problème, nous devons
forcer l'actualisation , une fois encore, par le
code VBA .
Un changement d'enregistrement a pour effet d'activer le formulaire, de lui rendre le focus. Nous devons gérer cet évènement.
Revenir sur le formulaire en mode conception,
Le sélectionner par son angle supérieur gauche (Cf. capture ci-dessous),
Puis, dans l'onglet Evènement de sa feuille de propriétés, cliquer sur le petit bouton de son évènement Sur activation ,
Dans la boîte de dialogue qui suit, choisir Générateur de code ,
Nous basculons de nouveau dans l'
éditeur VBA Access mais cette fois, entre les bornes de la
procédure évènementielle Form_Current . En d'autres termes, son code se déclenchera à chaque
activation du formulaire , donc à chaque changement d'enregistrement notamment.
Ajouter les deux instructions VBA suivantes :
Private Sub Form_Current()
Marque.Requery
Modèle.Requery
End Sub
Grâce à la
méthode Requery des objets de liste déroulante, nous forçons l'actualisation des enregistrements qui leur sont liés. Il s'agit bien sûr des requêtes source respectives.
Enregistrer les modifications et basculer sur le formulaire,
Enfoncer la touche F5 pour l'exécuter,
Le changement dans la liste parent a toujours pour effet d'annuler la précédente valeur suggérée. Et nous pouvons associer un nouveau modèle correspondant à la nouvelle marque. Mais cette fois, en plus de cela, lorsque nous changeons d'enregistrement, la liste enfant est correctement chargée des modèles de la marque présélectionnée dans la liste parent.
Nous avons donc parfaitement réussi la
liaison entre les
listes déroulantes du
formulaire Access tout en corrigeant ce petit défaut contraignant.