Syntaxe VBA : ‘.’ vs. ‘!’

Êtes-vous adepte du Dot (.) ou du Bang (!) dans vos syntaxes VBA ? Connaissez-vous la différence entre les 2 ? Dans cet article nous allons essayer d’y voir plus clair.

Un peu d’histoire pour comprendre

Bang (!) le séparateur historique

En 1992, lorsque Access est paru, il n’y avait que 2 possibilités pour automatiser les processus :

  • Les Macros
  • Les expressions
  • Access Basic dérivé de Visual Basic, qui deviendra avec Access 2.0 le célèbre VBA.

Pour accéder aux composants des formulaires et des états, le séparateur adopté fut le point d’exclamation (Bang en anglais). Toute la documentation Access Basic se résumant au manuel de programmation d’Access indiquait le Bang (!) comme séparateur.

Le Dot (.) modernise Access Basic

En version 2.0 d’Access le point (. Dot) fait son apparition et avec lui une fonctionnalité très attendue : L’autocomplétion.

Cette liste de membres ajoute du confort au développement en VBA et permet aux plus curieux une exploration des modèles objets utilisés.
Il faut au préalable avoir coché son utilisation dans VBE/Outils/Options :

Le F2 (explorateur d’objets) vient complété cette offre de service.

Bang ! vs. Dot .

On l’aura compris pour avoir une bonne maitrise du code et une courbe d’autoformation améliorée, l’utilisation du Dot (.) est à privilégier.
Doit-on abandonner le Bang pour autant ? La réponse est clairement Non !
Il a une signification, il désigne l’élément (méthode/propriété) par défaut de certaines classes.

'Code exemple
Dim rst as dao.Recordset
Set rst = currentdb.openrecordset("Select id, nom, prenom From tClient;", dbopensnapshot)

'cette syntaxe 
debug.print rst.fields("nom").value
' est equivalente à celle-ci
debug.print rst!nom.value

Avec l’Explorateur d’Objets de VBA (F2) on peut vérifier si un membre est déclaré « par défaut ».

Le point bleu sur l’icône + l’intitulé « Membre par défaut » dans la description du membre.

Utilisation de Bang (!) et ses exceptions

L’utilisation du Bang (!) dans les collections pourrait être simple s’il ne souffrait pas de quelques exceptions.
La collection Form et Report indique que « Controls » (collection des controls) est le membre par défaut. Mais étrangement il peut aussi désigner la colonne d’une table ou d’une requête indiqué dans la source du formulaire ou de l’état si celle-ci n’a pas de « Control » (zone de texte, zone de liste…) liée.

Autrement dit pour une source du formulaire comme ceci :

SELECT id, nom, prenom FROM tClient;

Où seul Nom et Prénom aurait leur zone de texte insérée dans le formulaire/état on pourrait très bien utiliser le Bang (!) dans VBA pour faire référence à Id qui lui n’a pas de « Control ».

'fonctionne
Me!Id
'ne fonctionne pas
Me.Id

Conclusion

L’utilisation du Dot (.) est donc primordial pour travailler avec VBA. D’ailleurs lorsqu’on regarde les problèmes remontés dans les forums sur du code qui provoque des erreurs du type « Membre inconnu » on remarque souvent que le Bang (!) est employé à tous les étages.

Certain diront que le code verbeux est proscrire mais il s’agit d’une habitude qui permet plusieurs années après la conception de mieux s’y retrouver. C’est pour cela que je n’emploie le Bang (!) que pour son exception, jamais pour le le membre par défaut.

Et vous, quelle habitude avez-vous et qu’utilisez vous majoritairement ?
Est-ce que ce billet va vous faire changer vos habitudes ?

Erreur 3010 avec DAO.CreateTableDef()

Ce problème est constaté le 16/01/2023

Le CreateTabledef() de DAO ne fonctionne plus comme avant !
Avec un :

Set td = db.CreateTableDef(tblname, dbAttachSavePWD, tblname, strConnexionOdbc)


On obtient une erreur 3010, la table existe déjà, mais non elle n’existe pas, ni dans la liste des objets, ni dans TableDefs et encore moins dans MsysObjects.

Quand on observe td on peut voir que Name et égal à SourceTableName …
Le contournement est possible :

Set td = db.CreateTableDef()
td.Name = strTable
td.SourceTableName = tblname
td.Connect = strConnexionOdbc
td.Attributes = dbAttachSavePWD


       Ou encore :

DoCmd.TransferDatabase acLink, "ODBC Database", strConnexionOdbc, acTable, tblname, strTable, False, False

Ce problème a été constaté avec une application qui fonctionne avec ce code depuis 2016, et sur une fonctionnalité qui est utilisée de manière hebdomadaire.

Le pilote ODBC n’est pas en cause, des tests ont été fait dans ce sens.

Microsoft Access n’est pas une base de données

Lorsque vous posez la question ; qu’est ce que Microsoft Access ? Immanquablement la réponse sera, « C’est une base de données ! ». Affirmation éculée mais totalement fausse colportée au mieux par les ignorants et au pire par les perroquets de salon. Cet article est là pour vous éclairer sur Microsoft Access.

Microsoft Access : une solution trop peu envisagée

Microsoft Access est plutôt à ranger dans la catégorie des RAD (Rapid Application Developpement – Outil de développement rapide d’application), accessoirement il est doté d’une base de données intégrées (Jet puis ACE depuis 2007) dont il se sert pour ses propres besoins. Cependant à aucun moment vous n’êtes tenu de l’utiliser dans votre projet. Beaucoup d’applications se résumant en un simple front-end (côté utilisateur) Microsoft Access utilisent comme un back-end (côté serveur) d’autres moteurs de bases de données comme MS SQL Server, Oracle, MySql/Mariadb, PostgreSql.

Microsoft Access est doté des composants suivants :

  • Les formulaires pour l’interaction avec l’utilisateur, ils sont dotés de composants riches et programmables.
  • Les états pour imprimer des données (test, image, graphique…). On y retrouve la totalité des composants du formulaire.
  • Les macros, un langage facile pour faire des tâches simples lorsqu’on ne connait rien à la programmation ça peut être suffisant.
  • Les modules VBA, certains nomment à tort le langage VBA comme un langage macro. C’est un véritable langage typés avec des instructions, des bibliothèques, des classes… On peut y faire des appels systèmes comme de la manipulation graphique.
  • Les requêtes, là on rentre dans le concept de base de données. Le générateur permet au néohpyte de se faire la main en générant rapidement des intructions SELECT, INSERT, DELETE… Elles prennent en charge les type UNION, Tableau croisé dynamique ou Passthrough (requête exécutée sur le serveur de base de données)
  • Les tables, la fameuse base de données accessoire.

Microsoft Access : ses qualités

L’une de ses premières qualité est que la conception de l’interface (IHM ou partie visible pour l’utilisateur) sera réalisée plus rapidement qu’avec les langages classiques. Vous serez donc à même de présenter une maquette sans que cela soit trop chronophage où l’utilisateur sera enfin son propre décideur.
De même que si la volumétrie de données et le nombre d’utilisateurs ne sont pas trop important vous opterez pour la base de données interne (ACE).
On peut également dire qu’il est assez accessible pour un profane, dans la limite d’un besoin simple.
En dernier ressort on peut également l’interfacer avec les produits VBA-Like (logiciels dont VBA est le langage de programmation), on y trouve bien évidemment les logiciels de la suite Office : Excel, Word, Powerpoint, Publisher… mais aussi AutoCad, Wordperfect, ArcGis, Solidwork…
Vous souhaitez faire des rapports complexes, envoyez vos données dans Microsoft Word ou bien dans Microsoft Excel.

Microsoft Access : ses défauts

Effectivement, à l’heure du tout-en-ligne, cloud et autre, une application Microsoft Access reste un client lourd, nécessitant Windows et qui n’est pas prévu pour le fonctionnement WEB. Il n’est donc pas possible de l’intégrer à du téléphone mobile.

Son éditeur VB (VBE) n’est pas un modèle d’avancée technologique puisqu’il n’a pas évolué depuis la version 7, soit 1995. Bien que quelques Add-in’s viennent compléter ses lacunes, beaucoup de développeurs souhaiteraient que Microsoft mettent un bon coup de collier pour fournir quelques évolutions essentielles.

Enfin la qualité d’accessibilité décrite dans le paragraphe précédent peut se transformer en défaut, et c’est ce que beaucoup lui reproche. On peut créer de véritables monstres dont la maintenance et l’évolution deviendra un repoussoir pour nombre d’expert de Microsoft Access.

Microsoft Access : une mauvaise réputation fondée ?

Je me permettrais de citer un paragraphe lu sur un site anglo-saxon qui résume à lui seul cet article.

« Les personnes qui n’ont jamais utilisé Microsoft Access ou quelque chose du genre et qui se considèrent comme des programmeurs invétérés ou des puristes de bases de données, considèrent Microsoft Access comme un jouet d’enfant dangereux, ne causant que du chagrin lorsque de vrais programmeurs et administrateurs de bases de données doivent déboguer le désordre désorganisé des amateurs. Ils rêvent du jour où cette nuisance sera éliminée et où leur entreprise pourra enfin être sous le contrôle bureaucratique strict d’applications bien conçues que personne ne se soucie d’utiliser. »

Microsoft Access n’échappe pas à la règles des outils et langages de développement, il ne fait que ce qu’on lui dit de faire et comment le faire. Une application inutilement gourmande en ressource, lente, mal conçue, désorganisée, moche ou simplement « user-spiteful » n’est pas la faute de l’outil mais bien du concepteur.

Conclusion

Pour conclure Microsoft Access, même si il a quelques défauts, n’en reste pas moins à ce jour un excellent moyen de concevoir rapidement des interfaces riches en faisant abstraction de la base de données utilisée.


MS ACCESS : pièces jointes grisées et autres problèmes

On peut constater de temps à autre des problèmes avec le composant des Pièces Jointes (PJ). Je l’ai constaté à la création d’une PJ avec 2016 alors qu’avec 2013 je n’avais pas rencontré ce problème.

Pièces Jointes grisées, menu grisé, trombone absent, Filtre #Erreur

Cela ce manifeste par l’absence de la barre d’outils sur le contrôle PJ.

la barre d’outils des PJ

Le menu contextuel du contrôle de PJ est grisé, surtout le Gérer le pièces jointes, et il comporte 2 lignes Filtres avec #Erreur mentionné.

Le menu contextuel des PJ

Et dans la table, la colonne de la PJ ne comporte pas le trombone dans la zone de saisie.

La colonne PJ dans la table

Réparation des Pièces Jointes

Sur la frontale (front end)

1) supprimer les tables liées. Attention ! Si vous n’avez pas de dorsale, ne supprimer pas les tables, vous les perdriez définitivement et vos données avec.
2) fermer l’application.
3) faire un décomp/comphttp://blogaccess.free.fr/?p=75)

Sur la dorsale (back end)

3) compacter la dorsale (le décomp/comp est inutile)
4) vérifier que le trombone est revenu sur la colonne en question.
5) rouvrir la frontale, supprimer le contrôle PJ et le recréer.

Si la frontale est correctement conçue l’attache se fait automatiquement, sinon refaire la liaison manuellement.

Conseil pour les PJ

A noter que stocker des PJ dans une base c’est une très mauvaise idée quand on la laisse à des utilisateurs. Lorsque la limite de 2Go est atteinte elle crashe est on se retrouve avec une belle brique décorative sur le disque.

Bonne utilisation.

ACCESS : Filtrer une zone de liste déroulante à l’appuie d’une touche.

Dans ce petit billet nous allons mettre en œuvre un système de filtrage d’une zone de liste déroulante en temps réel. Pour cela nous avons besoin d’une table et d’un formulaire contenant une zone de liste déroulante.

La liste déroulante

Créer une liste déroulante dont le nom sera « lmFiltre », puis réglons quelques propriétés pour quelle affiche les données de la table. Pour l’exemple j’utilise la table système MSysObjects.

Contenu : SELECT [MSysObjects].[Id], [MSysObjects].[Name] FROM MSysObjects;
Nbre colonnes : 2
Largeurs colonnes : 0cm;2,54cm

La colonne Name sera visualisée et le filtre agira sur celle-ci.

Le code VBA

Allez sur la propriété « Sur touche relâchée » cliquez que le bouton de création et sélectionnez Générateur de code et entrez le code suivant :

Private Sub lmFiltre_KeyUp(KeyCode As Integer, Shift As Integer)
'ce n'est pas un caractère A-Z a-z (à affiner) ni un Espace
If (KeyCode < 64 Or KeyCode > 123) And Not KeyCode = 32 And Not Shift=1 Then
   strlist = ""
   Me.lmFiltre.RowSource = "SELECT MSysObjects.Id, MSysObjects.Name " & _ " FROM MSysObjects;"
   Me.lmFiltre.Text = ""
Else
   strlist = strlist & Chr(KeyCode) 'ajoute la touche pressée
   Me.lmFiltre.RowSource = "SELECT MSysObjects.Id, MSysObjects.Name " & _ " FROM  MSysObjects where MSysObjects.Name like """ & strlist & "*"";"
End If
End Sub

Pour le fonctionnement nous avons besoin de déclarer une variable publique au formulaire. Placez-vous juste après les premières lignes d’option du module de formulaire.

Option Compare Database
Option Explicit

Dim strlist As String

Comment ça fonctionne ?

A chaque touche appuyée et relâchée, l’évènement « Sur souris relâchée » est invoqué. Le code (KeyCode) de la touche est analysé.
Si c’est 27, soit la touche Echap, on vide le filtre contenu dans strListe et on affecte à la source la requête d’origine ; sans la condition Where.
Si le code est compris entre 64 et 123 (caractère a-z A-Z, chiffres virgule…) on ajoute le code sous forme de caractère ( Chr(KeyCode) ) à la liste et on applique le filtre.
La condition Where utilise un Like. On peut modifier le comportement du filtre en agissant sur les « jokers » du Like.

Conclusion

Voilà c’est posé, il n’y a plus qu’à compiler et tester.

Avertissement

Ce code montre une méthode mais n’est pas parfait, en effet certains caractères ne sont pas pris en compte comme les caractères accentués. A vous de jouer pour les ajouter.

Manipuler des groupes de contrôles

Quoi de plus énervant que la réorganisation de gros formulaires ?

Avec sa capacité de plus de 700 contrôles, heureusement chiffre rarement atteint, les formulaires peuvent devenir de gros machin difficile à modifier et très chronophage lorsqu’il s’agit de réorganiser leurs contrôles.

Depuis la version 2000, et oui ce n’est plus tout jeune, Microsoft a doté le mode création d’ACCESS d’un petit outil sympathique qui permet de grouper/dégrouper des objets.

Attention, il ne s’agit pas d’exploiter cette fonctionnalité dans vos applications, mais de simplement apporter un peu de souplesse et de facilité dans cette tâche ingrate.

Comment ça marche ?

Tout d’abord prenez un gros formulaire, passez en mode Création, puis sélectionnez un groupe de contrôles.

Cliquez sur le ruban Organiser.

grouper0

Puis cliquer sur Taille/Espace pour dérouler le menu.

grouper1

Enfin sélectionnez Grouper.

Maintenant vos contrôles sont groupés, ils ne forment plus qu’un seul ensemble que vous pouvez manipuler. Déplacement, réduction, agrandissement…

Par contre si vous souhaitez régler un contrôle vous devez faire l’opération inverse et sélectionner Dissocier dans le menu.

Notez que ces regroupements sont conservés à la sauvegarde.

A vos souris !

La recherche et les accents en SQL et VBA.

Rechercher dans une base de données avec l’opérateur Like est assez trivial. Avec quelques jokers on arrive à retrouver ce que l’on souhaite. Cependant lorsque on a affaire à des contenus ayant des caractères accentués il est difficile de récupérer à la fois ceux qui en comporte et ceux qui n’en ont pas.

L’objet de ce billet est d’utiliser VBA pour contourner ce problème.

La première chose à faire est de créer une fonction qui va traiter le mot recherché.

Function ConvertAccForLike(strValue As String) As String
' Fabrice Constans (MVP ACCESS) mars 2016
If InStr(1, strValue, "a") > 0 Then
    strValue = Replace(strValue, "a", "[aàâä]")
End If
If InStr(1, strValue, "e") > 0 Then
    strValue = Replace(strValue, "e", "[eéèêë]")
End If
If InStr(1, strValue, "i") > 0 Then
    strValue = Replace(strValue, "i", "[iîï]")
End If
If InStr(1, strValue, "o") > 0 Then
    strValue = Replace(strValue, "o", "[oôö]")
End If
If InStr(1, strValue, "u") > 0 Then
    strValue = Replace(strValue, "u", "[uùûü]")
End If
ConvertAccForLike = strValue
End Function

Dans cette fonction, on recherche la présence des voyelles, une à une, en commençant par le a, ensuite le e, puis le i, etc. Chaque fois que la voyelle est détectée on la remplace par la syntaxe Contient de l’opérateur Like, soit […]

Pour le mot « eleve », la valeur renvoyée sera :

"[eéèêë]l[eéèêë]v[eéèêë]"

Les mots trouvés seront :

eleve, éleve, élève, élevé…

Vous pouvez l’utiliser directement dans objet requête, une source de formulaire, une clause Where d’un OpenForm ou OpenReport comme dans une requête en VBA.

Voici son utilisation :

SELECT * FROM matable WHERE champ1 Like convertAccForLike("eleve");

Evidemment vous pouvez compléter avec les autres jokers.

SELECT * FROM matable WHERE champ1 Like convertAccForLike("eleve?");

Bonne utilisation !

Champ mémo et Export Excel, la galère !?

Si vous avez un jour tenté de lier un source de données MS Access, requête ou table, à Excel, vous avez sûrement été confronté à l’interprétation aléatoire des champs mémo.

Aléatoire ? Pas tant que ça. Il faut savoir que pour réaliser un export à partir du menu DONNEES EXTERNES / Exporter Excel, MS Access ne se base non pas sur la structure du champ mais sur le contenu des premières lignes. Si dans ces premières lignes il rencontre un contenu de plus de 255 caractères il considère ce champ comme mémo (texte long)… et là tout va bien.

Dans le cas contraire, il tronquera tout le reste à 255 caractères qui est la limite du format Texte Court, anciennement Texte. Adieu vos 32 000 caractères suivant !

Info : Un champ Texte Long, anciennement  Mémo, de la base de données 
Jet (Ms ACCESS) et d'une capacité de 65 535 caractères exactement.
Une cellule MS EXCEL en contient tout au plus 32 767.
Il en manquera toujours un peu.

On peut donc oublier l’export CSV ou depuis la commande MS Access, à part faire un tri sur le nombre de caractères de votre champ mémo, si techniquement cela ne pose aucun problème fonctionnellement cela peut ne pas convenir. On ne sera jamais sûr d’avoir la totalité du contenu.

Heureusement, il existe un méthode, certes un peu plus complexe mais également plus efficace. Il s’agit de l’automation. Autrement dit, piloter Excel depuis Access. Il existe une méthode de copie de recordset disponible avec VBA Excel.

CopyFromRecordset

Cette méthode est disponible dans Excel sans ajout de bibliothèque (Références) car il faut le savoir, Excel est un consommateur de Recordset à ses heures.

Voici le code commenté :

Function fInsertInSheet(ByVal strPath As String, 
                        ByVal strFeuille As String, 
                        rst As Recordset2) As Boolean
      '-----------------------------------------------------------------
      ' Procedure : fInsertInSheet
      ' Author    : Fabrice CONSTANS (MVP)
      ' Date      : 21/01/2014
      ' Purpose   : Insère un ou plusieurs enregistrements issu de RST
      '             dans la feuille excel strFeuille du fichier strPath
      '             utilise fFieldFormated() et ADODB
      ' Parameters: strPath = chemin+nom du fichier Xls au format 12.0
      '             strFeuille = la feuille dans laquelle insérer l'enrg
      '             rst = le recordset contenant les données à insérer
      ' Return    : Boolean renvoi vrai si insertion réussie
      '-----------------------------------------------------------------
      '
      'Ecrit le recordset transmis dans la feuille indiquée
          Dim strSql As String
          Dim i As Long
          Dim l As Long
          ' Late Binding (cf mon article)
          Dim oExcel As Object         ' Excel application
          Dim oFeuille As Object       ' la feuille
          Dim oWork As Object          ' le workbook
          Dim boolStateDisplayAlerts As Boolean
          Dim boolStateAskToUpdateLinks As Boolean
          On Error GoTo Errsub
          
          Set oExcel = CreateObject("Excel.Application")
          oExcel.Visible = False
          'enregistre l'état
          boolStateDisplayAlerts = oExcel.DisplayAlerts
          boolStateAskToUpdateLinks = oExcel.AskToUpdateLinks
          'met en mode silentieux
          oExcel.AskToUpdateLinks = False
          oExcel.DisplayAlerts = False
          
          Set oWork = oExcel.Workbooks.Open(strPath) 
          ' ouvre le classeur
          
          Set oFeuille = oWork.Sheets(strFeuille)    
          ' active la feuille
          
          'xlByRows, xlPrevious
          l = 1                     'insertion en ligne 1
          oFeuille.Cells(l, 1).CopyFromRecordset rst 
          'copie recordset
          
          oExcel.Windows(1).Visible = True      
          oWork.Save                            
          'on le sauve

          'remet à l'état d'origine
          oExcel.DisplayAlerts = boolStateDisplayAlerts
          oExcel.AskToUpdateLinks = boolStateAskToUpdateLinks
          
          oExcel.Visible = True
          oExcel.Quit
          
          Set oFeuille = Nothing ' ferme les objet xls
          Set oWork = Nothing
          Set oExcel = Nothing
          fInsertInSheet = True  'ça c'est bien passé !
Exitsub:
         On Error GoTo 0
         Exit Function
              
Errsub:
          fInsertInSheet = False  'il y a un problème

          'ici une gestion d'erreur ou un msg

End Function

Donc voilà un code pas si mystérieux. On ouvre un recordset coté Access et on le copie coté Excel.

ACCESS – Répéter des données dans un état

La répétition de données dans un état peut être une nécessité, c’est souvent le cas pour l’édition d’étiquettes, de formulaires en plusieurs exemplaires ou tout simplement pour des codes barres.

Plusieurs solutions

La première, qui fait plus office de bricolage consiste à dupliquer les enregistrements à la source. Cependant cela nécessite d’avoir une table source dévouée à l’impression, de préparer l’impression en amont et bien sûr de consacrer du temps SGBD et serveur pour cette tâche.

La seconde, celle que nous allons mettre en pratique consiste à utiliser le moteur d’impression des états d’ACCESS pour simuler cette duplication.

Comment procéder ?

Admettons une table composé des 2 colonnes suivantes :

  • ValeurAImprimer qui contient les données à imprimer. (Texte 255)
  • FréquenceImpression un code qui détermine la fréquence d’impression. (Texte 50)

On commence par créer un état simplement basé sur cette table, on cache la zone de texte FréquenceImpression en mettant sa propriété Visible à Non.

Voilà le décors est planté, il n’y a plus qu’à insérer le code VBA correspondant.

Le code

Le code exploite les évènements Sur Ouverture et Sur Formatage, une variable globale, une petite fonction qui peut être facultative comme nous le verrons plus tard et utilise la propriété NextRecord propre aux états ACCESS.

La variable globale va permettre de compter les occurrences imprimées.

Option Compare Database
Option Explicit
Dim cpt As Long

Lors de l’ouverture de l’état la variable est initialisée à 1.

Private Sub Report_Open(Cancel As Integer)
    cpt = 1
End Sub

A chaque préparation de l’impression de la zone détail on analyse ce qui doit être effectué.

Private Sub Détail_Format(Cancel As Integer, FormatCount As Integer)
cpt = cpt + 1 
If cpt <= nbrRepeat(Me.FréquenceImpression) Then 
    Me.NextRecord = False 
Else
    cpt = 1 End If
End Sub

Si le compteur (cpt) n’a pas atteint le nombre de répétition souhaité on réimprime le même enregistrement.
Ce tour de force est effectué grâce à la propriété NextRecord qui, si elle est False, ne charge pas l’enregistrement suivant.

Le nombre de répétition est déterminé par la valeur contenue dans FréquenceImpression.
Dans cet exemple on veut imprimer suivant une périodicité une quantité déterminée d’informations.

Function nbrRepeat(period As String)
Select Case period
    Case "trimestriel"
       nbrRepeat = 3
    Case "annuel"
       nbrRepeat = 1
    Case "semestriel"
       nbrRepeat = 2
End Select
End Function

Par exemple si FréquenceImpression contient « trimestriel » l’enregistrement sera imprimé 3 fois.

Notez que cette dernière fonction peut être paramétrée à votre guise, ne pas exister du tout si vous indiquez directement le nombre dans la colonne FréquenceImpression ou si le nombre d’impression est fixe.

Bonne impression !

ACCESS : se positionner sur l’item d’une liste déroulante en entrant une partie du texte.

Dernièrement, un internaute me demandait s’il était possible de modifier le fonctionnement de l’auto complétion dans les listes déroulante. S’agissant d’une fonctionnalité interne d’ACCESS, il est évident que ce n’est pas possible nativement.

Par contre on peut toujours contourner le problème à l’aide du code VBA. Voici cette astuce basée sur l’utilisation de l’évènement KeyPress (touche pressée) de la liste.

On commence par créer une variable globale dans le formulaire pour stocker les touches pressées.

Option Compare Database
Option Explicit
Dim strList As String   'stocke les keycode

A chaque touche tapée par l’utilisateur, on parcourt la liste à la recherche du premier item correspondant aux caractères saisis.

Private Sub Modifiable1_KeyPress(KeyAscii As Integer)
Dim i As Long
'contrôle les touches
If KeyAscii = 27 Then strList = ""  'Sur Echap vide le contenu
If Not (KeyAscii > 64 And KeyAscii < 123) Then Exit Sub  
'ce n'est pas un caractère A-Z a-z (à affiner)

strList = strList & Chr(KeyAscii)  'ajoute la touche pressée

For i = 0 To Me.Modifiable1.ListCount - 1  'parcours les items
    If Me.Modifiable1.Column(1, i) Like "*" & strList & "*" Then  
       'l'item correspond

       'pour un liste
       'Me.Modifiable1.ListIndex = i  'on s'y positionne

       'pour une liste déroulante
       Me.Modifiable1 = Me.Modifiable1.Column(0, i)

       Exit For  'et on sort
    End If
Next
End Sub

La méthode suivante donne la valeur de la colonne 2 de la ligne i.

Column(1, i)

Likz est un opérateur logique commun à SQL et VBA.

Like "*" & strList & "*"

Par sécurité on vide les caractères saisis sur la prise et la perte du focus.

Private Sub Modifiable1_GotFocus()
strList = "" 'perte du focus on vide la liste de touche
End Sub
Private Sub Modifiable1_LostFocus()
     strList = ""   'perte du focus on vide les keycode
End Sub

Comme vous le voyez, rien de complexe, on utilise juste les nombreuses possibilités d’Access pour contourner le problème. Il va sans dire que l’auto complétion classique de la liste fonctionne toujours.

N’hésitez pas à affiner le contrôle des touches tapées, en effet, dans cet exemple seul l’alphabet classique est pris en compte, il manque les caractères accentués, les chiffres…