I. Introduction▲
Les questions touchant à la création de codes-barres sont relativement fréquentes sur le forum Access. Bien que plusieurs réponses aient été données, nombre de discussions demeurent non résolues. Dans la plupart des cas, ce n'est pas faute d'une bonne solution, mais plutôt l'absence de détails et de précisions qui ont fait que beaucoup de membres ont abandonné cette idée.
Cet article a pour but de vous expliquer comment créer des codes-barres, sans utiliser un contrôle ActiveX spécifique ni de police de caractères spéciale, mais uniquement en VBA.
Pour atteindre cet objectif, des connaissances en VBA sont nécessaires, ce qui réserve plutôt cet article à des utilisateurs ayant déjà quelque expérience de la programmation avec ce langage. Il est cependant suffisamment détaillé et le code amplement commenté. Les néophytes ne devraient pas rencontrer de grandes difficultés pour le mettre en œuvre.
II. Généralités▲
Le premier système de codes-barres a été breveté en 1952. Il concernait un code à ligne verticale et aussi de forme concentrique (en forme de cible) ainsi que le système de lecture des données.
Sa première utilisation a été l'étiquetage des wagons de train, sans que le succès commercial ne soit toutefois au rendez-vous.
Il faudra attendre le début des années 1970 et l'invention du code UCP, Universal Product Code ou CUP en français, utilisé dans la grande distribution, pour que leur usage se généralise.
Aujourd'hui, ils sont utilisés dans de nombreux domaines d'activité, par exemple :
- code 11 : télécommunications ;
- code 39 : industrie automobile, pharmacode France, armée américaine ;
- code 128 : transports, santé, pièces détachées pour le secteur automobile.
Cette liste est bien sûr loin d'être exhaustive.
II-A. Les codes-barres▲
À l'origine, les codes-barres sont la représentation, sous forme d'un ensemble de barres et d'espaces, d'une donnée numérique ou alphanumérique, l'épaisseur des barres et espaces variant selon la symbologie utilisée et les caractères de la donnée à coder. Ces codes, linéaires, sont lus horizontalement.
Puis sont apparus des codes linéaires empilés, ainsi nommés car ils sont constitués de plusieurs codes-barres linéaires empilés les uns sur les autres. Ils sont lus verticalement.
Plus récemment, ils ont encore évolué avec l'apparition de codes-barres à deux dimensions (2D), lus horizontalement et verticalement. Ils permettent de coder un grand nombre de données sur une petite surface, jusqu'à plusieurs milliers de caractères pour certains d'entre eux.
Code-barres linéaire | Code-barres linéaire empilé | Code-barres à deux dimensions |
Code-barres 128 | Code-barres PDF 417 | Code-barres Aztec |
II-B. Lecture des codes-barres▲
Pour lire les données ainsi codées, on utilise un lecteur de codes-barres, qui n'est autre qu'un lecteur optique émettant de la lumière :
- le lecteur émet de la lumière qui est absorbée par les barres sombres et réfléchie par les espaces clairs ;
- à l'intérieur du lecteur, une cellule photosensible reçoit la lumière réfléchie et la convertit en signal électrique ;
- le signal est faible pour les espaces clairs et fort pour les barres sombres ;
- la durée du signal détermine la largeur des barres et espaces ;
- un décodeur convertit le signal en caractères ;
- les caractères décodés sont transmis à l'ordinateur.
Différents types de lecteurs de codes-barres :
Stylo optique | Douchette | Scanner |
III. Le code 128▲
Comme nous l'avons vu dans la section précédente, il existe de nombreux types de codes-barres, destinés pour la plupart à des domaines bien spécifiques. Dans le cadre de cet article, nous n'en étudierons qu'un seul, choisi non pas en fonction d'un domaine d'utilisation précis, mais parce qu'il permet de coder un maximum de caractères de manière simple et fiable.
Le choix du code 128 s'est donc imposé presque naturellement. Il permet en effet de coder les 128 caractères ASCII de base, il est omnidirectionnel, il est très dense, notamment pour les valeurs numériques, et possède un caractère de contrôle.
Il ne faut pas confondre le code 128 avec le code EAN (UCC) 128. Ce dernier, basé sur la symbologie du code 128 n'est pas simplement un code-barres, c'est un standard qui définit la manière dont les données sont formatées.
Leur signification est précisée selon une liste d'Identificateurs d'Application, usuellement abrégés AI. Ces derniers, placés au début du code, indiquent ce que contiennent les données elles-mêmes (numéro de colis, date de production, d'emballage, etc.).
Le code EAN 128 est couramment utilisé dans l'industrie pour des besoins de logistique et de traçabilité.
III-A. Les différents caractères du code▲
Il est constitué de 107 motifs différents, représentant 103 caractères de données, trois caractères de démarrage et un caractère d'arrêt. Pour permettre de coder les 128 caractères de la table ASCII, il existe trois ensembles de codes (A, B et C) qui peuvent être mélangés dans un même code-barres par l'utilisation de caractères de permutation (caractères 99, 100 et 101).
Contenu des tables :
- 128A : les chiffres, les lettres majuscules, des caractères de ponctuation, des codes de contrôle et des codes spéciaux ;
- 128B : les chiffres, les lettres majuscules et minuscules, des caractères de ponctuation et des codes spéciaux ;
- 128C : des paires de chiffres, permettant de doubler la densité des caractères numériques, et des codes spéciaux.
La table représentant les trois ensembles de caractères du code est disponible en annexe.
Dans cet article, nous nous limiterons à l'usage des ensembles de caractères B et C, ce qui exclut le codage des 32 premiers caractères de la table ASCII (00 à 31).
III-B. La structure du code▲
Le code 128 est composé de six sections :
- une marge blanche à gauche ou "quiet zone" ;
- un caractère de démarrage ;
- la chaîne de caractères elle-même ;
- un caractère de contrôle ;
- un caractère d'arrêt ;
- une marge blanche à droite ou "quiet zone".
- Les marges ou "quiet zone" à gauche et à droite du code doivent avoir au moins dix modules d'épaisseur ;
- le caractère de démarrage détermine la table utilisée au départ ;
- le caractère, ou clé, de contrôle est obligatoire. Le détail du calcul est exposé ci-après ;
- le caractère d'arrêt est identique, quels que soient les ensembles de caractères utilisés.
III-C. Les modules▲
Comme nous l'avons vu précédemment, le code 128 est constitué de 107 motifs différents, composés chacun de onze modules, groupés en trois barres et trois espaces.
Le caractère d'arrêt est complété par deux modules de barres à son extrémité droite permettant de fermer le code-barres. Il est donc composé de treize modules au total.
Pour encoder les données, on peut considérer que le chiffre "1" représente des barres et le chiffre "0" des espaces. Ainsi la lettre "A" sera symbolisée par "10100011000", soit trois barres et trois espaces de différentes épaisseurs.
III-D. Optimisation du code▲
Un des intérêts du code 128 réside dans la possibilité d'optimiser le codage des données numériques en utilisant un seul caractère pour des paires de chiffres, en recourant à l'ensemble de caractères C.
Ainsi, si "44" nécessite deux fois le caractère "4" dans l'ensemble B, il peut être codé uniquement avec le caractère "L" en recourant à l'ensemble C.
Il faut tenir compte ici des caractères spéciaux permettant de passer d'un ensemble de caractères à l'autre. L'optimisation du code est donc possible pour autant que la donnée à coder :
- commence par quatre chiffres au moins ;
- se termine par quatre chiffres au moins ;
- comprenne six chiffres au moins au milieu de la donnée.
En effet, dans le premier cas, on commence à utiliser l'ensemble C, puis on utilise un caractère de permutation pour passer à l'ensemble B pour coder la suite des données si nécessaire.
Dans le deuxième cas, on commence par l'ensemble B, puis un caractère est utilisé pour passer vers l'ensemble C.
Enfin, dans le troisième cas de figure, deux caractères sont nécessaires pour passer de l'ensemble B vers l'ensemble C, puis à nouveau vers l'ensemble B.
À titre d'exemple, essayons de créer le code pour la donnée ABC2011, tout d'abord sans optimisation de l'encodage, c'est-à-dire en ayant recours uniquement à l'ensemble de caractères B.
Le résultat obtenu est le suivant :
Caractère ASCII | Ñ | A | B | C | 2 | 0 | 1 | 1 |
Caractère | Start B | A | B | C | 2 | 0 | 1 | 1 |
Valeur | 104 | 33 | 34 | 35 | 18 | 16 | 17 | 17 |
Reprenons la même donnée, en optimisant le code cette fois-ci, c'est-à-dire en ayant recours aux ensembles de caractères B et C.
Le résultat est naturellement différent, les quatre caractères numériques étant codés avec deux caractères uniquement :
Caractère ASCII | Ñ | A | B | C | Ì | 4 | + |
Caractère | Start B | A | B | C | Table C | 20 | 11 |
Valeur | 104 | 33 | 34 | 35 | 99 | 20 | 11 |
On voit bien l'intérêt d'optimiser l'encodage, le recours à ce procédé permettant de produire des codes très denses s'agissant de données numériques.
Dans les deux exemples ci-dessus, le caractère de contrôle et le caractère d'arrêt ne sont pas encore compris.
III-E. Le caractère de contrôle▲
Le caractère de contrôle, obligatoire, se calcule selon un schéma bien précis et en utilisant un modulo 103.
En lisant le code de gauche à droite, on commence par prendre la valeur du code de démarrage (103, 104 ou 105) pour les ensembles de caractères A, B ou C respectivement.
Puis, pour chaque caractère suivant, on multiplie la valeur du caractère par la valeur de sa position dans la chaîne, le caractère suivant immédiatement le caractère de démarrage ayant le rang 1.
Caractère ASCII | Ñ | A | B | C | Ì | 4 | + |
Caractère | Start B | A | B | C | Table C | 20 | 11 |
Valeur | 104 | 33 | 34 | 35 | 99 | 20 | 11 |
Position | - | 1 | 2 | 3 | 4 | 5 | 6 |
Multiplication | 104 | 33*1 | 34*2 | 35*3 | 99*4 | 20*5 | 11*6 |
Produit | 104 | 33 | 68 | 105 | 396 | 100 | 66 |
Le résultat de l'addition des produits, 872 dans cet exemple, est divisé par 103, le reste de la division étant la valeur du caractère de contrôle, soit 48.
Ensuite, cette valeur doit être convertie en caractère ASCII en appliquant la méthode suivante :
- si elle est comprise entre 0 et 94, on ajoute 32 ;
- si elle est supérieure à 94, on ajoute 105.
Ici, la valeur étant inférieure à 95, nous ajoutons 32. Le résultat, soit 80, donne le caractère ASCII "P".
Il ne reste alors plus qu'à ajouter ce caractère de contrôle et le caractère d'arrêt pour compléter le code 128 :
Caractère ASCII | Ñ | A | B | C | Ì | 4 | + | P | Ó |
Caractère | Start B | A | B | C | Table C | 20 | 11 | P | Stop |
Nous connaissons maintenant l'intégralité des caractères ASCII que nous devons convertir en barres et espaces pour obtenir le code-barres de la chaîne de caractères ABC2011.
III-F. Les spécifications▲
Il s'est avéré difficile de trouver des spécifications pour les codes-barres 128. La plupart de celles trouvées sur Internet sont le fait de fournisseurs de polices de caractères, de lecteurs de codes-barres ou encore d'imprimantes.
Il existe cependant des spécifications plus officielles, par exemple la norme française et européenne NF EN 799, applicable entre autres à l'impression des N° RPPS et N° AM des ordonnances médicales.
Le but de cet article n'est toutefois pas de produire des codes-barres pour un usage spécifique. Aussi, les indications fournies ci-après sont plutôt une synthèse des divers renseignements trouvés. Elles devraient permettre d'imprimer des codes-barres lisibles par la grande majorité des lecteurs disponibles sur le marché.
Il n'est non plus pas nécessaire de disposer d'une imprimante haut de gamme pour imprimer vos codes-barres. Laser ou jet d'encre, n'importe quelle imprimante suffit aujourd'hui à cette tâche.
III-F-1. Légende du code-barres▲
Le code-barres peut être légendé ou non.
III-F-2. Largeur des modules et du code-barres▲
La dimension X d'un module devrait être de 7.5 millièmes de pouce au minimum.
Sachant qu'un pouce est égal à 1440 twips ou 2.54 cm, un millième de pouce est égal à 1.44 twip. La dimension X minimum d'un module est donc d'environ 10.8 twips.
Bien qu'il soit tout à fait possible de lire des codes-barres ayant des modules de 10 twips, dans l'application, nous utiliserons une valeur par défaut de 12 twips, ce qui devrait garantir une lecture par tout type de matériel.
Ceci est en principe largement suffisant. Pour une donnée de 25 caractères par exemple, soit 28 caractères en tenant compte des caractères de démarrage, de contrôle et d'arrêt, la largeur du code-barres n'excède pas 6.56 cm.
La largeur des codes-barres n'est en théorie pas limitée. Vous devez cependant être attentif aux caractéristiques techniques de votre lecteur de codes-barres.
Certaines douchettes ne peuvent par exemple pas lire des codes-barres de plus de 7.5 cm de largeur.
III-F-3. Hauteur des modules▲
La symbologie du code 128 ne spécifie pas de hauteur maximum pour les modules. Il serait toutefois faux de croire que plus la hauteur d'un code-barres est importante, plus celui-ci est lisible.
La hauteur minimum du code-barres devrait être de 15 % de la longueur de ce dernier ou 0.25 pouce, soit environ 0.6 cm, la valeur la plus élevée étant retenue.
Pour la hauteur maximum, on peut se limiter à 0.5 pouce, soit environ 1.3 cm. Dans l'application exemple, elle est au plus de 1 cm, que la hauteur des modules soit fixe ou variable.
III-F-4. Spécifications de vos codes-barres ▲
Comme cela a été précisé, les spécifications ci-dessus n'ont rien d'officiel. Il vous faudra donc faire vos propres tests pour obtenir les meilleurs résultats possible.
Les lecteurs de codes-barres sont généralement livrés avec une documentation contenant des codes témoins, permettant soit de calibrer le lecteur, soit de faire des simples tests de lecture.
Si un code-barres 128 est donné en exemple, l'étude de celui-ci vous fournira de précieuses indications (hauteur et largeur des modules) pour la création de vos propres codes-barres.
IV. L'application de création des codes-barres▲
Après cette introduction théorique, nous pouvons passer à la création de l'application !
Celle-ci est assez modulaire, de sorte que vous devriez pouvoir l'intégrer facilement dans une application existante.
Elle est composée :
- d'une table ;
- d'un formulaire et de son module (quatre procédures) ;
- d'un état et de son module (deux procédures) ;
- d'un module de code contenant une procédure et deux fonctions nécessaires à l'encodage et au traçage des codes-barres.
IV-A. Table▲
On commence par créer une table tblCodesBarres avec trois champs :
- IdCodesBarres, de type NuméroAuto, qui est la clé primaire de la table ;
- CodesBarres, de type Mémo, pour enregistrer les modules du code-barres ;
- Libelle, de type Texte (taille 50), pour enregistrer le libellé du code.
Si vous êtes certains que le nombre de modules de vos codes-barres sera toujours égal ou inférieur à 255, vous pouvez bien sûr utiliser un champ de type Texte pour le champ CodesBarres.
IV-B. Formulaire▲
On peut ensuite passer à la création du formulaire frmCodeBarres et modifier les propriétés qui nous intéressent.
On notera principalement qu'il est indépendant, qu'il n'a pas de barres de défilement, ni de sélecteur et de diviseurs d'enregistrements.
Outre des cadres et étiquettes, on y place quatre zones de texte et une zone de liste déroulante, indépendantes elles aussi :
- txtChaineCaracteres va nous permettre de saisir les caractères du code-barres ;
- txtEtiquetteDebut indique la position de la première étiquette à imprimer. La propriété Valeur par défaut de cette zone de texte est fixée à 1 ;
- txtNbEtiquettes définit le nombre d'étiquettes désirées. La propriété Valeur par défaut de cette zone de texte est fixée à 16 ;
- cboHauteurModules permet de choisir le type de hauteur des modules, soit "Variable", en fonction de la longueur du code, soit "Fixe", qui est aussi la Valeur par défaut ;
- txtLargeurModules fixe la dimension X ou largeur des modules, exprimée en twips. La propriété Valeur par défaut de cette zone de texte est fixée à 12.
Puis on ajoute deux images et un bouton avec sa propriété Transparent à Oui, qu'on superpose les uns aux autres dans cet ordre, en commençant par l'arrière-plan :
- imgTracageVertical ;
- imgTracageHorizontal ;
- cmdTracage.
Ces trois éléments vont nous permettre, sur clic du bouton cmdTracage, de sélectionner le mode de traçage des colonnes.
Enfin, on ajoute encore un bouton, cmdApercuImpression, qui ouvre l'état rptEtiquettes en mode Aperçu avant impression.
Ci-dessous, l'aspect définitif du formulaire :
IV-C. État▲
Enfin, on crée un état rptEtiquettes, ayant comme Source la table tblCodesBarres.
Pour l'application exemple, le choix s'est porté sur un modèle de deux étiquettes de front. Après ajustement des dimensions, celles-ci sont d'environ 94 x 34 mm, soit seize étiquettes au total.
On y place ensuite deux zones de texte, ayant respectivement comme Source contrôle les champs CodeBarres et Libelle.
Ensuite de quoi nous renommons les deux zones de texte txtCodeBarres et txtLibelle.
Aperçu de l'état en mode Création :
Il est utile de commenter quatre propriétés de la zone de texte txtCodeBarres.
Tout d'abord, celle-ci n'est pas visible. En effet, on ne veut pas afficher la chaîne de caractères du code-barres dans la zone de texte, mais tracer le motif de celui-ci au-dessus de celle-ci, en utilisant le coin supérieur gauche comme point d'origine. La propriété Visible est fixée à Non.
D'autre part, il est possible de tracer des codes-barres de hauteur proportionnelle à la longueur du code ou de taille fixe.
Cette dernière option implique que les propriétés Auto extensible et Auto réductible soient fixées à Non également.
Toujours dans le cas où on désire tracer des codes-barres de hauteur fixe, c'est la propriété Hauteur qui sera déterminante, ici, 1 cm.
Propriétés de la zone de texte :
Si le champ CodeBarres et de type Mémo et que vous créez votre état avec l'Assistant Étiquettes, il est possible que celui ne soit pas proposé dans la liste des champs. Il est donc nécessaire de l'ajouter manuellement par la suite en modifiant votre état.
IV-D. Fonctions et procédures▲
Nous passons maintenant aux différentes fonctions et procédures de l'application.
IV-D-1. Entête de module (déclaration des variables publiques)▲
Comme on va le voir ultérieurement, certaines variables sont utilisées dans plusieurs modules. Elles doivent donc être déclarées comme Public dans l'entête d'un module, afin de pouvoir être reconnues dans tout le projet.
On crée donc un module de code et on le sauvegarde sous le nom de basCodesBarres. Dans la section Déclaration, on déclare cinq variables qui vont permettre de stocker les valeurs suivantes :
- le mode de traçage des colonnes ;
- le type de hauteur du code-barres ;
- la hauteur des modules ;
- la largeur des modules ;
- la largeur du code-barres.
Option
Compare Database
Option
Explicit
'Déclaration des variables publiques
'Mode de traçage des colonnes de l'état
Public
lngTracageColonne As
Long
'Type de hauteur du code-barre : fixe ou variable
Public
strHauteurCodeBarres
'Hauteur des modules de barre ou d'espace (twips)
Public
lngHauteurModule As
Long
'Largeur des modules de barre ou d'espace (twips)
Public
lngTailleModule As
Long
'Largeur du code-barres (twips)
Public
lngLargeurCodeBarres As
Long
IV-D-2. Événement Sur ouverture du formulaire▲
Lors de l'ouverture du formulaire frmCodeBarres, on affecte à la variable publique lngTracageColonne la valeur de la propriété ItemLayout de l'objet Printer, ce qui détermine le sens de traçage des colonnes.
Puis, en fonction de cette valeur, on affiche l'image correspondante, imgTracageVertical ou imgTracageHorizontal, et on modifie la légende de l'étiquette lblTracageColonnes.
Private
Sub
Form_Open
(
cancel As
Integer
)
On
Error
GoTo
GestionErreurs
'Vérification du mode de traçage des colonnes renvoyé par défaut par l'imprimante
'Traçage horizontal = acPRHorizontalColumnLayout = 1953
'Traçage vertical = acPRVerticalColumnLayout = 1954
lngTracageColonne =
Printer.ItemLayout
'Affichage de l'image correspondant au mode de traçage
'et modification de la légende de l'étiquette
If
lngTracageColonne =
1953
Then
Me.imgTracageHorizontal.Visible
=
True
Me.imgTracageVertical.Visible
=
False
Me.lblTracageColonnes.Caption
=
"Vers la droite, ensuite vers le bas"
Else
Me.imgTracageVertical.Visible
=
True
Me.imgTracageHorizontal.Visible
=
False
Me.lblTracageColonnes.Caption
=
"Vers le bas, ensuite vers la droite"
End
If
'Sortie de la procédure
Exit
Sub
GestionErreurs
:
'Affichage d'un message
MsgBox
"Une erreur inattendue s'est produite !"
&
vbNewLine
&
"Erreur no : "
_
&
Err
.Number
&
vbNewLine
&
Err
.Description
, vbCritical
, "Erreur !"
End
Sub
Le mode de traçage des colonnes peut être modifié après l'ouverture du formulaire.
IV-D-3. Événement Sur clic du bouton Format des colonnes▲
Rappelons que ce bouton placé au-dessus des images n'est pas visible puisque sa propriété Transparent et fixée à Oui.
Cette procédure est pratiquement identique à la précédente. Elle modifie la valeur de la variable publique, l'image affichée et la légende de l'étiquette.
Private
Sub
cmdTracage_Click
(
)
On
Error
GoTo
GestionErreurs
'Modification de la valeur de la variable publique,
'affichage de l'image correspondant au mode de traçage
'et modification de la légende de l'étiquette
If
lngTracageColonne =
1953
Then
lngTracageColonne =
1954
Me.imgTracageVertical.Visible
=
True
Me.imgTracageHorizontal.Visible
=
False
Me.lblTracageColonnes.Caption
=
"Vers le bas, ensuite vers la droite"
Else
lngTracageColonne =
1953
Me.imgTracageHorizontal.Visible
=
True
Me.imgTracageVertical.Visible
=
False
Me.lblTracageColonnes.Caption
=
"Vers la droite, ensuite vers le bas"
End
If
'Sortie de la procédure
Exit
Sub
GestionErreurs
:
'Affichage d'un message
MsgBox
"Une erreur inattendue s'est produite !"
&
vbNewLine
&
"Erreur no : "
_
&
Err
.Number
&
vbNewLine
&
Err
.Description
, vbCritical
, "Erreur !"
End
Sub
IV-D-4. Événement Sur clic du bouton Aperçu - 1re partie▲
Dans les différents contrôles du formulaire, on saisit la chaîne de caractères que l'on veut coder, la position d'impression de la première étiquette et le nombre désiré de celles-ci, ainsi que le type de hauteur souhaité et la largeur des modules du code-barres.
Une fois tous les champs renseignés et le mode de traçage des colonnes sélectionné, on peut cliquer sur le bouton cmdApercuImpression.
On commence par définir un Recordset et les cinq variables de la procédure.
Ne pas oublier d'ajouter la référence Microsoft DAO 3.6 Object Library ou Microsoft Office 12.0 (14.0) Access database engine Object Library pour Access 2007 et Access 2010 au projet. En l'absence de celle-ci, il n'est pas possible d'utiliser un objet Recordset.
Private
Sub
cmdApercuImpression_Click
(
)
'Déclaration de l'objet et des variables
Dim
db As
DAO.Database
Dim
rst As
DAO.Recordset
Set
db =
CurrentDb
Set
rst =
db.OpenRecordset
(
"select * from tblCodesBarres"
)
'Variable recevant le code 128, après encodage de la chaîne de caractères
Dim
strChaine As
String
'Variable recevant successivement chaque caractère du code 128, avant leur conversion
Dim
strCaractere As
String
'Variable recevant successivement les caractères du code 128, après conversion
Dim
strBarres
'Variable contenant le code 128 converti
Dim
strCodeBarres As
String
'Variable de compteur
Dim
i As
Long
Ensuite, on affecte le type de hauteur du code-barres à la variable publique strHauteurCodeBarres et on fait de même avec la variable lngTailleModule qui reçoit comme valeur la largeur des modules, en twips.
On
Error
GoTo
GestionErreurs
'Le type de hauteur du code-barres est affecté à la variable strHauteurCodeBarres
strHauteurCodeBarres =
Me.cboHauteurModules
'La largeur des modules est affectée à la variable lngTailleModule
lngTailleModule =
Me.txtLargeurModules
Puis, on supprime les enregistrements existants de la table tblCodesBarres.
'Suppression des enregistrements de la table tblCodesBarres
CurrentDb.Execute
"DELETE tblCodesBarres.CodeBarres FROM tblCodesBarres;"
, dbFailOnError
L'étape suivante consiste à coder la chaîne de caractères en code 128. Pour cela, on appelle la fonction Code128, en passant la chaîne de caractères en argument.
'Encodage de la chaîne de caractères en code 128
strChaine =
Code128
(
Me.txtChaineCaracteres
)
IV-D-5. Fonction d'encodage de la chaîne de caractères en code 128▲
Hormis certains caractères spéciaux (0 à 31 de la table ASCII), tous les autres caractères de la table ASCII de base sont disponibles dans la table B. On pourrait donc se limiter à l'utilisation de cette seule table pour coder notre chaîne de caractères.
Toutefois, un des intérêts majeurs du code 128 est, comme on l'a vu dans la section III-D, la possibilité de l'optimiser en utilisant la table C, en codant des paires de chiffres avec un unique caractère. C'est ce que permet de réaliser la fonction que nous allons utiliser.
Celle-ci est très simple, elle n'utilise pas de fonctions ou de procédures pouvant la simplifier ou l'optimiser. Le but est plutôt de pouvoir décrire facilement comment l'objectif est atteint.
On déclare huit variables dans l'entête de la fonction :
- le caractère en cours de traitement ;
- une chaîne de caractères temporaire ;
- un caractère temporaire ;
- deux variables permettant d'indiquer quelle table est en cours d'utilisation ;
- la valeur de la clé de contrôle ;
- deux variables de compteur.
Function
Code128
(
strChaine)
'Caractère en cours de traitement
Dim
strCaractere As
String
'Chaîne de caractères temporaire
Dim
strChaineTemp As
String
'Caractère temporaire en cours de traitement
Dim
strCarTemp As
String
'Table utilisée (table B)
Dim
blnTableB As
Boolean
'Table utilisée (table C)
Dim
blnTableC As
Boolean
'Valeur de la clé de contrôle
Dim
lngCaractereControle As
Long
'Variable de compteur
Dim
i As
Long
'Variable de compteur
Dim
j As
Long
Puis on vérifie que la chaîne de caractères à coder n'est pas Null.
On
Error
GoTo
GestionErreurs
'Génération d'une erreur définie par l'utilisateur
If
IsNull
(
strChaine) Then
Err
.Raise
513
Il est nécessaire d'apporter ici quelques précisions supplémentaires au sujet de la gestion des erreurs. Il est souvent conseillé de laisser la fonction ou procédure appelante les gérer, principe que nous allons appliquer ici.
Si la chaîne de caractères passée en argument est Null, on génère délibérément une erreur en utilisant la méthode Raise de l'objet Err, en lui attribuant le numéro 513, premier de la plage réservée aux erreurs définies par l'utilisateur (513 à 65535).
On passe ensuite à l'encodage de la chaîne de caractères, en suivant toujours le schéma suivant :
- on extrait successivement chacun des caractères de la chaîne ;
- on l'ajoute à la chaîne de caractères temporaire ;
- si les caractères contenus dans la chaîne de caractères temporaire peuvent être ajoutés à la variable Code128, on les traite, on purge la chaîne temporaire et on passe au caractère suivant ;
- sinon, on passe simplement au caractère suivant.
Si aucune table n'est encore utilisée, on tente immédiatement d'optimiser le code en essayant de débuter sur la table C. Pour cela, quatre caractères numériques sont nécessaires.
'Codage de la chaîne de caractères
For
i =
1
To
Len
(
strChaine)
'Extraction d'un caractère de la chaîne
strCaractere =
Mid
(
strChaine, i, 1
)
'Ajout du caractère à la chaîne temporaire
strChaineTemp =
strChaineTemp &
strCaractere
'Début sur table B ou C
If
Not
blnTableB And
Not
blnTableC Then
'Quatre caractères numériques sont nécessaires pour débuter en table C
If
IsNumeric
(
strCaractere) Then
'Suite du code...
End
If
Next
i
Si la chaîne temporaire contient quatre caractères numériques, on ajoute le caractère de démarrage de la table C à la variable Code128, on traite la chaîne de caractères temporaire et on déclare que la table C est utilisée.
En table C, pour obtenir le caractère ASCII recherché, on convertit la valeur de celui-ci de la façon suivante : si elle est comprise entre 0 et 94, on ajoute 32; si elle est supérieure à 94, on ajoute 105.
'La chaîne temporaire contient quatre caractères numériques, début sur table C
If
Len
(
strChaineTemp) =
4
Then
'Ajout du caractère de démarrage de la table C
Code128 =
Chr
(
210
)
'Traitement de quatre caractères. Ajout de deux caractères optimisés
For
j =
1
To
4
Step
2
strCarTemp =
Val
(
Mid
(
strChaineTemp, j, 2
))
strCarTemp =
IIf
(
strCarTemp <
95
, strCarTemp +
32
, strCarTemp +
105
)
Code128 =
Code128 &
Chr
(
strCarTemp)
Next
j
'Purge de la chaîne de caractères temporaire
strChaineTemp =
""
'La table C est utilisée
blnTableC =
True
End
If
Dans le cas contraire, on ajoute le caractère de démarrage de la table B à la variable Code128, on traite la chaîne de caractères et on déclare que la table B est utilisée.
'Le nombre de caractères numériques en début de chaîne est inférieur à quatre, début sur table B
Else
'Ajout du caractère de démarrage de la table B
Code128 =
Code128 &
Chr
(
209
)
'Ajout des caractères de la chaîne temporaire
For
j =
1
To
Len
(
strChaineTemp)
Code128 =
Code128 &
Mid
(
strChaineTemp, j, 1
)
Next
j
'Purge de la chaîne de caractères temporaire
strChaineTemp =
""
'La table B est utilisée
blnTableB =
True
End
If
À ce stade, on a codé le ou les premiers caractères et on connaît la table en cours d'utilisation. On passe au traitement des caractères suivants, toujours dans l'optique d'optimiser le code.
Si on est sur table C, on essaie de coder deux caractères numériques supplémentaires.
'Traitement de la suite de la chaîne de caractères
Else
'Traitement sur table C, tentative de traiter des caractères numériques supplémentaires
If
blnTableC Then
'Deux caractères numériques sont nécessaires pour continuer sur table C
If
IsNumeric
(
strCaractere) Then
Si ceux-ci sont trouvés, on traite la chaîne de caractères temporaire.
'La chaîne temporaire contient deux caractères numériques
If
Len
(
strChaineTemp) =
2
Then
'Traitement de deux caractères. Ajout d'un caractère optimisé
strCarTemp =
Val
(
Mid
(
strChaineTemp, 1
, 2
))
strCarTemp =
IIf
(
strCarTemp <
95
, strCarTemp +
32
, strCarTemp +
105
)
Code128 =
Code128 &
Chr
(
strCarTemp)
'Purge de la chaîne de caractères temporaire
strChaineTemp =
""
End
If
On passe au traitement du caractère suivant, toujours en tentant de trouver deux nouveaux caractères à optimiser.
Si on ne trouve pas deux caractères numériques, on doit passer sur la table B pour continuer l'encodage. On ajoute donc un caractère de permutation à la variable Code128 avant de traiter la chaîne de caractères et on déclare que la table B est utilisée.
'Le nombre de caractères numériques est inférieur à deux
Else
'Permutation sur table B
Code128 =
Code128 &
Chr
(
205
)
'Ajout des caractères de la chaîne temporaire
For
j =
1
To
Len
(
strChaineTemp)
Code128 =
Code128 &
Mid
(
strChaineTemp, j, 1
)
Next
j
'Purge de la chaîne de caractères temporaire
strChaineTemp =
""
'La table B est utilisée
blnTableC =
False
blnTableB =
True
End
If
Si on est sur table B, on essaie de passer ou revenir sur la table C. Il nous faut dans ce cas trouver six caractères numériques. Également, il nous faut nous assurer que le nombre de caractères contenus dans la chaîne temporaire et restant à traiter est au moins égal à six.
'Traitement sur table B, tentative de permuter sur table C pour optimiser le code
Else
'Le caractère est numérique
If
IsNumeric
(
strCaractere) Then
'Si le reste de la chaîne et le contenu de la chaîne temporaire est égal
'à au moins six caractères
If
Len
(
strChaine) -
i +
Len
(
strChaineTemp) >=
6
Then
'Suite du code...
End
If
End
If
Si la chaîne temporaire contient six caractères numériques, on peut passer sur la table C. On ajoute un caractère de permutation à la variable Code128, on traite la chaîne de caractères et on déclare que la table C est utilisée.
'La chaîne temporaire contient six caractères numériques
If
Len
(
strChaineTemp) =
6
Then
'Permutation sur table C
Code128 =
Code128 &
Chr
(
204
)
'Traitement de six caractères numériques. Ajout de trois caractères optimisés
For
j =
1
To
6
Step
2
strCarTemp =
Val
(
Mid
(
strChaineTemp, j, 2
))
strCarTemp =
IIf
(
strCarTemp <
95
, strCarTemp +
32
, strCarTemp +
105
)
Code128 =
Code128 &
Chr
(
strCarTemp)
Next
j
'Purge de la chaîne de caractères temporaire
strChaineTemp =
""
'La table C est utilisée
blnTableB =
False
blnTableC =
True
End
If
Lorsque le nombre de caractères contenus dans la chaîne temporaire et le nombre de caractères restant à traiter est inférieur à six, il n'est évidemment plus possible de permuter sur la table C.
On vérifie donc d'abord si le caractère en cours de traitement est le cinquième avant la fin de la chaîne de caractères. Si c'est le cas, on traite la chaîne temporaire. En effet, comme on est sur table B, il ne peut être optimisé en aucune manière.
'Le nombre de caractères de la chaîne temporaire et le reste de caractères à traiter est inférieur à six
Else
'Le reste de caractères à traiter est égal à cinq
If
Len
(
strChaine) -
i +
1
=
5
Then
'Ajout du caractère sur table B
Code128 =
Code128 &
strChaineTemp
'Purge de la chaîne de caractères temporaire
strChaineTemp =
""
End
If
Si le caractère en cours de traitement est numérique et que le nombre de caractères restant à traiter est égal ou inférieur à quatre, il est encore possible d'optimiser les quatre derniers caractères.
'Si le nombre de caractères restant est égal ou inférieur à quatre
If
Len
(
strChaine) -
i +
1
<=
4
Then
Si la chaîne temporaire contient quatre caractères numériques, on peut passer sur la table C. On ajoute un caractère de permutation à la variable Code128 et on traite la chaîne de caractères.
'La chaîne temporaire contient quatre caractères numériques
If
Len
(
strChaineTemp) =
4
Then
'Permutation sur table C
Code128 =
Code128 &
Chr
(
204
)
'Traitement de quatre caractères numériques. Ajout de deux caractères optimisés
For
j =
1
To
4
Step
2
strCarTemp =
Val
(
Mid
(
strChaineTemp, j, 2
))
strCarTemp =
IIf
(
strCarTemp <
95
, strCarTemp +
32
, strCarTemp +
105
)
Code128 =
Code128 &
Chr
(
strCarTemp)
Next
j
'Purge de la chaîne de caractères temporaire
strChaineTemp =
""
End
If
Lorsque les caractères en cours de traitement ne sont pas numériques, comme on est déjà sur la table B, on les ajoute simplement à la variable Code128.
'Le caractère en cours n'est pas numérique
Else
'Ajout du caractère sur table B
For
j =
1
To
Len
(
strChaineTemp)
Code128 =
Code128 &
Mid
(
strChaineTemp, j, 1
)
Next
j
'Purge de la chaîne de caractères temporaire
strChaineTemp =
""
End
If
Lorsqu'on traite le dernier caractère, quelques tests supplémentaires doivent être effectués. En effet, si à ce moment-là la chaîne temporaire n'est pas vide, les caractères contenus dans celle-ci doivent encore être ajoutés à la variable Code128.
'Traitement du dernier caractère de la chaîne
If
i =
Len
(
strChaine) And
Len
(
strChaineTemp) >=
1
Then
'Suite du code
End
If
Si on est sur table C, la chaîne temporaire ne contient qu'un caractère numérique qu'il n'est pas possible d'optimiser. On passe donc sur table B en ajoutant un caractère de permutation avant d'ajouter le caractère restant.
'La table C est en cours d'utilisation
If
blnTableC Then
'Permutation vers la table B
Code128 =
Code128 &
Chr
(
205
)
'Ajout du dernier caractère sur table B
Code128 =
Code128 &
strChaineTemp
Si on est sur table B, la chaîne de caractère temporaire peut contenir de un à trois caractères numériques qu'il n'est également pas possible d'optimiser. On les ajoute simplement à la variable Code128.
'La table B est en cours d'utilisation
ElseIf
blnTableB Then
'Ajout des caractères de la chaîne temporaire
For
j =
1
To
Len
(
strChaineTemp)
Code128 =
Code128 &
Mid
(
strChaineTemp, j, 1
)
Next
j
Si aucune des tables n'est utilisée, c'est que la donnée à encoder contient moins de quatre caractères numériques. On ajoute le caractère de démarrage de la table B à la variable Code128 et on traite la chaîne de caractères temporaire.
'Aucune des deux tables n'est utilisée. La chaîne de caractères contient moins
'de quatre caractères numériques
Else
'Début sur table B
Code128 =
Code128 &
Chr
(
209
)
'Ajout des caractères de la chaîne temporaire
For
j =
1
To
Len
(
strChaineTemp)
Code128 =
Code128 &
Mid
(
strChaineTemp, j, 1
)
Next
j
End
If
La chaîne de caractères est maintenant encodée, l'étape suivante consiste à calculer la valeur de la clé de contrôle comme indiqué dans la section III-E, puis à la convertir en caractère ASCII.
Enfin, on ajoute celui-ci et le caractère d'arrêt à la variable Code128.
'Calcul de la valeur de la clé de contrôle
For
j =
1
To
Len
(
Code128)
strCarTemp =
Asc
(
Mid
(
Code128, j, 1
))
strCarTemp =
IIf
(
strCarTemp <
127
, strCarTemp -
32
, strCarTemp -
105
)
If
j =
1
Then
lngCaractereControle =
strCarTemp
lngCaractereControle =
(
lngCaractereControle +
(
j -
1
) *
strCarTemp) Mod
103
Next
'Caractère ASCII de la clé de contrôle
lngCaractereControle =
IIf
(
lngCaractereControle <
95
, lngCaractereControle +
32
, lngCaractereControle +
105
)
'Ajout du caractère ASCII de la clé de contrôle et du caractère d'arrêt
Code128 =
Code128 &
Chr
(
lngCaractereControle) &
Chr
(
211
)
Exit
Function
On arrive à la fin de la procédure. En cas d'erreur, que celle-ci soit prévue ou inattendue, l'exécution du code se poursuit après l'étiquette GestionErreurs.
Ici, on ne gère pas directement l'erreur, mais on utilise la méthode Raise de l'objet Err pour la renvoyer à la procédure appelante avec deux arguments, le numéro d'erreur et la source de celle-ci, en l'occurrence la fonction Code128.
GestionErreurs
:
'Transmet l'erreur à la procédure appelante
Err
.Raise
Err
.Number
, "Code128"
End
Function
Code complet de la procédure au format texte.
IV-D-6. Événement Sur clic du bouton Aperçu - 2e partie▲
En retour, nous avons le code 128 de notre chaîne de caractères, soit :
- le caractère de démarrage ;
- les caractères du code ;
- le caractère de contrôle ;
- le caractère d'arrêt.
On peut vérifier notre code 128, ici pour ABC2011, dans la fenêtre d'exécution :
Le résultat, comparé à celui de la section III-E, est bien celui attendu.
Une fois les caractères du code 128 connus, il reste encore à convertir ceux-ci de manière à ce que le code-barres puisse être dessiné de façon simple.
Comme déjà mentionné dans la section III-A, le code 128 est constitué de 107 motifs différents, composés chacun de onze modules, groupés en trois barres et trois espaces, à l'exception du caractère d'arrêt qui est complété par deux modules de barres à son extrémité droite permettant de fermer le code-barres et qui est donc composé de treize modules au total.
On va donc convertir chaque caractère du code en une suite de "1" et de "0", représentant respectivement des barres et des espaces, soit le motif de ceux-ci.
Pour ce faire, on fait appel à la fonction MotifCodeBarres128, en passant successivement chaque caractère en argument. Les valeurs de retour sont ensuite concaténées dans la variable strCodeBarres.
'Conversion des caractères. Le chiffre "1" représente les barres, le chiffre "0" les espaces
For
i =
1
To
Len
(
strChaine)
strCaractere =
Mid
(
strChaine, i, 1
)
strBarres =
MotifCodeBarres128
(
strCaractere)
strCodeBarres =
strCodeBarres &
strBarres
Next
i
IV-D-7. Fonction de conversion du code 128 en barres et espaces▲
Ici, on teste simplement la valeur du code du caractère avec une instruction Select Case.
Si cette valeur correspond à un élément de la liste, le motif du caractère est affecté en tant que valeur de retour de la fonction.
Comme pour la fonction précédente, les erreurs sont traitées dans la procédure appelante. Si l'erreur est inattendue, on attribue le numéro de celle-ci à l'objet Err.
Par contre si l'erreur est due au fait que la valeur d'un caractère que l'on souhaite convertir n'est pas un élément de la liste, on définit la valeur de l'erreur comme étant 514.
Cette erreur va être générée lorsqu'on tente de convertir un caractère dont la valeur est comprise entre 127 et 199 ou supérieure à 211, un caractère accentué par exemple.
Public
Function
MotifCodeBarres128
(
strChaine As
String
) As
String
On
Error
GoTo
GestionErreurs
Select
Case
Asc
(
strChaine)
'Caractère = Espace / Table B = Espace / Table C = 00
Case
32
: MotifCodeBarres128 =
"11011001100"
'Caractère = ! / Table B = ! / Table C = 01
Case
33
: MotifCodeBarres128 =
"11001101100"
'Caractère = " / Table B = " / Table C = 02
Case
34
: MotifCodeBarres128 =
"11001100110"
'Caractère = # / Table B = # / Table C = 03
Case
35
: MotifCodeBarres128 =
"10010011000"
'Caractère = $ / Table B = $ / Table C = 04
Case
36
: MotifCodeBarres128 =
"10010001100"
'Caractère = % / Table B = % / Table C = 05
Case
37
: MotifCodeBarres128 =
"10001001100"
'Suite du code...
' Caractère = Ï - Table B = Fnc 1 / Table C = Fnc 1
Case
207
: MotifCodeBarres128 =
"11110101110"
' Caractère = Ð - Table B = Start A / Table C = Start A
Case
208
: MotifCodeBarres128 =
"11010000100"
' Caractère = Ñ - Table B = Start B / Table C = Start B
Case
209
: MotifCodeBarres128 =
"11010010000"
' Caractère = Ò - Table B = Start C / Table C = Start C
Case
210
: MotifCodeBarres128 =
"11010011100"
' Caractère = Ó - Table B = Stop / Table C = Stop
Case
211
: MotifCodeBarres128 =
"1100011101011"
'Erreur
Case
Else
: Err
.Raise
514
End
Select
'Sortie de la fonction
Exit
Function
GestionErreurs
:
'Transmet l'erreur à la procédure appelante
Err
.Raise
Err
.Number
, "MotifCodeBarres128"
End
Function
Code complet de la fonction au format texte.
IV-D-8. Événement Sur clic du bouton Aperçu - 3e partie▲
On peut également vérifier le résultat dans la fenêtre d'exécution, toujours pour ABC2011 :
Examinons en détail le résultat obtenu et comparons-le avec les caractères des tables annexées. On constate que la conversion est absolument correcte.
On connaît maintenant le nombre de modules du code-barres et il est donc possible de calculer la hauteur de ce dernier si on désire que celle-ci soit variable.
'Si la hauteur du code-barres est "Variable", on calcule celle-ci
If
strHauteurCodeBarres =
"Variable"
Then
'Calcul de la hauteur des modules par rapport à la largeur du code-barres
lngLargeurCodeBarres =
Len
(
strCodeBarres) *
Me.txtLargeurModules
Select
Case
lngLargeurCodeBarres
'15 % de la longueur excède 567 twips (1 cm)
Case
Is
>
3780
'Hauteur maximale des modules égale 567 twips
lngHauteurModule =
567
'15 % de la longeur est inférieur à 340 twips (0.6 cm)
Case
Is
<
2268
'Hauteur minimale des modules, 340 twips
lngHauteurModule =
340
Case
Else
'La hauteur des modules est égale à 15 % de la longueur du code-barres
lngHauteurModule =
Int
((
lngLargeurCodeBarres /
100
*
15
) +
1
*
0
.5
)
End
Select
End
If
Enfin, on ajoute des "quiet zone" à chaque extrémité du code-barres, soit onze modules d'espaces et on calcule la largeur totale de celui-ci, valeur qu'on affecte à la variable publique lngLargeurCodeBarres.
'Ajout des "Quiet zone" en début et en fin du code-barres
strCodeBarres =
"00000000000"
&
strCodeBarres &
"00000000000"
'Largeur du code-barres, "Quiet zone" comprises
lngLargeurCodeBarres =
Len
(
strCodeBarres) *
Me.txtLargeurModules
Il est maintenant temps de passer à l'enregistrement de la variable strCodeBarres et du libellé du code dans la table tblCodesBarres. Ici, on doit tenir compte de la position de la première étiquette. On va donc simplement créer
le nombre nécessaire d'enregistrements vides, puis on ajoute autant d'enregistrements que d'étiquettes désirées :
'Ajout d'enregistrements vides en fonction de l'étiquette de début désirée
i =
0
For
i =
1
To
Me.txtEtiquetteDebut
-
1
rst.AddNew
rst
(
"CodeBarres"
) =
Null
rst
(
"Libelle"
) =
Null
rst.Update
Next
i
'Ajout du nombre d'enregistrements correspondant au nombre d'étiquettes désirées
i =
0
For
i =
1
To
Me.txtNbEtiquettes
rst.AddNew
rst
(
"CodeBarres"
) =
strCodeBarres
rst
(
"Libelle"
) =
Me.txtChaineCaractere
rst.Update
Next
i
Le résultat pour un choix de six étiquettes, la position de la première étant la troisième de la feuille :
À noter que la position réelle d'impression de la première étiquette va dépendre du mode de traçage des colonnes choisi.
On peut maintenant ouvrir l'état rptEtiquettes.
'Ouverture de l'état rptEtiquettes en le maximisant et en l'ajustant à la fenêtre Access
DoCmd.OpenReport
"rptEtiquettes"
, acViewPreview
DoCmd.Maximize
DoCmd.RunCommand
acCmdFitToWindow
IV-D-9. Événement Sur ouverture de l'état▲
Dans cette procédure, on commence par affecter la valeur de la variable publique lngTracageColonne à la propriété ItemLayout de l'objet Printer pour définir le mode de traçage des colonnes.
Ensuite, on vérifie que la largeur du code-barres, "quiet zone" comprises, n'est pas supérieure à celle des étiquettes. Si c'est le cas, on annule l'ouverture de l'état, ce qui provoque une erreur 2501 dans la procédure appelante, où elle est gérée.
Private
Sub
Report_Open
(
cancel As
Integer
)
On
Error
GoTo
GestionErreurs
'Mode de traçage des étiquettes : 1953 = Traçage horizontal : 1954 = Traçage vertical
Me.Printer.ItemLayout
=
lngTracageColonne
If
lngLargeurCodeBarres >
Me.txtCodeBarres.Width
Then
'Annulation de l'ouverture de l'état. L'erreur est gérée dans la procédure appelante
cancel =
True
End
If
'Sortie de la procédure
Exit
Sub
GestionErreurs
:
'Affichage d'un message
MsgBox
"Une erreur inattendue s'est produite !"
&
vbNewLine
&
"Erreur no : "
_
&
Err
.Number
&
vbNewLine
&
Err
.Description
, vbCritical
, "Erreur !"
'Envoi de la touche Esc pour forcer la fermeture de l'état
SendKeys "{ESC}"
End
Sub
En cas d'erreur dans la procédure, on affiche un message et on envoie la touche Esc pour l'annuler et forcer la fermeture de l'état.
IV-D-10. Événement Au formatage de la section détail de l'état▲
Lors du formatage de cette section, les données enregistrées dans la table tblCodesBarres vont être affichées dans les deux zones de texte txtCodeBarres et txtLibelle.
Pour rappel, la propriété Visible de la zone de texte txtCodeBarres est fixée à Non, car nous ne voulons pas afficher des "1" et des "0", mais dessiner des barres et des espaces.
On va donc appeler la procédure TracerMotifCodeBarres128 en passant en argument la référence de la zone de texte txtCodeBarres et celle de l'état.
L'événement va se répéter autant de fois qu'il y a d'enregistrements dans la source de l'état.
Private
Sub
Detail_Format
(
cancel As
Integer
, FormatCount As
Integer
)
On
Error
GoTo
GestionErreurs
'Appel de la fonction de traçage des codes-barres
TracerMotifCodeBarres128 Me.txtCodeBarres
, Me
'Sortie de la procédure
Exit
Sub
GestionErreurs
:
'Affichage d'un message
MsgBox
"Une erreur inattendue s'est produite !"
&
vbNewLine
&
vbNewLine
&
_
"Source : "
&
Err
.Source
&
vbNewLine
&
_
"Erreur no : "
&
Err
.Number
&
vbNewLine
&
_
"Description : "
&
Err
.Description
, vbCritical
, "Erreur !"
'Envoi de la touche Esc pour forcer la fermeture de l'état
SendKeys "{ESC}"
End
Sub
En cas d'erreur dans la procédure, on procède de la même manière que dans la précédente.
IV-D-11. Procédure de traçage du code-barres 128▲
On va maintenant dessiner les codes-barres. Pour l'essentiel, cette procédure est inspirée de l'article Apprendre à écrire et dessiner dans les états Access de Philippe JOCHMANS.
Avant toute chose, on déclare deux constantes pour les couleurs des barres et espaces dans la section Déclaration du module, noire pour les barres et blanche pour les espaces.
'Déclaration des constantes utilisées dans le module
'Couleur des barres
Private
Const
CouleurBarre As
Long
=
0
'Couleur des espaces
Private
Const
CouleurEspace As
Long
=
16777215
Ensuite de quoi on déclare neuf variables dans l'entête de la procédure.
Public
Sub
TracerMotifCodeBarres128
(
Ctrl As
Control, rpt As
Report)
'Déclaration des variables
'Chaîne complète des modules du code-barres
Dim
strCodeBarres As
String
'Type d'un module : 1 = barre / 0 = espace
Dim
strTypeModule As
String
'Variable de compteur
Dim
i As
Long
'Largeur de la zone de texte
Dim
sngLargeurZoneTexte As
Single
'Valeur de la marge gauche en twips
Dim
sngMargeGauche As
Single
'Coordonnée horizontale (X1) du point de départ des barres et des espaces
Dim
sngX1 As
Single
'Coordonnée verticale (Y1) du point de départ des barres et des espaces
Dim
sngY1 As
Single
'Coordonnée horizontale (X2) du point d'arrivée des barres et des espaces
Dim
sngX2 As
Single
'Coordonnée verticale (Y2) du point d'arrivée des barres et des espaces
Dim
sngY2 As
Single
Puis, on affecte la valeur de la zone de texte txtCodeBarres passée en argument à la variable strCodeBarres, pour autant que celle-ci ne soit pas Null.
On
Error
GoTo
GestionErreurs
'Affectation de la chaîne de caractères du code-barres à la variable
If
Not
IsNull
(
Ctrl.Value
) Then
strCodeBarres =
Ctrl.Value
Else
Exit
Sub
End
If
On initialise les coordonnées horizontales et verticales du point de départ de la première barre, le coin en haut et à gauche de la zone de texte txtCodeBarres. La coordonnée horizontale du point d'arrivée est, elle, égale à la valeur de la variable lngTailleModule.
'Initialisation des coordonnées X1, Y1 et X2 en twips
sngX1 =
Ctrl.Left
sngY1 =
Ctrl.Top
sngX2 =
lngTailleModule
Il reste à initialiser la coordonnée verticale du point d'arrivée, en fonction du type de hauteur choisi. Si celle-ci est variable, la coordonnée Y2 prend la valeur de la variable lngHauteurModule. Si elle est fixe, c'est la hauteur de la zone de texte txtCodeBarres qui est affectée à cette dernière.
'Initialisation de la coordonnée Y2
Select
Case
strHauteurCodeBarres
'Si le type de hauteur est "Variable"
Case
"Variable"
'La coordonnée verticale du point d'arrivée est égale à la valeur
'de la variable lngHauteurModule
sngY2 =
lngHauteurModule
'Si le type de hauteur est "Fixe"
Case
Else
'La coordonnée verticale du point d'arrivée est définie par la hauteur
'de la zone de texte txtCodeBarres
sngY2 =
Ctrl.Height
End
Select
Comme on connaît la largeur du code-barres et la largeur de la zone de texte, il est simple de centrer très exactement celui-ci sur les étiquettes, en décalant la coordonnée horizontale du point de départ vers la droite.
'Calcul de la valeur de la marge à appliquer à gauche
sngLargeurZoneTexte =
Ctrl.Width
sngMargeGauche =
Int
((
sngLargeurZoneTexte -
lngLargeurCodeBarres) /
2
)
'Décalage de la valeur de la coordonnée X1 pour centrer le code-barres
sngX1 =
sngX1 +
sngMargeGauche
Enfin, on dessine les barres et les espaces sur l'état. Après avoir dessiné le premier espace, on décale simplement la coordonnée horizontale X1 du module suivant vers la droite.
'Traçage du code-barres
For
i =
1
To
Len
(
strCodeBarres)
'Type de module, barre ou espace, à tracer
strTypeModule =
Mid
(
strCodeBarres, i, 1
)
Select
Case
strTypeModule
Case
"1"
'Traçage d'une barre
rpt.Line
(
sngX1, sngY1)-
Step
(
sngX2, sngY2), CouleurBarre, BF
'Calcul de la coordonnée X1 suivante
sngX1 =
sngX1 +
lngTailleModule
Case
"0"
'Traçage d'un espace
rpt.Line
(
sngX1, sngY1)-
Step
(
sngX2, sngY2), CouleurEspace, BF
'Calcul de la coordonnée X1 suivante
sngX1 =
sngX1 +
lngTailleModule
End
Select
Next
i
L'exécution de la procédure étant achevée, on peut la quitter. En cas d'erreur, le numéro et la source de celle-ci sont transmis à la procédure appelante.
'Sortie de la procédure
Exit
Sub
GestionErreurs
:
'Transmet l'erreur à la procédure appelante
Err
.Raise
Err
.Number
, "TracerMotifCodeBarres128"
End
Sub
Code complet de la procédure au format texte.
IV-D-12. Événement Sur clic du bouton Aperçu - 4e partie▲
On arrive ici à la fin de la procédure. On prend soin de fermer le Recordset pour libérer la mémoire et d'affecter Nothing à la variable.
En cas d'erreur, que celle-ci soit prévue ou inattendue, l'exécution du code se poursuit après l'étiquette GestionErreurs.
On gère ici les erreurs suivantes :
- l'annulation de l'ouverture de l'état si la largeur des codes-barres est supérieure à celle des étiquettes (erreur 2501) ;
- la tentative d'encodage d'une chaîne de caractères ayant une valeur Null (erreur 513) ;
- la tentative de codage de caractères non supportés par le code 128 (erreur 514) ;
- toute erreur inattendue survenue dans les fonctions Code128 et MotifCodeBarres128.
Pour les trois premières erreurs, on affiche un message explicite. En cas d'erreur inattendue, on affiche sa source, son numéro et sa description.
Quel que soit le type d'erreur, l'exécution du code se poursuit après l'étiquette SortieApercuImpression, afin de garantir que même en cas d'erreur, le Recordset est bien fermé et la mémoire libérée.
SortieApercuImpression
:
'Libération de l'objet
rst.Close
db.Close
Set
rst =
Nothing
Set
db =
Nothing
'Sortie de la procédure
Exit
Sub
GestionErreurs
:
Select
Case
Err
.Number
'L'ouverture de l'état a été annulée
Case
2501
'Affichage d'un message
MsgBox
"La largeur des codes-barres est supérieure à celle des étiquettes !"
, _
vbCritical
, "Erreur !"
'Sortie de la procédure
Resume
SortieApercuImpression
'La chaîne de caractères est de valeur Null
Case
513
'Affichage d'un message
MsgBox
"La chaîne de caractères n'est pas valide (Null) !"
&
vbNewLine
&
vbNewLine
&
_
"Veuillez vérifiez votre saisie."
, vbCritical
, "Erreur !"
'Sortie de la procédure
Resume
SortieApercuImpression
'La chaîne de caractères contient un ou des caractères non supportés par le code 128
Case
514
'Affichage d'un message
MsgBox
"La chaîne de caractères n'est pas valide !"
&
vbNewLine
&
vbNewLine
&
_
"Elle contient des caractères non supportés par le code 128,"
&
vbNewLine
&
_
"par exemple des caractères accentués."
, vbCritical
, "Erreur !"
'Sortie de la procédure
Resume
SortieApercuImpression
Case
Else
'Affichage d'un message
MsgBox
"Une erreur inattendue s'est produite !"
&
vbNewLine
&
vbNewLine
&
_
"Source : "
&
Err
.Source
&
vbNewLine
&
_
"Erreur no : "
&
Err
.Number
&
vbNewLine
&
_
"Description : "
&
Err
.Description
, vbCritical
, "Erreur !"
'Sortie de la procédure
Resume
SortieApercuImpression
End
Select
End
Sub
Code complet de la procédure au format texte.
V. Conclusion▲
Il ne s'avère donc pas très compliqué de créer des codes-barres sans avoir recours à des composants externes, que ce soit une police de caractères ou un contrôle ActiveX.
Les nombreux tests effectués sur ces codes-barres conçus uniquement en utilisant VBA ont démontré qu'ils sont parfaitement lisibles et soutiennent aisément la comparaison avec des codes-barres imprimés au moyen de polices de caractères spéciales.
Cette solution offre en outre l'avantage de pouvoir calculer très précisément la largeur des modules et la hauteur des codes-barres si nécessaire.
VI. Remerciements▲
Je tiens à remercier tous les membres de l'équipe Office pour leurs conseils avisés. Remerciements tout particuliers à GAYOT pour ses nombreux tests de lecture des codes-barres.
VII. Liens▲
VIII. Annexe - composition des tables du code 128▲
Valeur | Table A | Table B | Table C | ASCII | Caractère | Motif |
---|---|---|---|---|---|---|
0 | Espace | Espace | 00 | 0032 | Espace | 11011001100 |
1 | ! | ! | 01 | 0033 | ! | 11001101100 |
2 | " | " | 02 | 0034 | " | 11001100110 |
3 | # | # | 03 | 0035 | # | 10010011000 |
4 | $ | $ | 04 | 0036 | $ | 10010001100 |
5 | % | % | 05 | 0037 | % | 10001001100 |
6 | & | & | 06 | 0038 | & | 10011001000 |
7 | ' | ' | 07 | 0039 | ' | 10011000100 |
8 | ( | ( | 08 | 0040 | ( | 10001100100 |
9 | ) | ) | 09 | 0041 | ) | 11001001000 |
10 | * | * | 10 | 0042 | * | 11001000100 |
11 | + | + | 11 | 0043 | + | 11000100100 |
12 | , | , | 12 | 0044 | , | 10110011100 |
13 | - | - | 13 | 0045 | - | 10011011100 |
14 | . | . | 14 | 0046 | . | 10011001110 |
15 | / | / | 15 | 0047 | / | 10111001100 |
16 | 0 | 0 | 16 | 0048 | 0 | 10011101100 |
17 | 1 | 1 | 17 | 0049 | 1 | 10011100110 |
18 | 2 | 2 | 18 | 0050 | 2 | 11001110010 |
19 | 3 | 3 | 19 | 0051 | 3 | 11001011100 |
20 | 4 | 4 | 20 | 0052 | 4 | 11001001110 |
21 | 5 | 5 | 21 | 0053 | 5 | 11011100100 |
22 | 6 | 6 | 22 | 0054 | 6 | 11001110100 |
23 | 7 | 7 | 23 | 0055 | 7 | 11101101110 |
24 | 8 | 8 | 24 | 0056 | 8 | 11101001100 |
25 | 9 | 9 | 25 | 0057 | 9 | 11100101100 |
26 | : | : | 26 | 0058 | : | 11100100110 |
27 | ; | ; | 27 | 0059 | ; | 11101100100 |
28 | < | < | 28 | 0060 | < | 11100110100 |
29 | = | = | 29 | 0061 | = | 11100110010 |
30 | > | > | 30 | 0062 | > | 11011011000 |
31 | ? | ? | 31 | 0063 | ? | 11011000110 |
32 | @ | @ | 32 | 0064 | @ | 11000110110 |
33 | A | A | 33 | 0065 | A | 10100011000 |
34 | B | B | 34 | 0066 | B | 10001011000 |
35 | C | C | 35 | 0067 | C | 10001000110 |
36 | D | D | 36 | 0068 | D | 10110001000 |
37 | E | E | 37 | 0069 | E | 10001101000 |
38 | F | F | 38 | 0070 | F | 10001100010 |
39 | G | G | 39 | 0071 | G | 11010001000 |
40 | H | H | 40 | 0072 | H | 11000101000 |
41 | I | I | 41 | 0073 | I | 11000100010 |
42 | J | J | 42 | 0074 | J | 10110111000 |
43 | K | K | 43 | 0075 | K | 10110001110 |
44 | L | L | 44 | 0076 | L | 10001101110 |
45 | M | M | 45 | 0077 | M | 10111011000 |
46 | N | N | 46 | 0078 | N | 10111000110 |
Valeur | Table A | Table B | Table C | ASCII | Caractère | Motif |
---|---|---|---|---|---|---|
47 | O | O | 47 | 0079 | O | 10001110110 |
48 | P | P | 48 | 0080 | P | 11101110110 |
49 | Q | Q | 49 | 0081 | Q | 11010001110 |
50 | R | R | 50 | 0082 | R | 11000101110 |
51 | S | S | 51 | 0083 | S | 11011101000 |
52 | T | T | 52 | 0084 | T | 11011100010 |
53 | U | U | 53 | 0085 | U | 11011101110 |
54 | V | V | 54 | 0086 | V | 11101011000 |
55 | W | W | 55 | 0087 | W | 11101000110 |
56 | X | X | 56 | 0088 | X | 11100010110 |
57 | Y | Y | 57 | 0089 | Y | 11101101000 |
58 | Z | Z | 58 | 0090 | Z | 11101100010 |
59 | [ | [ | 59 | 0091 | [ | 11100011010 |
60 | \ | \ | 60 | 0092 | \ | 11101111010 |
61 | ] | ] | 61 | 0093 | ] | 11001000010 |
62 | ^ | ^ | 62 | 0094 | ^ | 11110001010 |
63 | _ | _ | 63 | 0095 | _ | 10100110000 |
64 | NUL | ` | 64 | 0096 | ` | 10100001100 |
65 | SOH | a | 65 | 0097 | a | 10010110000 |
66 | STX | b | 66 | 0098 | b | 10010000110 |
67 | ETX | c | 67 | 0099 | c | 10000101100 |
68 | EOT | d | 68 | 0100 | d | 10000100110 |
69 | ENQ | e | 69 | 0101 | e | 10110010000 |
70 | ACK | f | 70 | 0102 | f | 10110000100 |
71 | BEL | g | 71 | 0103 | g | 10011010000 |
72 | BS | h | 72 | 0104 | h | 10011000010 |
73 | HT | i | 73 | 0105 | i | 10000110100 |
74 | LF | j | 74 | 0106 | j | 10000110010 |
75 | VT | k | 75 | 0107 | k | 11000010010 |
76 | FF | l | 76 | 0108 | l | 11001010000 |
77 | CR | m | 77 | 0109 | m | 11110111010 |
78 | SO | n | 78 | 0110 | n | 11000010100 |
79 | SI | o | 79 | 0111 | o | 10001111010 |
80 | DLE | p | 80 | 0112 | p | 10100111100 |
81 | DC1 | q | 81 | 0113 | q | 10010111100 |
82 | DC2 | r | 82 | 0114 | r | 10010011110 |
83 | DC3 | s | 83 | 0115 | s | 10111100100 |
84 | DC4 | t | 84 | 0116 | t | 10011110100 |
85 | NAK | u | 85 | 0117 | u | 10011110010 |
86 | SYN | v | 86 | 0118 | v | 11110100100 |
87 | ETB | w | 87 | 0119 | w | 11110010100 |
88 | CAN | x | 88 | 0120 | x | 11110010010 |
89 | EM | y | 89 | 0121 | y | 11011011110 |
90 | SUB | z | 90 | 0122 | z | 11011110110 |
91 | ESC | { | 91 | 0123 | { | 11110110110 |
92 | FS | | | 92 | 0124 | | | 10101111000 |
93 | GS | } | 93 | 0125 | } | 10100011110 |
94 | RS | ~ | 94 | 0126 | ~ | 10001011110 |
95 | US | Del | 95 | 0200 | È | 10111101000 |
96 | Fnc 3 | Fnc 3 | 96 | 0201 | É | 10111100010 |
97 | Fnc 2 | Fnc 2 | 97 | 0202 | Ê | 11110101000 |
Valeur | Table A | Table B | Table C | ASCII | Caractère | Motif |
---|---|---|---|---|---|---|
98 | Shift | Shift | 98 | 0203 | Ë | 11110100010 |
99 | Table C | Table C | 99 | 0204 | Ì | 10111011110 |
100 | Table B | Fnc 4 | Table B | 0205 | Í | 10111101110 |
101 | Fnc 4 | Table A | Table A | 0206 | Î | 11101011110 |
102 | Fnc 1 | Fnc 1 | Fnc 1 | 0207 | Ï | 11110101110 |
103 | Start A | Start A | Start A | 0208 | Ð | 11010000100 |
104 | Start B | Start B | Start B | 0209 | Ñ | 11010010000 |
105 | Start C | Start C | Start C | 0210 | Ò | 11010011100 |
106 | Stop | Stop | Stop | 0211 | Ó | 1100011101011 |