L'impression sous visual basic 6.0


précédentsommairesuivant

V. L'imprime à l'emploi

Remarque : n'oubliez pas de placer vos feuilles et PictureBox dans le même système d'unités que votre imprimante, afin de ne pas compliquer à loisir les conversions d'échelle.

V-A. Utilisation générale

V-A-1. Le centrage

Pour centrer le texte sur la feuille ou dans un cadre, il suffit d'une simple opération mathématique. Par exemple pour centrer sur la feuille horizontalement

 
Sélectionnez
Printer.CurrentX=Printer.Width/2 - Printer.TextWidth(Machaine)/2

V-A-2. Encadrer un texte

Comme je l'ai dit plus haut, il vaut mieux éviter d'encadrer à la volée, mais pour les passionnés, sachez que la syntaxe est la suivante (pour un cadre situé à 1.5 mm autour du texte) :

 
Sélectionnez
machaine = "Essai d'encadrement"
Printer.Print machaine;
Printer.Line Step(-Picture1.TextWidth(machaine) - 1.5, -1.5)-Step(Picture1.TextWidth(machaine) + 3,
Printer.TextHeight(machaine) + 3), , B

Vous noterez juste l'emploi des deux mots clés Step afin de travailler en coordonnées relatives.

V-A-3. Dessiner une case cochée

Là c'est très simple si on utilise pleinement le « dynamisme » des propriétés CurrentX et CurrentY :

 
Sélectionnez
Printer.Line -Step(4, 4), , B
Printer.Line -Step(-4, -4)
Printer.Line Step(4, 0)-Step(-4, 4)

Trace une case cochée de 4 mm de côté.

V-A-4. Insérer une image

Le plus simple est que cette image se trouve dans un contrôle image (pas forcément visible d'ailleurs) sur la feuille :

 
Sélectionnez
Printer.PaintPicture Image1.Picture, PositionX , PositionY

À noter que la position doit être en coordonnées absolues.

V-B. L'impression géométrique

Celle-ci est la plus simple. C'est une version un peu plus élaborée de la méthode PrintForm. Elle convient particulièrement pour les impressions d'un formulaire sur une page.

L'idée générale est de placer sur sa feuille, l'ensemble des contrôles qui devront être imprimés, dans une zone virtuelle (ou un picturebox). Éventuellement, pour gagner en qualité, on donnera un rapport hauteur/largeur à cette zone sensiblement égale à celui d'une page A4 dans le sens de l'orientation désiré (le rapport hauteur/largeur d'une feuille A4 en mode portrait est de Racine de 2 ) On calcule dans le code les coefficients d'expansions de cette zone vers la zone imprimable (et non vers la feuille) en X et en Y, par exemple :

 
Sélectionnez
FacX=(Printer.Width - 2*MargeX)/LargeurZone
FacY=(Printer.Heigth - 2*MargeY)/HauteurZone

On utilisera le plus petit de ces facteurs pour l'appliquer à la police.

Après cela on va parcourir la collection Controls de la feuille, tester la position ou le container, puis le type de contrôle afin de définir les actions.

Remarque : Placer ces contrôles dans un PictureBox simplifie la mise en place des contrôles sur la feuille, n'oubliez pas de mettre sa propriété ScaleMode égale à celle de l'imprimante. N'utilisez surtout pas de Frame, l'ensemble des coordonnées et dimensions de vos contrôles repasserait en twips.

Cette technique convient mieux à une impression en mode paysage, qui est le mode écran.

Exemple
Ma zone imprimable en paysage fait 257*180. Je place mes contrôles à imprimer dans un PictureBox. J'ai besoin qu'il ait une largeur de 200, je lui donne une hauteur de 140. Bien sûr, je respecte la proportion dans ce cas ce qui me permettra de n'utiliser qu'un seul facteur.

Dans cet exemple je complique pour montrer la conversion, car vous n'êtes pas sans remarquer que mon PictureBox tiendrait sur la feuille avec un facteur 1.

Dans ma feuille je déclare une constante de conversion

 
Sélectionnez
Private Const FacC! = 1.285 'facteur de conversion

Et la fonction Impression sera

 
Sélectionnez
Private Sub Impression()
Dim DecalY as single, DecalX as Single, ContImprim as Control
Printer.ScaleMode = 6
Printer.Orientation = 2
Printer.PaperSize = 9
Printer.PrintQuality = -4
Printer.ColorMode = 1
DecalX = 20 - (Printer.Width - Printer.ScaleWidth) / 2
DecalY = 15 - (Printer.Heigth - Printer.ScaleHeigth) / 2
'utilisez le décalage pour que le point(0,0) du PictureBox soit le point (0,0) de la zone imprimable
For Each ContImprim In Me.Controls
    If TypeOf ContImprim Is Label Then
        With Printer
            .FontName = ContImprim.FontName
            .FontBold = ContImprim.FontBold
            .FontSize = Int(FacEch * ContImprim.FontSize)
            .CurrentX = ContImprim.Left * FacEch
            .CurrentY = ContImprim.Top * FacEch
        End With
        Printer.Print ContImprim.Caption
    ElseIf TypeOf ContImprim Is TextBox Then
        With Printer
            .FontName = ContImprim.FontName
            .FontBold = ContImprim.FontBold
            .FontSize = Int(FacEch * ContImprim.FontSize)
            .CurrentX = ContImprim.Left * FacEch
            .CurrentY = ContImprim.Top * FacEch
        End With
        Printer.Print ContImprim.Text
        ElseIf TypeOf ContImprim Is CheckBox Then
            Printer.Line (ContImprim.Left * FacEch, ContImprim.Top * FacEch)-Step(7, 7), , B
            If ContImprim.Value = 1 Then
                Printer.Line (ContImprim.Left * FacEch, ContImprim.Top * FacEch)-Step(7, 7)
                Printer.Line ((ContImprim.Left * FacEch) + 7, ContImprim.Top * FacEch)-Step(-7, 7)
            End If
            With Printer
                .FontName = ContImprim.FontName
                .FontBold = ContImprim.FontBold
                .FontSize = Int(ContImprim.FontSize * FacEch)
                .CurrentX = ContImprim.Left * FacEch + 10
                .CurrentY = ContImprim.Top * FacEch + 2
            End With
            Printer.Print ContImprim.Caption
            ElseIf TypeOf ContImprim Is MSFlexGrid Then
                With Printer
                    .CurrentX = ContImprim.Left * FacEch
                    .CurrentY = ContImprim.Top * FacEch
                End With
                Printer.PaintPicture ContImprim.Picture, Printer.CurrentX, Printer.CurrentY
            End If
Next
End sub

Bien sûr, il s'agit d'un exemple pour quelques types de contrôles, mais le principe peut facilement s'étendre. Pour les polices, n'oubliez pas de prendre des polices TrueType et arrondissez le résultat.

V-C. Impression d'un ListBox.

Nous allons prendre le cas d'une liste à sélection unique, peu importe si tous ses éléments sont visibles.

 
Sélectionnez
Dim RappL As Single, AligH As Single, MaChaine As String, LigSel As Integer, compteur As Long
AligH = Printer.CurrentX
For compteur = 0 To List1.ListCount - 1
    If List1.Selected(compteur) Then 
        LigSel = compteur
        MaChaine = List1.List(compteur)
        RappL =Iif (Printer.TextWidth(MaChaine) > RappL, Printer.TextWidth(MaChaine), RappL)
        Printer.Print MaChaine
        Printer.CurrentX = AligH
Next compteur
'encadrement de la liste
Printer.Line Step(-1, 0)-Step(RappL + 2, -1 * Printer.TextHeight(String$(List1.ListCount - 1, vbCrLf))), , B
'sur lignage de la sélection
Printer.Line Step(-1 * RappL - 2, Printer.TextHeight(String$(LigSel, vbCrLf)))-Step(RappL + 2, -1 *
Printer.TextHeight("")), QBColor(8), B

V-D. Impression de longues chaînes

En général, les chaînes sont coupées dans les contrôles par VbCrLf et l'impression se passe bien. Mais par exemples, lors de l'impression d'une chaîne qui n'apparaît pas sur le formulaire, ou dans un TextBox multiligne, ce caractère n'est pas présent dans la chaîne. L'imprimante risque alors de déborder du cadre ou de la feuille. On utilise alors la fonction suivante pour découper la chaîne.
N.B.  Cette fonction gère le cas de très longues chaînes, elle peut être optimisée si l'on est sûr de ne jamais rencontrer de chaîne de plus de 3 ou 4 lignes.

 
Sélectionnez
Private Function DecoupeChaine(ByVal TextLong As String, ByVal TailleMax As Single) As String()
Dim TabSplit() As String, TabRetour() As String, compteur1 As Long, compteur2 As Long
Dim TabMot() As String, ChaineInter As String
TabSplit = Split(TextLong, vbCrLf)
ReDim TabRetour(0 To 0)
For compteur1 = 0 To UBound(TabSplit)
    If Printer.TextWidth(TabSplit(compteur1)) > TailleMax Then
        TabMot = Split(TabSplit(compteur1), " ")
        For compteur2 = 0 To UBound(TabMot)
            If Printer.TextWidth(ChaineInter & " " & TabMot(compteur2)) > TailleMax Then
                TabRetour(UBound(TabRetour)) = ChaineInter
                ChaineInter = TabMot(compteur2)
                ReDim Preserve TabRetour(0 To UBound(TabRetour) + 1)
            Else
                ChaineInter = IIf(Len(ChaineInter) > 0, ChaineInter & " " & TabMot(compteur2),
                TabMot(compteur2))
            End If
        Next compteur2
        If Len(ChaineInter) > 0 Then
            TabRetour(UBound(TabRetour)) = ChaineInter
            ChaineInter = ""
            ReDim Preserve TabRetour(0 To UBound(TabRetour) + 1)
        End If
    Else
        TabRetour(UBound(TabRetour)) = TabSplit(compteur1)
        ReDim Preserve TabRetour(0 To UBound(TabRetour) + 1)
    End If
Next compteur1
ReDim Preserve TabRetour(0 To UBound(TabRetour) - 1)
DecoupeChaine = TabRetour
End Function

De manière générale il est bon de traiter ces chaînes de façon à ne pas laisser dedans de caractères « VbCrLf » ce qui ramènerait currentX contre la marge de gauche, sauf si c'est évidemment le but rechercher.

V-E. Imprimer un recordset ou une grille

Je regroupe ces deux cas, car ils sont identiques. En effet un recordset peut être imaginé comme une grille de colonne champ et de ligne enregistrement. J'ai mis dans cet exemple deux modes d'encadrement différents, avant ou après l'écriture de la chaîne.

 
Sélectionnez
Private Sub cmdPrint_Click()
    Dim TabLong() As Single, compteur As Long, Total As Single
    Dim NomChamp As String, ReqLong As New ADODB.Recordset, strSQL As String
    Dim XFixe As Single, YMobile As Single, prnstring As String, ConnTemp As New ADODB.Connection
    ConnTemp.ConnectionString = Adodc1.ConnectionString
    ConnTemp.Open
    With Printer
        .TrackDefault = True
        .ScaleMode = 6
        .Orientation = 1
        .PaperSize = 9
        .PrintQuality = -4
        .ColorMode = 1
    End With
    XFixe = 20 - (210 - Printer.ScaleWidth) / 2
    YMobile = 15 - (297 - Printer.ScaleHeight) / 2
    ReDim TabLong(ReqGrille.Fields.Count - 1)
    With ReqGrille
        For compteur = 0 To .Fields.Count - 1
            NomChamp = .Fields(compteur).Name
            strSQL = "SELECT MAX(len([" & NomChamp & "])) AS LeMax FROM LaTable"
            ReqLong.Open strSQL, ConnTemp, adOpenStatic, adLockReadOnly
            ReqLong.MoveFirst
            TabLong(compteur) = IIf(ReqLong!lemax > Len(NomChamp), ReqLong!lemax, Len(NomChamp))
            ReqLong.Close
            TabLong(compteur) = Printer.TextWidth(String(TabLong(compteur), "X")) + 4
            Total = Total + TabLong(compteur)
        Next compteur
        .MoveFirst
        Total = XFixe
        For compteur = 0 To .Fields.Count - 1
            Printer.Line (Total, YMobile)-Step(TabLong(compteur), 8), QBColor(6), BF
            prnstring = CStr(.Fields(compteur).Name)
            Printer.CurrentX = Total + TabLong(compteur) / 2 - Printer.TextWidth(prnstring) / 2
            Printer.CurrentY = (YMobile + 4) - Printer.TextHeight(prnstring) / 2
            Printer.Print prnstring
            Total = Total + TabLong(compteur)
        Next compteur
        YMobile = YMobile + 8
        While Not .EOF
            Total = XFixe
            For compteur = 0 To .Fields.Count - 1
                prnstring = CStr(.Fields(compteur).Value)
                Printer.CurrentX = Total + TabLong(compteur) / 2 - Printer.TextWidth(prnstring) / 2
                Printer.CurrentY = (YMobile + 4) - Printer.TextHeight(prnstring) / 2
                Printer.Print prnstring
                Total = Total + TabLong(compteur)
                Printer.Line (XFixe, YMobile)-Step(Total - XFixe, 8), , B
            Next compteur
            .MoveNext
            YMobile = YMobile + 8
        Wend
    End With
    Printer.EndDoc
End Sub

V-F. L'impression sur plusieurs pages

Le cas se pose en général, pour l'impression de longues listes, de grands tableaux. J'envisage ici le cas d'une impression continue. En effet, l'impression de plusieurs fiches liées à un recordset par exemple n'est jamais qu'un cas d'impression de page unique répété à chaque changement de ligne du recordset.

Mais supposons pour reprendre le cas précédent, que je souhaite imprimer ma grille sans connaître au préalable son nombre de lignes. Je vais prendre un exemple que j'ai développé, il y a quelques années pour une association qui organisait un concours de pêche.

Le travail était simple, tout tenait dans une table. Il fallait pouvoir imprimer la liste des participants, puis le classement.

Sur ma page devait apparaître le logo de l'association, le titre, la date, le tableau et en bas le numéro de page. Donc sur mon formulaire il y avait un contrôle image, deux labels et un MSFlexGrid (plus un dessin de poisson, mais lui il n'y avait pas besoin de l'imprimer).

Je me suis basé sur les marges habituelles, il me fallait trois centimètres en haut pour le logo, et un centimètre en bas pour le numéro de page. Chaque ligne devait faire 8 mm de haut.

L'impression était en paysage afin de pouvoir visualiser toutes les colonnes.

Afin de connaître le nombre de pages, pour pouvoir valoriser les propriétés FromPage et ToPage de la boite de dialogue d'impression, j'ai procédé comme suit :

Ma hauteur imprimable pour la grille était de 140 (210-2*15-30-10). Il rentrait donc 17 lignes de 8 mm par page soit 16 enregistrements plus la ligne de titre.

Ce préambule n'a pas pour but de faire de vous des experts en concours de pêche, mais bien de vous montrer comment je me suis posé le problème. Allons-y !

Le code est le même que celui fait précédemment, sauf la différence d'orientation, dans la fonction ci-dessous je mettrai juste les lignes différentes.

 
Sélectionnez
Private Sub Impression()
Printer.Orientation = 2
XFixe = 20 - (297 - Printer.ScaleWidth) / 2
YMobile = 45- (210 - Printer.ScaleHeight) / 2
NbLigne= ReqList.Recordcount
NbPage=Iif(NbLigne Mod 16 >0, NbLigne \ 16+1, NbLigne \ 16)

À la place de l'impression de la ligne de titre :

 
Sélectionnez
Call EntetePied(TabLong)
YMobile = YMobile + 8

Et dans la boucle du recordset un compteur qui :

 
Sélectionnez
If Compt16=16 then
    Compt16=0
    Printer.NewPage
    Call EntetePied
    YMobile = 53 - (210 - Printer.ScaleHeight) / 2 '53, car 45+8 de la première ligne
End if
End Sub
Private Sub EntetePied(TabTaille() as Single)
    Dim Xfixe!, Yfixe!, Total&, compteur&
    XFixe = 20 - (297 - Printer.ScaleWidth) / 2
    YFixe = 15 - (210 - Printer.ScaleHeight) / 2
    YfirstLigne = 45 - (210 - Printer.ScaleHeight) / 2
    Printer.PaintPicture imgLogo.Picture, XFixe, YFixe
    Printer.CurrentX=Printer.Width/2 - Printer.TextWidth(Titre)/2
    Printer.CurrentY=Yfixe+15- Printer.TextHeigth(Titre)/2
    Printer.Print Titre
    Printer.CurrentX=Printer.Width-20 - Printer.TextWidth(LaDate)
    Printer.CurrentY=Yfixe+15- Printer.TextHeigth(LaDate)/2
    Printer.Print LaDate
    'Insère la ligne de titre
    Total = XFixe
    For compteur = 0 To .Fields.Count - 1
        Printer.Line (Total, YMobile)-Step(TabTaille(compteur), 8), QBColor(6), BF
        prnstring = CStr(ReqGrille.Fields(compteur).Name)
        Printer.CurrentX = Total + TabTaille(compteur) / 2 - Printer.TextWidth(prnstring) / 2
        Printer.CurrentY = (YMobile + 4) - Printer.TextHeight(prnstring) / 2
        Printer.Print prnstring
        Total = Total + TabTaille(compteur)
    Next compteur
    'Met Le pied De page
    strPied="Page : " & Printer.Page & " de " & NbPage
    Printer.CurrentX=Printer.Width/2 - Printer.TextWidth(strPied)/2
    Printer.CurrentY=Yfixe+ Printer.ScaleHeight -20- Printer.TextHeigth(strPied)/2
    Printer.Print strPied
End sub

Vous pouvez noter que l'on peut très bien écrire le pied de page avant le corps du texte.

V-G. Prévisualisation

Bien sûr, vous vous voyez déjà poussant des wagonnets de feuilles vers l'imprimante afin de réaliser vos tests d'impression. Afin de sauver les forêts, je vais vous montrer comment fabriquer une feuille de visualisation.

Dans cet exemple, je reste dans un cas d'impression paysage, mais on peut faire un outil beaucoup plus complexe en gérant dynamiquement l'orientation de la feuille, faire une réduction de taille, etc.

Tous les scalemode de la feuille et des picturebox sont en millimètres

Dans ma feuille je mets les contrôles suivants :

  • Un commandButton

    caption

    Fermer

    Dans ma feuille je mets les contrôles suivant :

  • Un PictureBox

    AutoRedraw

    True

    Name

    PctCont

    Height

    109.5

    Width

    153

    Dans ma feuille je mets les contrôles suivants :

  • Dans ce PictureBox, un HscrollBar sur toute la largeur

    Name

    HScroll1

    LargeChange

    148

    SmallChange

    15

    Dans ma feuille je mets les contrôles suivants :

  • Un VscrollBar sur toute la hauteur

    Name

    VScroll1

    LargeChange

    105

    SmallChange

    10

    Dans ma feuille je mets les contrôles suivants :

  • Et enfin un autre pictureBox (donc contenu dans pctCont)

AutoRedraw

True

Appearance

Flat

Name

PctPict

Height

210

Index

1

Left

0

Top

0

Width

153

Dans ma feuille je mets les contrôles suivants :

Dans le code de cette feuille

 
Sélectionnez
Private Sub HScroll1_Change()
pctCible(1).Left = HScroll1.Value * -1
End Sub
Private Sub VScroll1_Change()
pctCible(1).Top = VScroll1.Value * -1
End Sub

L'astuce consiste à se dire qu'à peu de choses près l'objet printer et le PictureBox fonctionnent de la même façon.
Donc on écrit une fonction ou dans le code on remplacera partout Printer par Cible. Pour les méthodes différentes pour les deux objets, on fera un test avec la fonction Is

 
Sélectionnez
Public sub Impression (Cible as object)
If Cible Is Printer Then
    With Printer
        .TrackDefault = True
        .ScaleMode = 6
        .Orientation = 1
        .PaperSize = 9
        .PrintQuality = -4
        .ColorMode = 1
    End With
End if
'
'
'
If Cible Is Printer then
    Printer.EndDoc
Else
    frmView.Show
End If
End Sub

Le seul cas particulier étant pour NewPage

 
Sélectionnez
If Cible Is Printer then
    Printer.NewPage
Else
    Cible.Visible=False
    Load frmView.pctPict(Count+1)
    Set Cible= frmView.pctPict(Count)
    Cible.Visible=True
End if

Dans le cas d'une impression multipage, il convient de modifier le code d'événements des scrollbars.
L'appel de la fonction se fait de la manière suivante
Call Impression(frmView.pctPict.Picture)


précédentsommairesuivant

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Copyright © 2002 bidou. Aucune reproduction, même partielle, ne peut être faite de ce site ni 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.