VB.NET : PrintDocument, Printing in Tabular Format

Hi guys, this article contains a sample on how to make a table using PrintDocument for printing.
Something like this:


It will be easier to understand if you read previous articles.
Introducing PrintDocument Component
Setting Font for PrintDocument Printing
Setting Vertical (Y) Position Automatically on PrintDocument
Setting Alignment

We're getting to an intermediate level. Let's modify PrintCellText Function into the following code:

Public Function PrintCellText(ByVal strValue As StringByVal x As Integer, _
                              ByVal y As IntegerByVal w As Integer, _
                              ByVal e As System.Drawing.Printing.PrintPageEventArgs, _
                              Font As Font, Format As StringFormat, _
                              Optional Border As Boolean = False, _
                              Optional Fill As Brush = Nothing, _
                              Optional h As Integer = 0) As Integer

    Dim cellRect As RectangleF = New RectangleF()
    cellRect.Location = New Point(x, y)

    If h > 0 Then
        cellRect.Size = New Size(w, h)
    Else
        cellRect.Size = New Size(w, 10 +
                             (CInt(e.Graphics.MeasureString(strValue, Font, w - 10,
                              StringFormat.GenericTypographic).Height)))
    End If

    If IsNothing(Fill) = False Then
        e.Graphics.FillRectangle(Fill, Rectangle.Round(cellRect))
    End If

    e.Graphics.DrawString(strValue, Font, Brushes.Black, cellRect, Format)

    If Border = True Then
        e.Graphics.DrawRectangle(Pens.Black, Rectangle.Round(cellRect))
    Else
        e.Graphics.DrawRectangle(Pens.Transparent, Rectangle.Round(cellRect))
    End If

    Return y + cellRect.Size.Height
End Function

See the highlighted text for detail of changes. I also add 3 optional parameters. Border, fill (for fill color), and h for the height that manually set.
Next, we're going to tidy up the code into a class file. We're still using our previous project. Add a class by selecting menu Project -> Add Class...


Name it with PrintingFormat, then click Add.


This code is written in the class, you may copy it. But hopefully, you try to understand each code in it.



You can also download PrintingFormat Class here.

In this class, I only put 3 type of font to be used.

  • FntTitle untuk judul
  • FntTableHeader untuk header tabel
  • FntTableCell untuk isi cell

You can add your own font type if needed. Then for UI still using this following:


For example, printing data that contain in DataTable. In this case, I'll manually add ItemRow into DataTable. I use DataTable so you can adjust into your own project using any database. I assume that you've already familiar with database programming. Especially fill data into DataTable.

Dim dt As DataTable

Sub Data_Load()
    dt = New DataTable
    With dt.Columns
        .Add("code", Type.GetType("System.String"))
        .Add("name"Type.GetType("System.String"))
        .Add("address"Type.GetType("System.String"))
    End With

    Dim ItemRow As DataRow

    ItemRow = dt.NewRow()
    ItemRow("code") = "A001"
    ItemRow("name") = "Dwi Nuraeni"
    ItemRow("address") = "Bandung"
    dt.Rows.Add(ItemRow)

    ItemRow = dt.NewRow()
    ItemRow("code") = "A002"
    ItemRow("name") = "Kania Desiani"
    ItemRow("address") = "Jakarta"
    dt.Rows.Add(ItemRow)

    ItemRow = dt.NewRow()
    ItemRow("code") = "A002"
    ItemRow("name") = "Naufal Hartanto"
    ItemRow("address") = "Medan"
    dt.Rows.Add(ItemRow)

End Sub

Call sub procedure in form_load event.

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

    Data_Load()

End Sub

We'll also declare some variable that used for this printing process.

'declaring class printing
 Dim pf As PrintingFormat = New PrintingFormat

'declaring veriable for default setting 
 Dim PS As System.Drawing.Printing.PageSettings
 Dim PWArea As Integer
 Dim PHArea As Integer
 Dim xZero As Integer
 Dim yZero As Integer
 Dim iPage As Integer
 Dim As Integer 'variable for saving row number

The values of those variables will be set on print_begin event.

Private Sub PrintDocument1_BeginPrint(sender As Object, e As PrintEventArgs) _
    Handles PrintDocument1.BeginPrint
    PS = PrintDocument1.DefaultPageSettings 'get default setting 
    PWArea = PS.PaperSize.Width - (PS.Margins.Left + PS.Margins.Right)
    PHArea = PS.PaperSize.Height - (PS.Margins.Left + PS.Margins.Right)
    xZero = PS.Margins.Left
    yZero = PS.Margins.Top
    iPage = 0 'indicate page number
    r = 0 
End Sub

Last in PrintDocument1_PrintPage event. I put comment in code for its descriptions. (green colored)

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

    'get starting point of y from top margin 
    Dim CurY As Integer = yZero

    'print title only on the first page.
    If iPage = 0 Then
        CurY = pf.PrintCellText("Member Data", CurY, xZero, PWArea, e, pf.FntTitle, pf.MidCenter)
    End If

    'give space between title and table
    CurY = CurY + 10

    'code to handle if more than one page
    If iPage > 0 Then CurY = yZero

    'for saving header text in array
    Dim ColHeader() As String = {"Member Code", "Member Name", "Address"}

    'for saving columns width in array
    'get width with proportional of printing area width
    Dim ColWidth() As Integer = {CInt(PWArea * 0.3), CInt(PWArea * 0.3), CInt(PWArea * 0.4)}

    'starting position of x for each columns
    Dim ColX(ColWidth.Length - 1) As Integer

    'width value that already used in 1 loop
    'for counting starting point on each columns
    Dim totColWidth As Integer = xZero

    'variable to save height of character that printed 
    Dim iResult As Integer

    For i As Integer = 0 To ColWidth.Length - 1
        'ounting starting point on each columns
        ColX(i) = totColWidth : totColWidth = totColWidth + ColWidth(i)
        'print table header
        iResult = pf.PrintCellText(ColHeader(i), ColX(i), CurY, ColWidth(i), e, _
                  pf.FntTableHeader, pf.MidCenter, True)
    Next

    'get y position from the height of last text printed 
    CurY = iResult
    
    Do While r <= dt.Rows.Count - 1
        'print text value each cell
        iResult = pf.PrintCellText(dt.Rows(r)("code"), ColX(0), CurY, ColWidth(0), e, _
                  pf.FntTableCell, pf.MidLeft, True)
        iResult = pf.PrintCellText(dt.Rows(r)("name"), ColX(1), CurY, ColWidth(1), e, _
                  pf.FntTableCell, pf.MidLeft, True)
        iResult = pf.PrintCellText(dt.Rows(r)("address"), ColX(2), CurY, ColWidth(2), e, _
                  pf.FntTableCell, pf.MidLeft, True)

        'get y position from the height of last text printed 
        CurY = iResult

        'create and go to the next page if already reached 90% height of printing area.
        If CurY >= 0.9 * PHArea Then
            e.HasMorePages = True
            iPage += 1
            r += 1
            Return
        End If

        r += 1
    Loop

    If r = dt.Rows.Count Then e.HasMorePages = False

End Sub

Don't forget to add "Imports System.Drawing.Printing", and this below is the complete code:



Try to run and print.


Result:


I give you step by step tutorial so it's clearer to understand each code in it. For this step, I only show you how to display single-line text in each cell.

To make it works with multiline text in cell, read also this article:
PrintDocument, Creating/Printing Table with Multiline Cell



Post a Comment

0 Comments