A common use of DynaPDF is to write reports. Or you may need to output the content of a Listbox to a PDF. For these cases our DynaPDFTableMBS class helps. It automatically calculates how much space the text in the cell needs and determines the row height. And if the table doesn't fit on one page, it can continue on another page. If you have header rows, they get repeated on each page.
Let us start with an example. First we need to know what Listbox (or DesktopListbox) we like to output. Then we start a new DynaPDF environment using DynaPDFMBS class, which you can be subclasses to catch events like Error or PageBreak.
When we create a new PDF, we can pass nil for an in-memory PDF. In that case call GetBuffer after calling the CloseFile method to grab the finished PDF. Otherwise you can pass a folderitem, so DynaPDF can create the PDF there.
// we want to output this list
Var list As Listbox = listbox1
// start a PDF with a folderitem to write the file
var pdf As New MyDynapdfMBS
var file As FolderItem = SpecialFolder.Desktop.Child("Table.pdf")
Call pdf.CreateNewPDF(file)
Once you started the PDF, you may want to set some metadata like the author or subject for the document. For the coordinate system in the PDF, we prefer top-down coordinates, so we configure this. By default PDF uses bottom-up coordinates, so the Y = 0 is on the bottom. With using SetPageCoords, we can change it to top-down just like Xojo's graphics class.
// add some metadata
Call pdf.SetDocInfo pdf.kdiCreator, "Xojo test application"
Call pdf.SetDocInfo pdf.kdiTitle, "My first table output"
// in Xojo we prefer top-down coordinates instead of bottom-up
Call pdf.SetPageCoords pdf.kpcTopDown
To start a page, you call the Append method. Or if you like to import a page
// we add a new page
Call pdf.Append
Let's create a table with DynaPDFTableMBS class. We pass the expected numbers of rows and the number of columns, so DynaPDF can pre-allocate the memory for the table. You can later add more rows if needed.
We also pass the width of the table. In this case the table width is the page width with an inch of space left and right. In the PDF world 72 points are one inch = 2.54 cm.
// create a table
Var TableWidth As Integer = pdf.GetPageWidth - 72 - 72 // width - left and right
Var table As DynaPDFTableMBS = pdf.CreateTable(list.ListCount, list.ColumnCount, TableWidth, 8.0)
We have a table and like to establish a default font for all rows and columns. We use Helvetica without any style. Then we set all cells to have a bit of padding and spacing. You can also set grid lines and a border, both with color and width.
// we set a default font for all
Call table.SetFont(AllRows, AllColumns, "Helvetica", pdf.kfsRegular, True, pdf.kcpUnicode)
// add some spacing for all rows
Call table.SetCellPadding(AllRows, AllColumns, 2.0, 2.0, 2.0, 2.0)
Call table.SetCellSpacing(AllRows, AllColumns, 0.0, 0.0, 0.0, 2.0)
Since we output a Listbox, we need to translate the column widths. If the ColumnWidths property is set, we parse the text there. There may be columns with stars, percentages or absolute values.
// calculate the column widths
Var columnwidths(-1) As Integer
Var cw(-1) As String = Split(List.ColumnWidths,",")
if cw.Count > 1 then
Redim columnwidths(list.ColumnCount)
Var remainingspace As Integer = TableWidth
Var starcount As Integer
For Each s As String In cw
s = s.Trim
If s = "*" Then
starcount = starcount + 1
ElseIf InStr(s,"*")>0 Then
starcount = starcount + s.ToInteger
End If
Next
For i As Integer = 0 To UBound(Cw)
Var s As String = cw(i).Trim
Var columnwidth As Integer
If InStr(s,"%")>0 Then
columnwidth=s.toDouble*(TableWidth)/100.0
ElseIf s = "*" Then
columnwidth = remainingspace/starcount
ElseIf InStr(s,"*")>0 Then
columnwidth = s.toDouble*remainingspace/starcount
Else
columnwidth = s.ToDouble
End If
columnwidths(i)=columnwidth
remainingspace=remainingspace-columnwidth
Next
end if
Next we add a header row and set the column widths and pass the heading texts.
// now add the column headers
Var rowNum As Integer = table.AddRow
For cx As Integer = 0 To list.ColumnCount-1
if columnwidths.Count > 0 then
Call table.SetColWidth(cx, columnwidths(cx), False)
End If
Call table.SetCellText(rowNum, cx, pdf.ktaLeft, table.kcoCenter, list.Heading(cx))
Next
We set a border width for the header row. Then we set the font to bold for this row only. And we mark the this header row, so DynaPDF repeats them on every page.
// we can have a border
Call table.SetBorderWidth(rowNum, AllColumns, 0.5, 0.5, 0.5, 0.5)
// make the header bold and mark it as header
Call table.SetFont(rowNum, AllColumns, "Helvetica", pdf.kfsBold, True, pdf.kcpUnicode)
Call table.SetFlags(rowNum, AllColumns, table.ktfHeaderRow)
Now we add the rows from the ListBox. When we transfer the cells, we check for the column alignment and pass the right constant to DynaPDF.
// now add the content
For cy As Integer = 0 To list.ListCount - 1
rowNum = table.AddRow
// and fill each cell with alignment
For cx As Integer = 0 To list.ColumnCount - 1
If list.ColumnAlignment(cx) = list.AlignCenter Then
Call table.SetCellText(rowNum, cx, pdf.ktaCenter, table.kcoCenter, list.Cell(cy,cx) )
ElseIf list.ColumnAlignment(cx) = list.AlignRight Then
Call table.SetCellText(rowNum, cx, pdf.ktaRight, table.kcoCenter, list.Cell(cy,cx) )
Else
Call table.SetCellText(rowNum, cx, pdf.ktaLeft, table.kcoCenter, list.Cell(cy,cx) )
End If
Next
Next
Finally we can output the table. We loop until we have no more data. We draw the table with the height we need. The height could be different on the different pages if you need to put some address above the table on the first page or you need to add an image on one of the pages. When you need another page, we call Append. If you like to use an existing page as template, you could of course import a page here instead.
// output the table to PDF
Var TableHeight As Double = pdf.GetPageHeight - 72 - 72
Do
// draw something
Call table.DrawTable( 55.0, 72.0, TableHeight)
If table.HaveMore Then
// we got more to draw, so let's start a new page
Call pdf.EndPage
Call pdf.Append
Else
// we are done
Exit
End If
Loop
Finally we end the last page and close the file. DynaPDF finishes the file and we can use Launch method to open it.
// close the last page and the file
Call pdf.EndPage
Call pdf.CloseFile
file.Launch
Please try. Check out the "Table with Listbox" example file coming with the plugin. If you need a DynaPDF license, you can get the Starter one with OmegaBundle.