none
How to send graphics to a printer? RRS feed

  • Question

  • Can someone please tell me how to send graphics to a printer - or point me to a suitable webpage?

    I know how to send a string of text to a printer - and I know how to send graphics to a form.  The form which displays my graphics has a button with the name CmdPrint, and I simply need to know what code to put inside 
    Private Sub CmdPrint_Click(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles CmdPrint.Click

    If it helps, I display the graphics on the form using

        Private Sub frmStat_Repaint(ByVal eventSender As Object, ByVal e As PaintEventArgs) Handles MyBase.Paint
            Call frmMain.Drawgraphics(Me)
        End Sub

    where Drawgraphics looks like

    Public Sub Drawgraphics(destform As Form)
            Dim gr As Graphics = destform.CreateGraphics
            gr.Clear(Color.CornflowerBlue)
            gr.DrawRectangle(Pens.Black, 10, 10, 50, 50)
            .........
            gr.Dispose()
     End Sub

    Thanks in advance for your help!

    Friday, February 24, 2017 3:05 PM

Answers

  • Thanks.  I can see that PrintDocument is part of the solution, but what I don't understand is how to

    1  create a suitable print document, and then direct the graphics towards it (given that my Subroutine expects to send its graphics to a form)

    2  send the resulting document to the required printer (selected in Printdialog1.Showdialog)



    If it can't be done in Fortran 77 it's not worth doing, IMO

    Modify your subroutine so that it takes a Graphics instance as a parameter.  When you draw on the form, pass the form's graphics objects.  When you print, pass the PrintDocument's graphics object.

    e.g

    Public Sub Drawgraphics(g as Graphics)
            Dim gr As Graphics = g
            gr.Clear(Color.CornflowerBlue)
            gr.DrawRectangle(Pens.Black, 10, 10, 50, 50)
            .........
            gr.Dispose()
     End Sub
        Private Sub frmStat_Repaint(ByVal eventSender As Object, ByVal e As PaintEventArgs) Handles MyBase.Paint
            Call frmMain.Drawgraphics(e.Graphics)
        End Sub

    From within the Paint event handler, and the PrintDocument.PrintPage event handler, the event args parameter give you access to the related graphics object.  No need to use CreateGraphics (in fact, it will cause you problems - take you current code, execute the drawing to the form, then resize the form or drag another window over top of it and see how the drawing is "erased").

    -EDIT-

    Sorry, I suppose it does appear to work since you re-create the graphics instance on the Paint event.  Still, it is unnecessary to manually create the graphics object and if it is not disposed of you could be creating a memory leak situation.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"


    Friday, February 24, 2017 3:36 PM
    Moderator
  • Excellent - I now have a working Drawgraphics subroutine which takes an argument of type Graphics instead of type Form.

    But what do I do in Sub CmdPrint_Click?  I've tried saying Dim pr As New Printing.PrintDocument()  but pr does not then seem to have a graphics  member...

    And then, how do I actually send the resulting document to the printer of my choice?



    If it can't be done in Fortran 77 it's not worth doing, IMO

    Drag an instance of PrintDocument from the toolbox onto your form.  Double click the component to create the default handler for the PrintPage event.  In that handler, add your code to call the drawing routine.

    Your print button then just calls the Print method on the PrintDocument instance.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    • Marked as answer by Aylmer51 Friday, February 24, 2017 5:09 PM
    Friday, February 24, 2017 4:09 PM
    Moderator
  • Oh, also, you can drag a PrintDialog onto the form to select the printer and options.  Make sure you set the Document property of the PrintDialog to your PrintDocument instance.

    Here's a really short example:

    Public Class Form1
        Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
            DrawGraphics(e.Graphics)
        End Sub
    
        Private Sub PrintDocument1_PrintPage(sender As Object, e As Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
            DrawGraphics(e.Graphics)
        End Sub
    
        Private Sub PrintToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles PrintToolStripMenuItem.Click
            If PrintDialog1.ShowDialog = DialogResult.OK Then
                PrintDocument1.Print()
            End If
        End Sub
    
        Private Sub DrawGraphics(g As Graphics)
            Dim bounds = Me.ClientRectangle
            bounds.Inflate(-50, -50)
            g.DrawRectangle(Pens.Blue, bounds)
        End Sub
    End Class


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    • Marked as answer by Aylmer51 Friday, February 24, 2017 5:08 PM
    Friday, February 24, 2017 4:22 PM
    Moderator
  • Those other event handlers should just need to call Invalidate() to force the form to repaint itself.  All of the actual drawing must be done in the draw routine so you may need to pass around some other variables, depending on what these other event handlers were doing.

    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    • Marked as answer by Aylmer51 Friday, February 24, 2017 5:23 PM
    Friday, February 24, 2017 5:03 PM
    Moderator

All replies

  • You can see this thread for example.
    Friday, February 24, 2017 3:10 PM
  • Thanks.  I can see that PrintDocument is part of the solution, but what I don't understand is how to

    1  create a suitable print document, and then direct the graphics towards it (given that my Subroutine expects to send its graphics to a form)

    2  send the resulting document to the required printer (selected in Printdialog1.Showdialog)



    If it can't be done in Fortran 77 it's not worth doing, IMO

    Friday, February 24, 2017 3:22 PM
  • Thanks.  I can see that PrintDocument is part of the solution, but what I don't understand is how to

    1  create a suitable print document, and then direct the graphics towards it (given that my Subroutine expects to send its graphics to a form)

    2  send the resulting document to the required printer (selected in Printdialog1.Showdialog)



    If it can't be done in Fortran 77 it's not worth doing, IMO

    Modify your subroutine so that it takes a Graphics instance as a parameter.  When you draw on the form, pass the form's graphics objects.  When you print, pass the PrintDocument's graphics object.

    e.g

    Public Sub Drawgraphics(g as Graphics)
            Dim gr As Graphics = g
            gr.Clear(Color.CornflowerBlue)
            gr.DrawRectangle(Pens.Black, 10, 10, 50, 50)
            .........
            gr.Dispose()
     End Sub
        Private Sub frmStat_Repaint(ByVal eventSender As Object, ByVal e As PaintEventArgs) Handles MyBase.Paint
            Call frmMain.Drawgraphics(e.Graphics)
        End Sub

    From within the Paint event handler, and the PrintDocument.PrintPage event handler, the event args parameter give you access to the related graphics object.  No need to use CreateGraphics (in fact, it will cause you problems - take you current code, execute the drawing to the form, then resize the form or drag another window over top of it and see how the drawing is "erased").

    -EDIT-

    Sorry, I suppose it does appear to work since you re-create the graphics instance on the Paint event.  Still, it is unnecessary to manually create the graphics object and if it is not disposed of you could be creating a memory leak situation.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"


    Friday, February 24, 2017 3:36 PM
    Moderator
  • Excellent - I now have a working Drawgraphics subroutine which takes an argument of type Graphics instead of type Form.

    But what do I do in Sub CmdPrint_Click?  I've tried saying Dim pr As New Printing.PrintDocument()  but pr does not then seem to have a graphics  member...

    And then, how do I actually send the resulting document to the printer of my choice?



    If it can't be done in Fortran 77 it's not worth doing, IMO

    Friday, February 24, 2017 3:55 PM
  • Excellent - I now have a working Drawgraphics subroutine which takes an argument of type Graphics instead of type Form.

    But what do I do in Sub CmdPrint_Click?  I've tried saying Dim pr As New Printing.PrintDocument()  but pr does not then seem to have a graphics  member...

    And then, how do I actually send the resulting document to the printer of my choice?



    If it can't be done in Fortran 77 it's not worth doing, IMO

    Drag an instance of PrintDocument from the toolbox onto your form.  Double click the component to create the default handler for the PrintPage event.  In that handler, add your code to call the drawing routine.

    Your print button then just calls the Print method on the PrintDocument instance.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    • Marked as answer by Aylmer51 Friday, February 24, 2017 5:09 PM
    Friday, February 24, 2017 4:09 PM
    Moderator
  • Oh, also, you can drag a PrintDialog onto the form to select the printer and options.  Make sure you set the Document property of the PrintDialog to your PrintDocument instance.

    Here's a really short example:

    Public Class Form1
        Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
            DrawGraphics(e.Graphics)
        End Sub
    
        Private Sub PrintDocument1_PrintPage(sender As Object, e As Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
            DrawGraphics(e.Graphics)
        End Sub
    
        Private Sub PrintToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles PrintToolStripMenuItem.Click
            If PrintDialog1.ShowDialog = DialogResult.OK Then
                PrintDocument1.Print()
            End If
        End Sub
    
        Private Sub DrawGraphics(g As Graphics)
            Dim bounds = Me.ClientRectangle
            bounds.Inflate(-50, -50)
            g.DrawRectangle(Pens.Blue, bounds)
        End Sub
    End Class


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    • Marked as answer by Aylmer51 Friday, February 24, 2017 5:08 PM
    Friday, February 24, 2017 4:22 PM
    Moderator
  • Thanks, this is working beautifully!

    The only remaining problem is that there are various other subroutines attached to the form (mousemove, formresize &c.) which also need to call DrawGraphics - but they now can't do so, because they don't have access to PaintEventArgs, or PrintPagEeventArgs, so cannot pass over the form's graphics member.

    Can you solve that one, too? :-)


    If it can't be done in Fortran 77 it's not worth doing, IMO

    Friday, February 24, 2017 4:53 PM
  • Those other event handlers should just need to call Invalidate() to force the form to repaint itself.  All of the actual drawing must be done in the draw routine so you may need to pass around some other variables, depending on what these other event handlers were doing.

    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    • Marked as answer by Aylmer51 Friday, February 24, 2017 5:23 PM
    Friday, February 24, 2017 5:03 PM
    Moderator
  • Perfect! Your help has been remarkably easy to apply - which I guess is what you are referring to, in your 'signature'.

    You have saved me hours(/days/weeks) of trawling through Microsoft documentation to find the answer to this problem - I am truly grateful.

    If it can't be done in Fortran 77 it's not worth doing, IMO

    Friday, February 24, 2017 5:23 PM
  • Perfect! Your help has been remarkably easy to apply - which I guess is what you are referring to, in your 'signature'.

    You have saved me hours(/days/weeks) of trawling through Microsoft documentation to find the answer to this problem - I am truly grateful.

    If it can't be done in Fortran 77 it's not worth doing, IMO

    You're quite welcome.  :)

    The quote is actually from an episode of Futurama, but I've found it applicable to many aspects of life. 


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Saturday, February 25, 2017 2:08 PM
    Moderator