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.
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 :
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 :
2.
3.
4.
5.
6.
7.
8.
Public
Sub
AmnImages
(
)
Dim
ctrl As
Control
For
Each
ctrl In
LeFormulaire.Controls
If
IsNull
(
Ctrl.PictureData
) And
ctrl.PictureType
=
1
And
ctrl.Tag
Like "*.*"
Then
ctrl.Picture
=
CurrentProject.Path
&
"\Images\"
&
ctrl.Tag
End
If
Next
ctrl
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 |
438 |
Passer au suivant. |
Le format est inadéquat |
2114 |
Signaler à l'utilisateur (message ad hoc). |
Le format est adéquat, mais |
2220 |
Signaler à l'utilisateur (message ad hoc). |
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 :
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 :
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.
bFond =
True
If
IsNull
(
CodeContextObject.PictureData
) 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 :
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 :
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 :
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 :
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 ;
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
- 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 :
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
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.
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
Enfin, on peut utiliser ceci pour les erreurs non prévues :
Case
Else
MsgBox
"Erreur inattendue dans AmnImages"
&
vbLf
_
&
err
.Number
&
" : "
&
err
.Description
, vbCritical
III-C-4. Version finale▲
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
IsNull
(
CodeContextObject.PictureData
) 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
IsNull
(
Ctrl.PictureData
) 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 :
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.