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-barre 128 - linéaire Code-barre Pdf417 - linéaire empilé Code-barre Aztec - à 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
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".
Code-barres 128 - Developpez.com - Code 128
  • 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 :

Propriétés de la table tblCodesBarres
  • 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.

Propriétés du formulaire frmCodeBarres

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 :

Aperçu du formulaire frmCodeBarres

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 :

Aperçu de l'état rptEtiquettes 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 :

Propriétés de la zone de texte txtCodeBarres

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
Sélectionnez
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
Sélectionnez
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
Sélectionnez
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
Sélectionnez
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
Sélectionnez
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
Sélectionnez
'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
Sélectionnez
'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
Sélectionnez
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
Sélectionnez
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
Sélectionnez
'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
Sélectionnez
'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
Sélectionnez
'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
Sélectionnez
'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
Sélectionnez
'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
Sélectionnez
'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
Sélectionnez
'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
Sélectionnez
'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
Sélectionnez
'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
Sélectionnez
'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
Sélectionnez
'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
Sélectionnez
'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
Sélectionnez
'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
Sélectionnez
'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
Sélectionnez
'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
Sélectionnez
'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
Sélectionnez
'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
Sélectionnez
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 :

Code-barres 128 ABC2011

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
Sélectionnez
'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
Sélectionnez
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 :

Motif du code-barres 128 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
Sélectionnez
'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
Sélectionnez
'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
Sélectionnez
'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 :

Table avec 2 enregistrements vides et 6 enregistrements valides

À 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
Sélectionnez
'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
Sélectionnez
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
Sélectionnez
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
Sélectionnez
'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
Sélectionnez
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
Sélectionnez
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
Sélectionnez
'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
Sélectionnez
'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
Sélectionnez
'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
Sélectionnez
'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
Sélectionnez
    '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
Sélectionnez
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