Access : créer des codes-barres 128 en VBA

Dominique KIRCHHOFER

Créer des codes-barres 128 en VBA. Commentez

- Titre : Access : créer des codes-barres 128 en VBA

- Auteur : Dominique KIRCHHOFER

- Parution : 20 décembre 2011

- Mise à jour : 15 février 2012

- Public visé :

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2010 Kirchhofer Dominique. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Droits de diffusion permanents accordés à Developpez LLC.

Sommaire

- I. Introduction

- II. Généralités

- II-A. Les codes-barres

- II-B. Lecture des codes-barres

- III. Le code 128

- III-A. Les différents caractères du code

- III-B. La structure du code

- III-C. Les modules

- III-D. Optimisation du code

- III-E. Le caractère de contrôle

- III-F. Les spécifications

- III-F-1. Légende du code-barres

- III-F-2. Largeur des modules et du code-barres

- III-F-3. Hauteur des modules

- III-F-4. Spécifications de vos codes-barres

- IV. L'application de création des codes-barres

- IV-A. Table

- IV-B. Formulaire

- IV-C. État

- IV-D. Fonctions et procédures

- IV-D-1. Entête de module (déclaration des variables publiques)

- IV-D-2. Événement Sur ouverture du formulaire

- IV-D-3. Événement Sur clic du bouton Format des colonnes

- IV-D-4. Événement Sur clic du bouton Aperçu - 1re partie

- IV-D-5. Fonction d'encodage de la chaîne de caractères en code 128

- IV-D-6. Événement Sur clic du bouton Aperçu - 2e partie

- IV-D-7. Fonction de conversion du code 128 en barres et espaces

- IV-D-8. Événement Sur clic du bouton Aperçu - 3e partie

- IV-D-9. Événement Sur ouverture de l'état

- IV-D-10. Événement Au formatage de la section détail de l'état

- IV-D-11. Procédure de traçage du code-barres 128

- IV-D-12. Événement Sur clic du bouton Aperçu - 4e partie

- V. Conclusion

- VI. Remerciements

- VII. Liens

- VIII. Annexe - composition des tables du code 128

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.

Code

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.

Code

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.

Code

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.

Code

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.

Code

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.

Code

'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.

Code

'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.

Code

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.

Code

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.

Code

'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.

Code

'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.

Code

'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.

Code

'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.

Code

'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.

Code

'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.

Code

'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.

Code

'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.

Code

'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.

Code

'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.

Code

'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.

Code

'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.

Code

'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.

Code

'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.

Code

'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.

Code

'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.

Code

'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.

Code

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.

Code

'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.

Code

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 = &#208; - Table B = Start A / Table C = Start A
Case 208: MotifCodeBarres128 = "11010000100"
' Caractère = &#209; - 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.

Code

'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.

Code

'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 :

Code

'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.

Code

'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.

Code

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.

Code

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.

Code

'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.

Code

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.

Code

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.

Code

'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.

Code

'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.

Code

'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.

Code

'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.

Code

'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.

Code

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

Wikipédia, code-barres 128
Code original de la création de codes-barres 39 en VBA

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