« Register custom funct… | Home | Copy and paste XML in… »

From Listbox to PDF

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.

28 08 25 - 09:33