I. Avant-propos

Access permet de stocker des images directement dans la base de données. Que ce soit en tant que valeur du champ OLE d'une table ou en tant que propriété Image (Picture) d'un formulaire, d'un état ou d'un contrôle de l'un de ces deux objets.

Toutefois, cela peut très vite alourdir la base de données si l'on a un grand nombre d'images en jeu.

cafeine, dans son tutoriel Gestion de photos par formulaire, a montré comment externaliser les images : ce sont les adresses qui sont stockées dans la table et non les images elles-mêmes.

Cafeine s'est concentré sur l'aspect dynamique du traitement : la photo affichée varie au fur et à mesure que le formulaire parcourt les enregistrements de la table qui constitue sa source.

Ici, nous allons aborder le côté statique : l'affichage des images fixes qui décorent les formulaires et les états de la base de données.

Certes le problème du poids de ces images dans la base de données se pose d'une manière moins aiguë que lorsqu'il s'agit de tables contenant des milliers d'enregistrements avec des champs OLE. Cependant pensez à une base avec quelques dizaines de formulaires et autant d'états, tous décorés du logo de l'entreprise : ça commence à peser...

II. L'idée

Exactement la même que celle suivie par Cafeine : c'est l'adresse de l'image qui se trouve dans la base. Le programme va chercher l'image là où elle est stockée physiquement et seulement pour le temps nécessaire à son utilisation.

II-A. De quelles images parle-t-on ?

Celles que l'on affiche sur un contrôle image, un bouton de commande, un bouton bascule, un onglet, ou comme image de fond d'un formulaire ou d'un état.

II-B. Les propriétés que nous allons utiliser

Il s'avère que tous les objets (formulaire ou état) et les différents contrôles qui peuvent contenir une image ont tous trois propriétés en commun.

II-B-1. Propriété Image (Picture)

C'est, en principe, ici que l'on spécifierait le chemin d'une image. Plusieurs types de fichiers sont autorisés, dépendant des filtres d'importation dont vous disposez. Toutefois, les boutons de commande ou de bascule ne peuvent comporter que des images bitmap.

Dans notre cas, nous n'affecterons aucune valeur à cette propriété lors de la construction de l'état ou du formulaire. « (aucune) » apparaîtra en regard de la propriété.

II-B-2. Propriété Type image (PictureType)

Ici, lorsqu'une image a été affectée à la propriété précédente on a le choix entre « Intégré » et « Attaché ».

Si l'on choisit « Intégré », l'image est incorporée dans l'objet et fait partie du fichier de base de données. La taille de la base de données s'accroît alors d'autant d'octets que le fichier image (parfois plus).

Lorsque cette propriété est définie sur « Attaché », la taille de la base de données n'augmente pas, car Access enregistre seulement un pointeur vers l'emplacement.

Lors de la construction de l'état ou du formulaire, nous fixerons la valeur de cette propriété à « Attaché ».

II-B-3. Propriété Remarque (Tag)

Voici une propriété rarement utilisée et pourtant bien pratique ! C'est un pense-bête, vous pouvez y inscrire ce que vous voulez avec un maximum de 2048 caractères. Contrairement aux autres propriétés, le paramétrage de celle-ci n'affecte pas les attributs d'un objet.

Nous allons nous en servir pour y stocker le nom du fichier image que nous voudrons affecter à ce contrôle en temps utile.

On pourrait y inscrire le chemin complet. Toutefois, nous avons opté pour le rassemblement de toutes les images de notre base de données dans un même répertoire que nous logerons dans le même dossier que la base.

Image non disponible

Cette méthode a deux avantages :

  • si on connaît le nom du fichier de l'image, on peut construire de chemin avec l'instruction :
 
Sélectionnez
CurrentProject.Path & "\Images\" & "le contenu de la propriété Remarque"
  • quel que soit le dossier où se situent la base et le répertoire : sur votre PC, une clé USB...

II-C. Déclenchement du processus

Dans l'événement Sur ouverture de l'état ou du formulaire, nous explorerons les propriétés de l'objet et de ses contrôles et chaque fois que nous constaterons que nous avons simultanément :

Nom de la propriété Valeur de la propriété
Picture (Image) (aucune)
PictureType (Type image) 1
Tag (Remarque) De la forme : nom.extension

Nous déclencherons un processus pour modifier temporairement la propriété Picture : nous remplacerons « (aucune) » par le chemin de l'image construit au départ du contenu de la propriété Tag.

Ainsi, si la base est logée dans le répertoire c:\MesBases et que la propriété Tag contient « Fond.jpg », la propriété Picture deviendra : c:\MesBases\Images\Fond.jpg le temps que le formulaire ou l'état concerné restera ouvert.

Ce processus est codé dans la procédure Public Sub AmnImages(). Celle-ci sera appelée lors de l'ouverture de l'état ou du formulaire.

III. La procédure Sub AmnImages()

III-A. YAKA

Dans le meilleur des mondes, elle se présenterait comme ceci pour un formulaire :

 
Sélectionnez
  1. Public Sub AmnImages() 
  2. Dim ctrl As Control 
  3. For Each ctrl In LeFormulaire.Controls 
  4.     If Ctrl.Picture = "(aucune)" And ctrl.PictureType = 1 And ctrl.Tag Like "*.*" Then 
  5.          ctrl.Picture = CurrentProject.Path & "\Images\" & ctrl.Tag 
  6.     End If 
  7.  Next ctrl 
  8. End Sub 

À la ligne 3, on lance une boucle dans la collection des contrôles de l'objet.

À la ligne 4, on vérifie si les trois propriétés ont :
Picture = (aucune) ;
PictureType = 1 ;
Tag = la syntaxe d'un fichier (nom.extension).

À la ligne 5, si les conditions sont remplies, on construit le chemin de l'image et on l'affecte à la propriété Picture.

Attention : cela, c'est sans compter que :

-tous les contrôles n'ont pas ces trois propriétés ;
-le format de l'image proposée est peut-être incompatible avec ce que Access attend ;
-le lien construit pour trouver le fichier de l'image est peut-être mort.

Dans tous ces cas, une erreur sera relevée.

III-B. Actions en cas d'erreur

Type d'erreur Numéro Action correctrice
Le contrôle n'a pas
les trois propriétés

438
Passer au suivant.
Le format est inadéquat
2114
Signaler à l'utilisateur (message ad hoc).
S'il s'agit de l'image de fond de l'objet, laisser « (aucune) ».
S'il s'agit de l'image d'un contrôle, assigner une image par défaut.
Dans les deux cas, passer au contrôle suivant.
Le format est adéquat, mais
l'image est absente

2220
Signaler à l'utilisateur (message ad hoc).
S'il s'agit de l'image de fond de l'objet, laisser « (aucune) ».
S'il s'agit de l'image d'un contrôle, assigner une image par défaut.
Dans les deux cas, passer au contrôle suivant.

Dans le processus de gestion de la survenance éventuelle des erreurs 2114 ou 2220, il conviendra de distinguer si l'on traite l'image de fond de l'objet ou l'image d'un de ses contrôles.

III-C. Le code de la procédure

III-C-1. Une procédure dans un module de classe indépendant des formulaires ou états

Ceci a pour but d'éviter d'inclure un code semblable pour chaque objet. Ce qui facilite la portabilité (puisque plus générique) et la maintenance éventuelle.

Le code de la procédure sera donc logé dans un module.

L'objet y fera appel dans son événement Sur ouverture :

 
Sélectionnez
Private Sub Form_Open(Cancel As Integer)
Call AmnImages
End Sub

Lorsqu'elle se déclenchera, cette procédure doit être capable de déterminer quel est l'objet qui l'appelle. C'est en effet ce formulaire ou cet état spécifique qu'il faut toiletter.

Access dispose de la propriété CodeContextObject pour répondre à ce besoin. Elle permet de déterminer dans quel objet du code Visual Basic est en cours d'exécution.

Quand la routine AmnImages() s'exécute : CodeContextObject représente l'objet qui a déclenché l'exécution. Il hérite alors de toutes les propriétés de ce dernier.

Par exemple, si le formulaire fImagesExternes appelle AmnImages(), nous aurons :

CodeContextObject.name égal à « fImagesExternes » ;
CodeContextObject.Controls représentera la collection des contrôles de fImagesExternes ;
CodeContextObject.picture donnera le chemin de l'image de fond.

III-C-2. Construisons le code pas à pas

Il faut d'abord déclarer les variables et donner l'étiquette où l'on gère les erreurs :

 
Sélectionnez
Dim Ctrl As Control         ' pour boucler dans la collection des contrôles
Dim bFond As Boolean    ' nous permettra de savoir si l'on s'occupe ou non de l'image de fond 
On Error GoTo GestionErreur

On s'occupe ensuite de l'image de fond de l'objet.

On positionne le flag bFond à True.

Comme il s'agit d'atteindre des propriétés de l'objet (et non d'un contrôle), on utilise les propriétés de CodeContextObject.

 
Sélectionnez
bFond = True
If CodeContextObject.Picture = "(aucune)" And CodeContextObject.PictureType = 1 And CodeContextObject.Tag Like "*.*" Then
      CodeContextObject.Picture = CurrentProject.Path & "\Images\" & CodeContextObject.Tag
End If

Si les trois conditions sont remplies (Image = (aucune) ; Type image = Attaché ; Remarque = la structure d'un nom de fichier), on construit le chemin complet de l'image et on l'affecte à la propriété Image de l'objet.

Deux causes d'erreur : le format de l'image est inadéquat (2214) ou l'image est introuvable (2220). Nous expliquerons plus loin comme réagir.

Ensuite, on positionne le flag bFond à False : on va parcourir la collection de contrôles de l'objet :

 
Sélectionnez
ImgControles:            'cette étiquette sera nécessaire pour le traitement des erreurs
bFond = False
For Each Ctrl In CodeContextObject.Controls
     [...]
  Next Ctrl

et pour chaque contrôle, si les trois propriétés ont la valeur ad hoc, on affecte le chemin de l'image :

 
Sélectionnez
If Ctrl.Picture = "(aucune)" And Ctrl.PictureType = 1 And Ctrl.Tag Like "*.*" Then
      Ctrl.Picture = CurrentProject.Path & "\Images\" & Ctrl.Tag
     End If

Trois erreurs sont possibles : le contrôle examiné n'a pas ce type de propriété (438) ; le format de l'image est inadéquat (2214) ou l'image est introuvable (2220).

III-C-3. Gestion des erreurs

On passe en revue les cas possibles :

 
Sélectionnez
Select Case err.Number
       [...]
End Select

438 : le contrôle actuellement examiné n'a pas l'une des propriétés qui nous intéressent.

Rien de spécial, on passe au suivant :

 
Sélectionnez
Case 438  
          Resume Next

2114 : le format de l'image est inadéquat. Il faut distinguer si cette erreur survient

  • soit lors du traitement de l'image de fond : il faut alors prévenir l'utilisateur et continuer avec le processus relatif aux contrôles. Il n'y aura pas d'image de fond ;
 
Sélectionnez
Case 2114 
          If bFond = True Then         
             MsgBox "(2114) L'image de fond de '" & CodeContextObject.Name & "', c'est-à-dire : '" _
                  & CodeContextObject.Tag & "' est d'un format invalide."
             Resume ImgControles
Image non disponible
  • soit lors du traitement de l'image d'un contrôle : il faut alors prévenir l'utilisateur, affecter une image par défaut et passer au contrôle suivant :
 
Sélectionnez
MsgBox "(2114) L'image '" & Ctrl.Tag & "' est d'un format invalide pour le contrôle '" _
                  & Ctrl.Name & "' de l'objet '" & CodeContextObject.Name & "'."
             Ctrl.Picture = CurrentProject.Path & "\Images\Default.bmp"
             Resume Next
Image non disponible

Avant de vérifier si le format est adéquat, Access voit d'abord si le fichier existe.
Donc une image d'un format inadéquat et manquante relèvera une erreur 2220, et non 2114.

2220 : l'image est absente. C'est exactement la même réaction que celle de l'erreur 2214, aux messages d'erreurs près.

 
Sélectionnez
Case 2220 
          If bFond = True Then         'C'est l'image de fond
             MsgBox "(2220) L'image de fond de '" & CodeContextObject.Name & "', c'est-à-dire : '" _
                  & CodeContextObject.Tag & "' est absente."
             Resume ImgControles
          Else
             MsgBox "(2220) L'image '" & Ctrl.Tag & "' est absente pour le contrôle '" _
                & Ctrl.Name & "' de l'objet '" & CodeContextObject.Name & "'."
             Ctrl.Picture = CurrentProject.Path & "\Images\Default.bmp"
             Resume Next
          End If
Image non disponible
Image non disponible

Enfin, on peut utiliser ceci pour les erreurs non prévues :

 
Sélectionnez
Case Else
          MsgBox "Erreur inattendue dans AmnImages" & vbLf _
               & err.Number & " : " & err.Description, vbCritical

III-C-4. Version finale

 
Sélectionnez
Option Compare Database
Option Explicit
            
Public Sub AmnImages()
Dim Ctrl As Control
Dim bFond As Boolean
On Error GoTo GestionErreur
'Image de fond
bFond = True
If CodeContextObject.Picture = "(aucune)" And CodeContextObject.PictureType = 1 And CodeContextObject.Tag Like "*.*" Then
      CodeContextObject.Picture = CurrentProject.Path & "\Images\" & CodeContextObject.Tag
End If
ImgControles:
'Image des contrôles
bFond = False
For Each Ctrl In CodeContextObject.Controls
     If Ctrl.Picture = "(aucune)" And Ctrl.PictureType = 1 And Ctrl.Tag Like "*.*" Then
      Ctrl.Picture = CurrentProject.Path & "\Images\" & Ctrl.Tag
     End If
  Next Ctrl
Exit Sub
GestionErreur:
Select Case err.Number
       Case 438   ' pas d'image dans le contrôle examiné
          Resume Next
       Case 2114 'format d'image invalide
          If bFond = True Then         'C'est l'image de fond
             MsgBox "(2114) L'image de fond de '" & CodeContextObject.Name & "', c'est-à-dire : '" _
                  & CodeContextObject.Tag & "' est d'un format invalide."
             Resume ImgControles
          Else
             MsgBox "(2114) L'image '" & Ctrl.Tag & "' est d'un format invalide pour le contrôle '" _
                  & Ctrl.Name & "' de l'objet '" & CodeContextObject.Name & "'."
             Ctrl.Picture = CurrentProject.Path & "\Images\Default.bmp"
             Resume Next
          End If
       Case 2220  'L'image est absente
          If bFond = True Then         'C'est l'image de fond
             MsgBox "(2220) L'image de fond de '" & CodeContextObject.Name & "', c'est-à-dire : '" _
                  & CodeContextObject.Tag & "' est absente."
             Resume ImgControles
          Else
             MsgBox "(2220) L'image '" & Ctrl.Tag & "' est absente pour le contrôle '" _
                & Ctrl.Name & "' de l'objet '" & CodeContextObject.Name & "'."
             Ctrl.Picture = CurrentProject.Path & "\Images\Default.bmp"
             Resume Next
          End If
       Case Else
          MsgBox "Erreur inattendue dans AmnImages" & vbLf _
               & err.Number & " : " & err.Description, vbCritical
End Select
End Sub

IV. Encore une suggestion

Si votre propos est d'afficher une image à l'écran en dehors de votre formulaire, pensez à l'instruction :

 
Sélectionnez
shell "C:\WINDOWS\EXPLORER.EXE " & "Chemin de l'image", vbNormalFocusc

ce qui équivaut à un double-clic sur le nom du fichier dans l'Explorateur Windows.

V. Téléchargez une base de données avec un exemple

Vous trouverez ici, un exemple d'application pour illustrer tous les cas possibles :

  • un formulaire (fImagesExternes) qui contient à la fois des images incorporées et des images externes. Dans ce formulaire, si vous double-cliquez sur un contrôle de type « Imagexxx », l'image renseignée dans la propriété Remarque s'affichera à l'écran avec le logiciel associé à ce type de fichier ;
  • un formulaire (fImagesExternes) qui contient lui-même un sous-formulaire (sfImEx) tous deux faisant appel à la routine AmnImages() ;
  • un état (eImEX).

    Vous devez décompresser l'archive dans un dossier qui contiendra la base de données ImagesExternes.mdb et le répertoire Images.

  • N.B. À l'ouverture du formulaire, une série de messages d'alerte : dans l'exemple, des images sont volontairement absentes pour montrer la réaction du formulaire dans de telles circonstances.

VI. Remerciements

Merci à l'équipe Office, pour sa collaboration dans la réalisation de ce tutoriel et à Maxime Gault (Max) et Fabian Piette (bifconsult) pour en avoir corrigé le texte.