PolyGeo
PolyGeo

Reputation: 1400

Splitting ReportLab table across PDF page (side by side)?

The code below creates a nice test table with 99 rows of data and a header that gets repeated at each page break. The table is quite narrow so I am trying to figure out how to make it split so that it has rows 1-37 on the left hand side of the first page, rows 38-74 on the right hand side of the first page, and rows 75-99 on the left hand side of the second page. I've called this "splitting a table across a page" but there may be a better name for what I am trying to do so I hope I have described it accurately.

from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Frame, Spacer
from reportlab.lib import colors
from reportlab.lib.units import cm
from reportlab.lib.pagesizes import A3, A4, landscape, portrait
from reportlab.lib.styles import ParagraphStyle, getSampleStyleSheet
from reportlab.lib.enums import TA_LEFT, TA_RIGHT, TA_CENTER, TA_JUSTIFY
from reportlab.pdfgen import canvas

pdfReportPages = "C:\\Temp\\test.pdf"
doc = SimpleDocTemplate(pdfReportPages, pagesize=A4)

# container for the "Flowable" objects
elements = []
styles=getSampleStyleSheet()
styleN = styles["Normal"]

# Make heading for each column and start data list
column1Heading = "COL ONE"
column2Heading = "COL TWO"
# Assemble data for each column using simple loop to append it into data list
data = [[column1Heading,column2Heading]]
for i in range(1,100):
    data.append(["Col 1 Row " + str(i),"Col 2 Row " + str(i)])

tableThatSplitsOverPages = Table(data, [2.5 * cm, 2.5 * cm], repeatRows=1)
tableThatSplitsOverPages.hAlign = 'LEFT'
tblStyle = TableStyle([('TEXTCOLOR',(0,0),(-1,-1),colors.black),
                       ('VALIGN',(0,0),(-1,-1),'TOP'),
                       ('LINEBELOW',(0,0),(-1,-1),1,colors.black),
                       ('BOX',(0,0),(-1,-1),1,colors.black),
                       ('BOX',(0,0),(0,-1),1,colors.black)])
tblStyle.add('BACKGROUND',(0,0),(1,0),colors.lightblue)
tblStyle.add('BACKGROUND',(0,1),(-1,-1),colors.white)
tableThatSplitsOverPages.setStyle(tblStyle)
elements.append(tableThatSplitsOverPages)

doc.build(elements)

Upvotes: 2

Views: 6558

Answers (2)

bdoubleu
bdoubleu

Reputation: 6107

If you know the exact number of rows on the page you can use this function to simulate two columns. That way the the table still automatically flows over multiple pages and you don't have to worry about PageTemplates.

def columnize(data, interval):
    ret = []
    for i in range(0, len(data), interval * 2):
        for j in range(min(interval, len(data) - i)):
            ret.append(data[i + j] + (data[i + j + interval] if i + j + interval < len(data) else []))
    return ret

Use in your example:

data = columnize(data, 75)
tableThatSplitsOverPages = Table(data, [2.5 * cm, 2.5 * cm], repeatRows=1)

Upvotes: 3

Gordon Seidoh Worley
Gordon Seidoh Worley

Reputation: 8068

You will need to use PageTemplates to accomplish this by creating a PageTemplate that has multiple Frames that will allow you to specify content areas to draw the document within the page. This unfortunately means abandoning SimpleDocTemplate and instead using BaseDocTemplate and supplying your own PageTemplates (as well as other things if you want them).

Upvotes: 3

Related Questions