Site:  Cours VB.net  
4.11 Imprimer.

            

Comment Imprimer ?

Prévoir une longue soirée, au calme, un bon siège, 1 g de paracétamol et un gros thermos de café!!

On verra que l'on peut utiliser pour imprimer:

A- La méthode .Net

Soit avec un composant 'PrintDocument'.

Soit avec une instance de 'la Class PrintDocument'.

 

B- On peut, en ajoutant une référence, imprimer comme en VB6 et c'est plus simple!! 

 

A- Avec PrintDocument

1 Imprimer 'Hello' avec le composant 'PrintDocument'

 L'utilisateur clique sur un bouton, cela imprime 'Hello'

Cet exemple utilise un 'composant PrintDocument'

Comment faire en théorie?

C'est le composant PrintDocument qui imprime.

En prendre un dans la boite à outils, le mettre dans un formulaire. Il apparaît sous le formulaire et se nomme PrintDocument1.

Pour imprimer il faut utiliser la méthode Print de ce composant PrintDocument; Il faut donc écrire l'instruction suivante: 

PrintDocument1.Print

Cette instruction appelle la procédure évènement PrintDocument1_PrintPage du composant PrintDocument et qui contient la logique d'impression. Un paramètre de cet évènement PrintPage  est l'objet graphique envoyé à l'imprimante (nommé e). C'est à vous de dessiner dans l'objet graphique (e) ce que vous voulez imprimer . En fin de routine, l'objet graphique sera imprimé (automatiquement).

En pratique:

Private Sub PrintDocument1_PrintPage(ByVal sender As System.Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage

End Sub

C'est cette procédure qui est fondamentale et qui contient les routines d'impression écrites par le programmeur. Les routines d'impression agissent sur l'objet graphique qui sera utilisé pour imprimer , cet objet graphique est fourni dans les paramètres de la procédure(ici c'est e qui est de type PrintPageEventArgs)

e.Graphics.DrawString("Hello", New Font("Arial", 80, FontStyle.Bold), Brushes.Black, 150, 125)

PrintDocument1.Print()

Voici le code complet:

Private Sub PrintDocument1_PrintPage(ByVal sender As System.Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage

e.Graphics.DrawString("Hello", New Font("Arial", 80, FontStyle.Bold), Brushes.Black, 150, 125)

End Sub

Private Sub ButtonPrint_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonPrint.Click

PrintDocument1.Print()

End Sub

Si je clique sur le bouton 'ImprimerHello' cela imprime un gros 'Hello'.

La méthode Print d'un PrintDocument déclenche l'évènement PrintPage de ce PrintDocument qui contient le code dessinant sur le graphique de la page à imprimer. En fin de routine PrintPage le graphique est imprimer sur la feuille de l'imprimante.

Toutes les méthodes graphiques écrivant, dessinant, traçant des lignes... sur un graphique permettent donc d'imprimer.

 

Imprimer un dessin:

Créons une ellipse bleue à l'intérieur d'un rectangle avec la position et les dimensions suivantes : début à 100, 150 avec une largeur de 250 et une hauteur de 250.


Private Sub PrintDocument1_PrintPage(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
   e.Graphics.FillEllipse(Brushes.Blue, New Rectangle(100, 150, 250, 250))
End Sub
 
Afficher un Message Box indiquant 'Fin d'impression'.

On a étudié l'évènement PrintPage, mais il existe aussi les évènements:

BeginPrint et EndPrint respectivement déclenchés en début et fin d'impression
 

Il suffit d'utiliser l'évènement EndPrint pour prévenir que l'impression est terminée:


Private Sub PrintDocument1_EndPrint(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintEventArgs) Handles PrintDocument1.EndPrint
   MessageBox.Show("Fin d'impression")
End Sub

On peut même fignoler et afficher "Fin d'impression de Nom du document"

Il faut avoir renseigné le DocumentName:

PrintDocument1.DocumentName = "MyTextFile"

Puis écrire:
Private Sub PrintDocument1_EndPrint(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintEventArgs) Handles PrintDocument1.EndPrint
   MessageBox.Show( "Fin d'impression de "+PrintDocument1.DocumentName)
End Sub

2-Même programme: Imprimer 'Hello' mais avec la Classe PrintDocument

 L'utilisateur clique sur un bouton, cela imprime 'Hello'

Cet exemple utilise 'une instance de la Classe PrintDocument'. On ne met pas de composant 'PrintDocument' dans le formulaire.

Comment faire en théorie?

Il faut importer l'espace de nom 'Printing' par :

Imports System.Drawing.Printing

Il faut créez  une instance de la Classe PrintDocument dans le module.

 Dim pd As new PrintDocument()

Il faut créer soi même, une routine pd_PrintPage .

Private Sub pd_PrintPage(sender As object, ev As System.Drawing.Printing.PrintPageEventArgs)
End sub

 

Il faut indiquer le "lien" entre l'objet  pd et la routine évènement PrintPage

AddHandler pd.PrintPage, AddressOf Me.pd_PrintPage

 

Dans la procédure Button_Click d'un bouton "Imprimer" il faut appeler la méthode Print  du PrintDocument pour effectuer l'impression du document .

pd.Print

 Cela déclenche la procédure Private Sub pd_PrintPage précédemment écrite, dans laquelle on a ajouté:

ev.Graphics.DrawString ("Hello", printFont, Brushes.Black, leftMargin, yPos, new StringFormat()).

 
Cela donne le code complet:

Imports System.Drawing.Printing

 

Public Class Form1

Inherits System.Windows.Forms.Form

 

Dim pd As  New PrintDocument 'Assumes the default printer

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    AddHandler pd.PrintPage, AddressOf Me.Pd_PrintPage

End Sub

Private Sub Pd_PrintPage(ByVal sender As System.Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs)

e.Graphics.DrawString("Hello", New Font("Arial", 80, FontStyle.Bold),   Brushes.Black, 150, 125)

End Sub

Private Sub ButtonPrint_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonPrint.Click

    pd.Print()

End Sub

 

End Class

 

Comment choisir l'imprimante?

Le composant PrintDialog permet le choix de l'imprimante, de la zone à imprimer (tout, la sélection..) et donne accès aux caractéristiques de l'imprimante.

Comment l'utiliser?

Il faut créer une instance de PrintDialog:

    Dim dlg As New PrintDialog

Il faut indiquer au PrintDialog sur quel PrintDocument travailler:

    dlg.Document = pd

Puis ouvrir la fenêtre PrintDialog avec la méthode ShowDialog.

L'utilisateur choisit son imprimante puis clique sur 'Ok'.

Si elle retourne Ok, on imprime.

Quand l'utilisateur clique sur le bouton ButtonPrint ('Imprimer')  la fenêtre PrintDialog s'ouvre:

 

Voici le code complet:

Private Sub ButtonPrint_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonPrint.Click

Dim dlg As New PrintDialog

dlg.Document = pd

Dim result As DialogResult = dlg.ShowDialog()

If (result = System.Windows.Forms.DialogResult.OK) Then

    pd.Print()

End If

 

End Sub

 

Comment modifier la page à imprimer?

Comment choisir d'imprimer en portrait ou paysage? modifier les marges..

Il faut utiliser un composant PageSetUpDialog.

Pour stocker les informations sur la page (marges...) il faut un PageSetting

Je lie le PageSetting au PageSetUpDialog en donnant à la propriété PageSettings du PageSetUpDialog le nom du PageSetting.

puis j'ouvre le PageSetUpDialog.

Au retour le PageSetting contient les modifications, je les 'passe' au PrintDocument avant d'imprimer.

Cela donne:

Dim psDlg As New PageSetupDialog

Dim LePageSettings As New PageSettings

psDlg. PageSettings = LePageSettings

psDlg.ShowDialog()

pd.DefaultPageSettings = LePageSettings

 

Prévisualisation de la page à imprimer?

On utilise pour cela un PrintPreviewDialog, on lui indique quel PrintDocument pré visualiser en l'assignant à sa méthode document puis on l'affiche par ShowDialog().

Dim dllg As New PrintPreviewDialog

dllg.Document = pd

dllg.ShowDialog()

 
Construction d'une application d'impression complexe:

Comment imprimer le contenu d'un fichier texte?

Tous les didacticiels (Microsoft compris) donnent cet exemple.

La première chose que vous devez faire est d'écrire votre logique d'impression. Pour cela, quand la méthode PrintDocument.Print() est appelée, les événements suivants sont déclenchés.

La fonction PrintPage est appelée autant de fois qu'il y a de page.
Par défaut une document à une seule page. Si en imprimant la page on veut faire un  saut de page, on positionne:

e.HasMorePages = true


Cela fait un saut de page et déclenche de nouveau PrintPage pour la page suivante. Il faut donc  incrémenter une variable à chaque appel de cette fonction afin de savoir quelle est la page courante.

 

L'argument d'événement de PagePrint (PagePrintEventArgs) comprend une propriété HasMorePages. Si celle-ci a la valeur True lors du retour de votre gestionnaire d'événements, PrintDocument définit une nouvelle page et déclenche de nouveau l'événement PagePrint.

Voyons la logique dans votre gestionnaire d'événements PagePrint :

Il faut dans la procédure PagePrint imprimer ligne par ligne en se déplaçant à chaque fois vers le bas d'une hauteur de ligne.

Pour 'simplifier', on considère que chaque ligne ne déborde pas à droite!!

 

Public Class ExampleImpression
    Inherits System.Windows.Forms.Form

    ....

    private printFont As Font
    private streamToPrint As StreamReader

    Public Sub New ()
        MyBase.New
        InitializeComponent()
    End Sub


    'Evénement survenant lorsque l'utilisateur clique sur le bouton 'Imprimer'
    Private Sub printButton_Click(sender As object, e As System.EventArgs)

        Try
            streamToPrint = new StreamReader ("PrintMe.Txt")
            Try
                printFont = new Font("Arial", 10)
                Dim pd as PrintDocument = new PrintDocument()
'déclaration du PrintDocument
                AddHandler pd.PrintPage, AddressOf Me.pd_PrintPage
                pd.Print()
            Finally
                streamToPrint.Close()
            End Try

        Catch ex As Exception
            MessageBox.Show("Une erreur est survenue: - " + ex.Message)
        End Try

    End Sub

   
'Evènement survenant pour chaque page imprimer
    Private Sub pd_PrintPage(sender As object, ev As System.Drawing.Printing.PrintPageEventArgs)

        Dim lpp As Single = 0   
'nombre de ligne par page
        Dim yPos As Single =  0 
'ordonnée  
        Dim count As Integer = 0
'numéro de ligne
        Dim leftMargin As Single = ev.MarginBounds.Left
        Dim topMargin As Single = ev.MarginBounds.Top
        Dim line as String

       
'calcul le nombre de ligne par page
        ' hauteur de la page/hauteur de la police de caractère

        lpp = ev.MarginBounds.Height  / printFont.GetHeight(ev.Graphics)

      
       
'lit une ligne dans le fichier
        line=streamToPrint.ReadLine()
       

        'Boucle affichant chaque ligne   

        while (count < lpp AND line <> Nothing)

            yPos = topMargin + (count * printFont.GetHeight(ev.Graphics))

           
'Ecrit le texte dans l'objet graphique
            ev.Graphics.DrawString (line, printFont, Brushes.Black, leftMargin, _
                                    yPos, new StringFormat())

            count = count + 1

            if (count < lpp) then
                line=streamToPrint.ReadLine()
            end if

        End While

       
'S'il y a encore des lignes, on réimprime une page
        If (line <> Nothing) Then
            ev.HasMorePages = True
        Else
            ev.HasMorePages = False
        End If

    End Sub

    ....

End Class


On a vu que pour 'simplifier', on considère que chaque ligne ne déborde pas à droite.
Dans la pratique, pour gérer les retours à la ligne automatiques on peut dessiner dans un rectangle en utilisant une surcharge de DrawString.

Dim rectangle As New RectangleF (100, 100, 150, 150 )

Dim T as String= "Chaîne de caractères très longue"

g.DrawString (T, Me.Font, New SolidBrush (ColorBlack), Rectangle)

On peut mesurer la longueur (ou le nombre de lignes) d'une chaîne:

Avec MeasureString

(Voir la page sur les graphiques.)
 
Propriétés du 'PrintDocumet':

On peut sans passer par une 'boite de dialog' gérer directement l'imprimante, les marges, le nombre de copies..

Si pd est le PrintDocument:

pd.PrinterSetting    désigne l'imprimante en cours

pd.PrinterSetting.PrinterName retourne ou définit le nom de cet imprimante

pd.PrinterSetting.Printerresolution  donne la résolution de cette imprimante.

pd.PrinterSetting.installedPrinted   donne toutes les imprimantes installées.

La propriété DefaultPageSetting est en rapport avec les caractéristiques de la page.

pd.PrinterSetting.DefaultPageSetting.Margins donne les marges

pd.PrinterSetting.PrinttoFile  permettrait d'imprimer dans un fichier (non testé)

 

 Imprime le formulaire en cours.

Exemple fournit par Microsoft.

La routine CaptureScreen capture l'image du formulaire en cours et la met dans memoryImage. puis memoryImage est passé dans l'objet graphique e qui est imprimé.

Private Declare Function BitBlt Lib "gdi32.dll" Alias "BitBlt" (ByVal _
   hdcDest As IntPtr, ByVal nXDest As Integer, ByVal nYDest As _
   Integer, ByVal nWidth As Integer, ByVal nHeight As Integer, ByVal _
   hdcSrc As IntPtr, ByVal nXSrc As Integer, ByVal nYSrc As Integer, _
   ByVal dwRop As System.Int32) As Long
Dim memoryImage As Bitmap
Private Sub CaptureScreen()
   Dim mygraphics As Graphics = Me.CreateGraphics()
   Dim s As Size = Me.Size
   memoryImage = New Bitmap(s.Width, s.Height, mygraphics)
   Dim memoryGraphics As Graphics = Graphics.FromImage(memoryImage)
   Dim dc1 As IntPtr = mygraphics.GetHdc
   Dim dc2 As IntPtr = memoryGraphics.GetHdc
   BitBlt(dc2, 0, 0, Me.ClientRectangle.Width, _
      Me.ClientRectangle.Height, dc1, 0, 0, 13369376)
   mygraphics.ReleaseHdc(dc1)
   memoryGraphics.ReleaseHdc(dc2)
End Sub
Private Sub PrintDocument1_PrintPage(ByVal sender As System.Object, _
   ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles _
   PrintDocument1.PrintPage
   e.Graphics.DrawImage(memoryImage, 0, 0)
End Sub
Private Sub PrintButton_Click(ByVal sender As System.Object, ByVal e As _
   System.EventArgs) Handles PrintButton.Click
   CaptureScreen()
   PrintDocument1.Print()
End Sub
 
Imprime un contrôle DataGrid.

Exemple fournit par Microsoft.

Cet exemple nécessite :

Comme d'habitude PrintPage imprime e.Graphics.
D'après ce que j'ai compris, l'évènement Paint redessine un contrôle 
mais on peut choisir le contrôle et l'endroit ou le redessiner,
Je redessine donc grâce à Paint,le DataGrid dans e.graphics.  
PaintEventArgs Fournit les données pour l'événement Paint: 

PaintEventArgs spécifie l'objet graphics à utiliser pour peindre le contrôle, ainsi que le ClipRectangle dans lequel le peindre.

InvokePaint déclenche l'évènement Paint

Private Sub ImprimerGrid_Click(ByVal sender As System.Object, ByVal e As _
   System.EventArgs) Handles PrintGrid.Click
   PrintDocument1.Print()
End Sub

Private Sub PrintDocument1_PrintPage(ByVal sender As System.Object, _
   ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles _
   PrintDocument1.PrintPage
   Dim myPaintArgs As New PaintEventArgs(e.Graphics, New Rectangle(New _
      Point(0, 0), Me.Size))
   Me.InvokePaint(DataGrid1, myPaintArgs)
End Sub
 

Imprime le texte d'un RichTextBox

Voir Imprimer le contenu d'une RichtextBox

Simple, non!!  Je plaisante!!

 

B- Imprimer comme en VB6 avec un objet 'Printer' 

Microsoft propose un PowerPack de compatibilité vb6 le 'Microsoft.VisualBasic.PowerPacks.Printing.Printer' qui ajoute à VB 2005 une Classe permettant d'imprimer 'comme en VB6'; cela permet d'utiliser votre code de routine d'impression VB6 ou de créer des routines d'impression beaucoup plus simple!!

Télécharger le  PowerPack Printercompatibility 1

Voir la Documentation complète

Après avoir installé le Pack, aller dans le menu Project cliquer sur 'Ajouter une référence'.

Sur l'onglet NET , cliquez sur  Microsoft.VisualBasic.PowerPacks.Printing.Printer, puis sur OK.

Dans le  Code, ajouter en haut du module:

    Imports Microsoft.VisualBasic.PowerPacks.Printing.Compatibility.VB6

Maintenant on peut utiliser du code VB6 pour imprimer:

Dim pr As New Printer        'Instanciation de l'imprimante par défaut

Dim pFont As New Font("Arial", 14)    'Une nouvelle font

pr.Font = pFont

pr.Print("This text will print in 14 point ")  'Texte à imprimer

pr.EndDoc()    'fin, on lance l'impression

Simple, non!!  Je plaisante pas!!

 

 DrawMode, DriverName, hDC, Port, TrackDefault, et Zoom n'existent plus.

Par contre il y a en plus:  PrintAction property  qui permet un print preview ou permet d'imprimer dans un fichier.

Il y a aussi la  PrinterCollection class qui contient les imprimantes . La  global Printers collection permet de sélectionner une imprimante.