John
John

Reputation: 65

How do I set the margins for the PrintDocument?

I am having a terrible time trying to allow the user to set the margins for a report. Right now I have it hard coded but I would prefer to set them at run time so they can be changed. I tried this:

Private Sub rotHCReport_BeginPrint(ByVal sender As Object, _
      ByVal e As System.Drawing.Printing.PrintEventArgs) Handles Me.BeginPrint

    Me.OriginAtMargins = True
    Me.DefaultPageSettings.Margins = New Margins(25, 25, 25, 25)

End Sub

To print a 1/4" margin which is well beyond the printer's hard margins. Nothing prints. According to Margins the arguments are in hundreds of an inch. If I change the code to:

Private Sub rotHCReport_BeginPrint(ByVal sender As Object, _
      ByVal e As System.Drawing.Printing.PrintEventArgs) Handles Me.BeginPrint

    Me.OriginAtMargins = True
    Me.DefaultPageSettings.Margins = New Margins(20, 20, 23, 23)

End Sub

I do get good output: Good output

But when I change the code to:

Private Sub rotHCReport_BeginPrint(ByVal sender As Object, _
      ByVal e As System.Drawing.Printing.PrintEventArgs) Handles Me.BeginPrint

    Me.OriginAtMargins = True
    Me.DefaultPageSettings.Margins = New Margins(21, 20, 23, 23)

End Sub

This is what I get, which makes no sense. It looks like it shifts over 1 inch: Bad output

And I am not the only one having problems with margins, there is no response here and I even posted to microsoft, with no response.

Since report writers can produce the majority of documents I will presume not many people use the PrintDocument object. So I am seeing what anyone here has to say before I report a bug to Microsoft, which will take a considerable time for a response to come from then.

EDIT: I made a simpler version and got similar but still strange results. I had to leave a lot of the code in the class, class definitions, properties, ect. that the caller requires. I just removed (almost) all the code from the events.

Here is the event code:

Private Sub rotHCReport_BeginPrint(ByVal sender As Object, _
      ByVal e As System.Drawing.Printing.PrintEventArgs) Handles Me.BeginPrint

    Me.OriginAtMargins = True
    Me.DefaultPageSettings.Margins = New Margins(19, 20, 23, 23)
    mintLevel = 0
    'Reset the loop trackers (used when we need to break out to print a page but remember our place) and others.
    mintRowLoopStart = 0
    mintTableLoopStart = 0
    'Flags
    ResetHeaderFooterFlags()
    'Page counters
    mintCurrentPage = 0
    mintTotalPages = 0

End Sub

Private Sub rotHCReport_QueryPageSettings(ByVal sender As Object, _
     ByVal e As System.Drawing.Printing.QueryPageSettingsEventArgs) Handles Me.QueryPageSettings

    e.PageSettings.Landscape = mePageOrientation = Orientation.Landscape
    mintCurrentPage += 1

End Sub

Private Sub rotHCReport_PrintPage(ByVal sender As Object, _
    ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles Me.PrintPage


    Dim DR As DataRow
    Dim PrintFont As Font


    e.Graphics.PageUnit = GraphicsUnit.Inch
    PrintFont = New Font("Arial", 8, FontStyle.Regular)

    For intRow = 0 To 10

        DR = mDS.Tables(0).Rows(intRow)

        For intColumn = 0 To 5

            e.Graphics.DrawString(DR(intColumn).ToString, PrintFont, New SolidBrush(Color.Black), intColumn + 1, CSng(intRow + 1))

        Next
    Next

End Sub

Private Sub rotHCReport_EndPrint(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintEventArgs) Handles Me.EndPrint

    mbSetUpRequired = True

End Sub

Which produces (looks less than 1/8 of an inch): Less

And changing:

Me.DefaultPageSettings.Margins = New Margins(20, 20, 23, 23)

Produces (looks more than 1/4 inch): enter image description here

EDIT2: I tried TnTinMn's technique and I had a difficult time understanding the TranslateTransform method. From my testing it almost sounds like it "adds" to whatever margin you have. Worse, if I use 0 I get a larger margin than what I have set, OriginAtMargins makes no difference at this point. What I am trying to do is create a consistent margin across printers.

Private Sub rotHCReport_BeginPrint(ByVal sender As Object, _
      ByVal e As System.Drawing.Printing.PrintEventArgs) Handles Me.BeginPrint

    'Me.OriginAtMargins = True
    Me.DefaultPageSettings.Margins = New Margins(25, 25, 25, 25)
    'Subreport level
    mintLevel = 0
    'Reset the loop trackers (used when we need to break out to print a page but remember our place) and others.
    mintRowLoopStart = 0
    mintTableLoopStart = 0
    'Flags
    ResetHeaderFooterFlags()
    'Page counters
    mintCurrentPage = 0
    mintTotalPages = 0

End Sub

Private Sub rotHCReport_QueryPageSettings(ByVal sender As Object, _
     ByVal e As System.Drawing.Printing.QueryPageSettingsEventArgs) Handles Me.QueryPageSettings

    e.PageSettings.Landscape = mePageOrientation = Orientation.Landscape
    mintCurrentPage += 1

End Sub


Private Sub rotHCReport_PrintPage(ByVal sender As Object, _
    ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles Me.PrintPage


    Dim DR As DataRow
    Dim PrintFont As Font


    e.Graphics.PageUnit = GraphicsUnit.Inch
    e.Graphics.ResetTransform()
    e.Graphics.TranslateTransform(e.MarginBounds.X / 100.0F, e.MarginBounds.Y / 100.0F)
    PrintFont = New Font("Arial", 8, FontStyle.Regular)

    For intRow = 0 To 10

        DR = mDS.Tables(0).Rows(intRow)

        For intColumn = 0 To 5

            e.Graphics.DrawString(DR(intColumn).ToString, PrintFont, New SolidBrush(Color.Black), CSng(intColumn + 1), CSng(intRow + 1))

        Next
    Next

End Sub

Private Sub rotHCReport_EndPrint(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintEventArgs) Handles Me.EndPrint

    mbSetUpRequired = True

End Sub

Which produces: enter image description here

I can change the TranslateTransform call to this:

e.Graphics.TranslateTransform(-e.MarginBounds.X / 100.0F, -e.MarginBounds.Y / 100.0F)

Which produces this, better, but I already have a hack job working. I am trying to figure out how to do this right.

enter image description here

It seems a great mystery on how to use the PrintDocument properly.

TnTinMn is using the PrintController while I am using the PrintDocument. I tried incorporating his proposed change and it did not work at all. Any idea how to get these two object to work together?

Public Class NewController
    Inherits PrintController

    Public Overrides Function OnStartPage(ByVal document As System.Drawing.Printing.PrintDocument, ByVal e As System.Drawing.Printing.PrintPageEventArgs) As System.Drawing.Graphics

        Dim g As System.Drawing.Graphics


        g = MyBase.OnStartPage(document, e)
        g.PageUnit = GraphicsUnit.Inch
        g.ResetTransform()
        g.TranslateTransform((e.MarginBounds.X - e.PageSettings.HardMarginX) / 100.0F, (e.MarginBounds.Y - e.PageSettings.HardMarginY) / 100.0F)

        'This does not work either
        'e.Graphics.PageUnit = GraphicsUnit.Inch
        'e.Graphics.ResetTransform()
        'e.Graphics.TranslateTransform((e.MarginBounds.X - e.PageSettings.HardMarginX) / 100.0F, (e.MarginBounds.Y - e.PageSettings.HardMarginY) / 100.0F)

        'Return e.Graphics
        Return g

    End Function
End Class

And I changed the other class.

Private mPC As NewController


Public Sub New()

    MyBase.New()
    mPC = New NewController
    Me.PrintController = mPC

End Sub

Private Sub rotHCReport_BeginPrint(ByVal sender As Object, _
      ByVal e As System.Drawing.Printing.PrintEventArgs) Handles Me.BeginPrint

    Me.DefaultPageSettings.Margins = New Margins(25, 25, 25, 25)
    'Subreport level
    mintLevel = 0
    'Reset the loop trackers (used when we need to break out to print a page but remember our place) and others.
    mintRowLoopStart = 0
    mintTableLoopStart = 0
    'Flags
    ResetHeaderFooterFlags()
    'Page counters
    mintCurrentPage = 0
    mintTotalPages = 0

End Sub

'Raised before each and every page
Private Sub rotHCReport_QueryPageSettings(ByVal sender As Object, _
     ByVal e As System.Drawing.Printing.QueryPageSettingsEventArgs) Handles Me.QueryPageSettings

    e.PageSettings.Landscape = mePageOrientation = Orientation.Landscape
    mintCurrentPage += 1

End Sub


Private Sub rotHCReport_PrintPage(ByVal sender As Object, _
    ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles Me.PrintPage


    Dim DR As DataRow
    Dim PrintFont As Font


    e.Graphics.PageUnit = GraphicsUnit.Inch
    PrintFont = New Font("Arial", 8, FontStyle.Regular)

    For intRow = 0 To 10

        DR = mDS.Tables(0).Rows(intRow)

        For intColumn = 0 To 5

            e.Graphics.DrawString(DR(intColumn).ToString, PrintFont, New SolidBrush(Color.Black), CSng(intColumn + 1), CSng(intRow + 1))
            'millimetersd
            'e.Graphics.DrawString(DR(intColumn).ToString, PrintFont, New SolidBrush(Color.Black), CSng((intColumn + 1) * 25.4), CSng((intRow + 1) * 25.4))

        Next
    Next

End Sub

Private Sub rotHCReport_EndPrint(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintEventArgs) Handles Me.EndPrint

    mbSetUpRequired = True

End Sub

Same results.

EDIT FINAL: TnTinMn's solution worked perfectly. I think I made an error somewhere copying the code between here, my test dll and production dll. In any event, I went over everything again, albeit a little more carefully and it worked. Here is the code that worked in test (and the same technique worked in production)

Private Sub rotHCReport_BeginPrint(ByVal sender As Object, _
      ByVal e As System.Drawing.Printing.PrintEventArgs) Handles Me.BeginPrint

    'Me.OriginAtMargins = True 'Don't need this anymore
    Me.DefaultPageSettings.Margins = New Margins(25, 25, 25, 25) 'These are the margins actually used
    'Subreport level
    mintLevel = 0
    'Reset the loop trackers (used when we need to break out to print a page but remember our place) and others.
    mintRowLoopStart = 0
    mintTableLoopStart = 0
    'Flags
    ResetHeaderFooterFlags()
    'Page counters
    mintCurrentPage = 0
    mintTotalPages = 0

End Sub

'Raised before each and every page
Private Sub rotHCReport_QueryPageSettings(ByVal sender As Object, _
     ByVal e As System.Drawing.Printing.QueryPageSettingsEventArgs) Handles Me.QueryPageSettings

    e.PageSettings.Landscape = mePageOrientation = Orientation.Landscape
    mintCurrentPage += 1

End Sub

Private Sub rotHCReport_PrintPage(ByVal sender As Object, _
    ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles Me.PrintPage

    Dim DR As DataRow
    Dim PrintFont As Font


    e.Graphics.PageUnit = GraphicsUnit.Inch
    e.Graphics.ResetTransform()
    e.Graphics.TranslateTransform((e.MarginBounds.X - e.PageSettings.HardMarginX) / 100.0F, (e.MarginBounds.Y - e.PageSettings.HardMarginY) / 100.0F)
    PrintFont = New Font("Arial", 8, FontStyle.Regular)

    For intRow = 0 To 10

        DR = mDS.Tables(0).Rows(intRow)

        For intColumn = 0 To 5

            e.Graphics.DrawString(DR(intColumn).ToString, PrintFont, New SolidBrush(Color.Black), CSng(0.25 + intColumn), CSng(0.25 + intRow))

        Next
    Next

End Sub

Private Sub rotHCReport_EndPrint(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintEventArgs) Handles Me.EndPrint

    mbSetUpRequired = True

End Sub

I set 1/4" margins and I got 1/4" margins! Here's my 7th screenshot, lucky #7.

enter image description here

Upvotes: 4

Views: 10168

Answers (1)

TnTinMn
TnTinMn

Reputation: 11801

In your PrintPage handler, you have the statement e.Graphics.PageUnit = GraphicsUnit.Inch and are thus causing the problem. The received e.Graphics.PageUnit is set to Display and the Graphics has a coordinate transform applied to it that reflects your OriginAtMargins = True setting. The transforms' OffsetX and OffsetY values were computed using the Display PageUnit setting (in 1/100 inch). When you change the PageUnit to Inch those offsets are now interpreted as Inches and whatever you are drawing on the Graphics is drawn out of bounds. This is why you get an empty page.

You should be able to eliminate the OriginAtMargins = True statement and modify the PrintPage handler code like this:

e.Graphics.PageUnit = GraphicsUnit.Inch
e.Graphics.ResetTransform() ' clear any previous transforms
e.Graphics.TranslateTransform((e.MarginBounds.X - e.PageSettings.HardMarginX) / 100.0F, (e.MarginBounds.X - e.PageSettings.HardMarginY) / 100.0F)

Edit: I corrected the TranslateTransform arguments to account for the printer's hard margin values that I originally neglected. This is based on the transform performed by the StandardPrintController.OnStartPage method when then PrintDocument.OriginAtMargins property is true.

Upvotes: 4

Related Questions