VBA : Sélectionner une valeur connue dans une liste

Autant la sélection automatique d’un item dans une liste modifiable est facile grâce à une simple affectation, autant avec une liste classique c’est plus compliqué.

Je vous livre l’astuce consistant à mettre un peu de code dans une liste déroulante reprenant les valeurs de la liste.

Dans l’événement Après MAJ de la liste déroulante ou d’une zone de texte mettre le code VBA ci-dessous :

Dim i As Long 
Dim i_save As Long  
Me.lstMultiple.Selected(0) = True    'désélection de la liste multiple 

For i = 1 To Me.lstMultiple.ListCount - 1  'parcours la liste multiple    Me.lstMultiple.Selected(i) = False      'déselection de l'élement courant   
   If (Me.lstMultiple.ItemData(i) = CStr(Nz(Me.lstRecherche, ""))) Then   
      's'il est identique à ce que je cherche        
      i_save = i  'je repère la ligne     
   End If 
Next 
Me.lstMultiple.Selected(i_save) = True  'en sortant je sélectionne la liste

lstMultiple est la liste classique et lstRecherche est la liste modifiable ou la zone de texte ou vous sélectionnez la valeur à trouver.

L’astuce consiste à parcourir la liste à la recherche de la valeur, d’en capter l’indice de la ligne pour l’affecter à cette même liste.

Bonne utilisation !

VBA : Early ou Late Binding : Qu’est-ce que c’est ? Comment choisir ?

Si vous utilisez des bibliothèques externes à MS Access, comprenez qui ne sont pas distribuées avec MS Access, cet article vous intéresse.

Earlybinding, vous l’utilisez systématiquement sans le savoir.

Pour utiliser une bibliothèque avec MS Access, habituellement on ouvre VBE, l’éditeur de VBA, et on utilise Outils/Références. La liste qui s’affiche dans cette fenêtre sont les bibliothèques disponibles sur le poste. Il suffit de cocher la bibliothèque que l’on souhaite utiliser.

Dans ce cas on utilise le Earlybinding qu’on peut traduire approximativement par liaison en amont. MS Access se comporte alors de la manière suivante. Au moment de l’ouverture de l’application et avant que la première ligne de code de l’application ne  s’exécute, MS Access va vérifier que les bibliothèques requises existent. Il va sans dire qu’aucun contrôle n’est possible durant cette phase.

Cela occasionne des problèmes lorsque la bibliothèque n’est pas installée sur le poste cible ou qu’elle a une version différente. Dans ce cas, un message d’erreur s’affiche et l’application ne démarre pas.

Voici l’exemple d’un code en Earlybinding en relation avec la bibliothèque Microsoft Word x.xx Object Library :

Dim wApp As Word.Application 
Dim oDoc As Word.Document 'crée l'objet Word 
Set wApp = CreateObject("Word.Application") 

wApp.Visible = False 
Set oDoc = wApp.Documents.Open(Chemin) 

With oDoc 
   .MailMerge.OpenDataSource Name:="c:\temp\export.csv" ...

On remarque que les objets sont fortement typés lors de leur déclaration.

Latebinding ou comment contrôler la présence des bibliothèques.

Heureusement, le langage VBA dispose de moyen de prévenir l’absence de la bibliothèque au moyen du Latebinding ou liaison tardive.

Avec le LateBinding la bibliothèque n’est plus déclarée avant, c’est à dire dans les références, mais bel et bien dans le code au moment de son utilisation. Les objets ne sont plus fortement typés mais reçoivent le type générique Object. De même éventuelles constantes ne sont plus disponibles, il faudra donc les recréer.

Voici un cas concret d’une transformation Early vers Late pour palier un problème de version d’Office lors d’une automation avec Word.

On recrée les constantes correspondantes à la bibliothèque Microsoft Office x.xx Object Library.

Option Compare Database 
Option Explicit 

Const wdDoNotSaveChanges = 0 
Const wdExportFormatPDF = 17

Les objets sont typés de manière générique.

'Debug 'Dim wApp As Word.Application 
'Dim oDoc As Word.Document 'Exploitation 
Dim wApp As Object 
Dim oDoc As Object 

Set wApp = CreateObject("Word.Application") 

wApp.Visible = False 
Set oDoc = wApp.Documents.Open(Chemin) 
With oDoc .MailMerge.OpenDataSource Name:="C:\export.csv" ... 
.Close (wdDoNotSaveChanges)

Notez la mise en commentaires des lignes Earlybinding pour permettre une maintenance/évolution facilité.

Cette technique permet, dans la limite de la compatibilité des bibliothèques, de déployer l’application sur n’importe quel Office puisque le code n’est plus attaché à une version unique de Word.

Dans les références on peut se passer de la déclaration comme on peut le voir ci-dessous.

Voici un cas concret d’une vérification de présence de Word lors de l’ouverture d’un formulaire.

Private Sub Form_Open(Cancel As Integer) 

On Error GoTo ErrSub 
Dim wApp As Object 
Set wApp = CreateObject("Word.Application") 
Set wApp = Nothing 
Exit Sub 

ErrSub: 
If Err.Number = 429 Then 
   MsgBox "Vous devez disposer de Word pour utiliser cette fonctionnalité." 
   vComposant = False 
End If 

End Sub

L’erreur 429 est remontée lorsqu’une bibliothèque est absente.

Conclusion

Si le LateBinding est préférable pour une application en exploitation, il n’en va pas de même lors du développement. En effet le Earlybinding donne accès à l’autocomplétion, ce qui est un confort non négligeable dans cette phase du projet.

Astuce : Connaitre l’équivalent VBA d’une propriété

Je vous livre une petite astuce simple pour connaître l’équivalent d’une propriété d’un formulaire ou d’un état en VBA.

En mode création, placez-vous sur la propriété voulue, puis pressez la touche F1.

Vous aurez l’équivalent VBA de la propriété, son utilité et souvent un exemple de code.

Bonne utilisation !

Tour Booking Software

Votre activité est le booking d’artistes, vous recherchez un logiciel pratique, puissant sans être un gouffre financier. Tour Booking Software est pour vous. Ce logiciel permet de gérer votre activité de booking précisément grâce à ses fonctionnalités. De la gestion des artistes et des autres intervenants du spectacle à la gestion des contrats et factures votre activité devient claire et rapide à gérer. Voici les fonctionnalités :

  • gestion des compagnies (artistes, salles/festivals.., promoteurs, autres : hôtel, transporteur, maison de disque…)
  • gestion des évènements (multi artiste)
  • gestion des prestations de l’événement
  • gestion multi devises (euros, livres…)
  • gestion de la tva
  • gestion des contrats avec 2 types de contrats possibles (« location » de l’artiste en direct ou bien le booker organise le show)
  • gestion des factures (générées directement à partir du contrat ou de manière indépendante)
  • gestion des paiements
  • génération du document récapitulatif à destination de l’artiste.
  • génération des contrats et factures en PDF à partir de modèles WORD.
  • gestion des modèles (certaines formules sont répétitives, vous pouvez les stocker et les rappeler dans certaines zones de saisies)
  • mailer (en émission uniquement). Vous pouvez envoyer vos contrats factures ou tout autres documents d’un simple clic à vos correspondants privilégiés et vous en recevez une copie directement sur votre messagerie.
  • Tableau de bord :
    • planning de suivi des événements
    • suivi des événements
    • suivi des contrats
    • suivi des factures/paiements
  • Liste de recherche et de filtrage des informations principale avec des fonctions d’export au format CSV, d’envoi de mail (compagnies, événements, contrats, factures, paiements, Comptabilité).
  • Classement des documents générés

LA PAYE des artistes N’EST PAS GÉRÉE. Cette application fonctionne sur PC équipé de Windows uniquement.

VBA : Afficher/Cacher le ruban à la demande

Cette fois-ci je vous livre l’une de mes astuces que j’utilise systématiquement dans toutes mes applications : Afficher/Cacher le ruban à la demande.

La méthode est simple, une variable globale permet de fixer l’état du ruban. Un raccourci dans une macro Autokey permet de changer l’état du ruban et une fonction VBA affiche ou cache le ruban suivant l’état de la variable.

Option Compare Database 
Option Explicit 

Dim StateRibbon As Boolean 

Function DisplayRibbon() 
' Auteur : Fabrice CONSTANS (MVP) 
' Description : Affiche/cache le ruban 
' ctrl+shift+R 
Nz StateRibbon, False  
' 1er passage initialise à faux 
' (ribbon invisible) 
DoCmd.ShowToolbar "Ribbon", IIf(StateRibbon, acToolbarNo, acToolbarYes) 
StateRibbon = Not StateRibbon  ' inverse la valeur 

End Function

Le raccourci :

+^{R}  ExecuterCode DisplayRibbon()

Cacher le ruban permet de cacher également les boutons Restaurer/ Fermer ce qui donne une touche professionnelle à l’application.

Bonne utilisation !

VBA : Connaître le nom du formulaire/état et le contrôle actif

Dans la rubrique d’assistance à la maintenance d’application voici un bout de code à coupler à une macro  AutoKeys.

Lorsque vous devez intervenir sur une vieille application ou une application volumineuse, ce code vous rendra le service de ne pas avoir à chercher le formulaire et le contrôle actif parmi les multitudes de bibliothèques et de formulaires ou états. Cerise sur le gâteau si vous ouvrez l’éditeur VBA vous serez automatiquement positionné sur son module.

Son fonctionnement est simple ; Il repère le nom retourné par Screen.Activeform et Screen. Activecontrole et essaye de trouver le code dans le VBE components.

Function msgNameBase() 
' Auteur : Fabrice CONSTANS MVP 
' Description : renvoie le nom : de l'objet, de la base pour l'objet 
' actif 
On Error GoTo Err_msgNomBase 

Dim strNomBase As String 
Dim sCurfrm As String, sExt As String 
Dim sCurControle As String 
Dim i As Integer 

sExt = "form_" ' c'est un formulaire par défaut. 
' recupère le nom du forms, si c'est un report ' il part en erreur (voir traitement des erreurs) 

sCurfrm = Screen.ActiveForm.Name 
sCurControle = Screen.ActiveControl.Name 

' si le nom n'existe pas (voir erreur) 
Curfrm = Application.VBE.VBProjects(i).VBComponents(sExt & _ sCurfrm).Name 
GoTo Exit_msgNomBase Err_msgNomBase: 

' TRAITEMENT POUR UN ETAT. 
If Err = 2475 Then 
   ' ce n'est pas un form (2476 ce n'est pas un report) 
   ' on capture le nom du report sCurfrm = Screen.ActiveReport.Name 
   ' le prefixe pour un report  
   sExt = "Report_" Resume Next 

   ' on continue 
ElseIf Err = 9 Then 
   'Erreur 
   i = i + 1 
   If i > Application.VBE.VBProjects.Count Then 
      MsgBox "Impossible de trouver " & sCurfrm & _ " dans l'application." 
      Exit Function 
   End If 

   Resume 
ElseIf Err > 0 Then 
   MsgBox "Erreur non prévue :" & Err.Number & "---" & _ Err.Description 
   Exit Function 
End If 
Exit_msgNomBase: 
MsgBox IIf(sExt = "form_", "Forms", "Report") & " : " & _ sCurfrm & vbCrLf & _ "Controle : " & sCurControle & vbCrLf & _ "Base : " & Application.VBE.VBProjects(i).Name 

End Function

L’intérêt est évidemment de pouvoir le déclencher n’importe quand dans l’IHM, c’est pour cela qu’il faut le coupler à une macro AutoKeys.

Bonne utilisation !

VBA : Désélection zone de liste

Lorsque vous utilisez une zone de liste sans sélection multiple, il peut arriver d’avoir besoin de désélectionner la ligne. Inutile de vous acharner sur la ligne sélectionnée avec votre souris, elle restera en surbrillance.

Je vous livre ici ma méthode pour enlever la sélection :

Dim itSel As Integer 

Private Sub Form_Open(Cancel As Integer) 
   'initialise à -1 pour ne pas perturber la première sélection 
   itSel = -1 
End Sub 

Private Sub Liste_Click() 
   'la selection est identique à la précédent 
   If Me.Liste.ListIndex = itSel Then 
      Me.Liste.ListIndex = -1 
      'on déselectionne itSel = -1 
   Else 
      'on fixe le choix pour la prochaine comparaison 
      itSel = Me.Liste.ListIndex 
   End If 
End Sub

La liste se nomme Liste. On déclare une variable globale au  formulaire, que l’on nomme itSel, elle permettra de conserver le précédent choix opéré, soit un entier positif pour une sélection et -1 pour la dé-sélection.

Sur l’ouverture du formulaire on considère que rien n’est sélectionné et on attribue la valeur -1 à itSel. Lorsqu’on clique sur la zone de liste, on vérifie si le clic correspond à la sélection en cours au moyen de la propriété ListIndex.

Cette propriété retourne un entier de 0 à x ou x est le dernier item de la liste. Lorsque qu’on attribue une valeur à ListIndex l’item correspond est sélectionné, par contre si l’on met -1 aucune ligne n’est sélectionnée.

Bonne utilisation !

ACCESS : Réparer un fichier accdb ou mdb

Avec Microsoft Access, il peut arriver d’avoir du code VBA lié aux formulaires ou aux états qui ne soit plus accessible ou qui provoque des erreurs inexplicables. C’est rageant ! Surtout que les moyens de réparation sont rares. Je vous livre ici une méthode qui, pour moi, a fait ses preuves dans de nombreux cas. Cela consiste à traiter le fichier avec deux commandes.

Attention vous devez traiter uniquement une copie de la base endommagée. C’est pour cette raison que le fichier est copié avant d’être traité.

Voici donc un batch (.cmd) qui peut être utilisé directement par Windows.

rem @echo off 
echo --------------- GUIDE D'UTILISATION -------------------------------- 
echo Copiez ce fichier dans le répertoire racine à traiter. 
echo Decompile et compacte le fichier. 
echo Enfoncé la touche Shift pour la première passe. 
echo -------------------------------------------------------------------- 
echo AUTEUR : FABRICE CONSTANS MVP 

copy %1 %1.sav 
SET NoExecuteApplication = "Oui" 
"C:\Program files\Microsoft Office\OFFICE14\MSACCESS.EXE" %1 /Decompile 
"C:\Program files\Microsoft Office\OFFICE14\MSACCESS.EXE" %1 /Compact 
SET NoExecuteApplication=

Faites-glisser la copie de votre application sur le batch en maintenant le shift appuyé pour éviter l’exécution du code. Lorsque la barre de progression d’Access est terminée fermez l’application pour démarrer le compactage. Vous décompilez (reconstruction des liens VBA) et compactez la base. Vous pouvez l’utilisé à partir de la version 97.

Notez que suivant la version d’Access vous devrez remplacer le chemin MSACCESS.EXE par le votre.

NoExecuteApplication permet à votre application de ne pas s’exécuter lors de ce traitement. Il faut dans l’application prévoir ce cas en utilisant ce code dans votre procédure de démarrage de l’application :

'debogage, decompil, compactage 
If Not Environ("NoExecuteApplication") = "" Then 
   'autres traitements possibles en post livraison 
   Application.Quit 
   'quitte 
End If

Bonne utilisation !

ACCESS : Contrôle OLE lié et application manquante

Dans les applications MS Access, il peut arriver d’avoir des contrôles OLE liés à des applications qui ne sont pas ou plus installées. Dans ce cas, toutes les tentatives d’interventions se soldent par le message :

Impossible de modifier cette propriété : elle est en lecture seule.

ou encore.

Le serveur OLE n'est pas inscrit. Pour l'inscrire, réinstallez-le.

Une seule méthode pour s’en débarrasser :

Clic-droit sur l’objet, Remplacer par…, Image

Un joli message s’affiche :

Vous ne pouvez pas annuler cette opération et ne pourrez plus modifier cet objet.

Cliquez sur Oui.

Votre objet est à nouveau accessible mais bien entendu, pas avec l’application originelle puisque celle-ci n’est pas installée.

Bonne utilisation !

VBA : Rechercher un mot dans toutes les requêtes

Les modifications d’une application conséquente sont souvent difficiles à réaliser, surtout dans le cas des requêtes. Dans ce billet je vous propose un bout de code pour rechercher un mot, complet ou non, dans toutes les requêtes d’un fichier MS Access.

Function SnifQuery(Optional strText As String = "") 
   On Error GoTo errSub 
   Dim db As DAO.Database 
   Dim qry As DAO.QueryDef 

   Set db = CodeDb 

   ' si rien n'est transmis on demande le mot 
   If strText = "" Then 
      strText = InputBox("Indiquez le mot à rechercher dans les requêtes." & _ 
           vbCrLf & "Ce mot peut être incomplet.", "Mot à rechercher", "") 
      If strText = "" Then Exit Function 
   End If 

   ' balaye toutes les requêtes 
   For Each qry In db.QueryDefs 
      'si on trouve le mot 
      If qry.sql Like "*" & strText & "*" Then 
         ' on ouvre la requête 
         DoCmd.OpenQuery qry.Name, acViewDesign 
      End If 
   Next 

   ' on est propre donc on ferme le chose dont on ne se sert plus. 
   Set qry = Nothing 
   Set db = Nothing 
   Exit Function 
   
   errSub: 
   Resume Next
 
End Function

Pour le lancement vous pouvez passer par la fenêtre Exécution de VBE ou encore créer une macro Autokeys.

  • Ouvrez une nouvelle macro.
  • Affichez la colonne Nom de macro.
  • Entrez le raccourci souhaité. Exemple +^{Q}
  • Dans la colonne Action sélectionnez ExécuterCode.
  • Indiquez dans le nom de la fonction SnifQuery().

Lorsque vous utiliserez Ctrl+Shift+Q la fonction sera appelée.

Attention ce bout de code ne fait pas de recherche dans les requêtes des bibliothèques.

Bonne utilisation !