简体   繁体   中英

Conditional page break in reportlab

I am creating PDFs tables with Reportlab platypus. I don´t know, when the page is full because of the dynamic content. How can I check out, if I am at the end of the page ?

Is there any method in platypus to check end of page?

I have list of companies and each company has multiple business units with their charges.

   companies = [('company1', 'businessunit1', 500),
                ('company1', 'businessunit2',400),
                ('company2', 'businessunit3',200),
                ('company2', 'businessunit4', 700),
                ('company3', 'businessunit5', 800)
               ]

The above list should generate 3 tables each for one company, but if this list has multiple companies which will generates multiple tables and if any table reaches end of page which will break.

      fields = ['company name', 'business unit name', 'charge']
      for i, comp in enumerate(companies):
          charges = []
          document.append(Paragraph("<b>%s</b>" %comp[i][0], STYLES['COMPANY_NAME']))
          document.append(Spacer(1, 5))
          charges.append(comp[i][0])
          charges.append(comp[i][1])
          charges.append(comp[i][2])
          charges_table = LongTable([fields] + charges, colWidths=(30,150,100))
          charges_table.setStyle(TableStyle([
                          ('BACKGROUND', (0, 0), (-1, 0), colors.gray),
                          ('FONTSIZE', (0, 0), (-1, 0), 6),
                          ('GRID', (0, 0), (-1, -1), 1, colors.gray),
                          ('FONTSIZE', (0, 0), (-1, -1), 7),
                          ('TEXTCOLOR',(0,-1),(-1,-1),'#FF4500'),
                          ])
                          )

          charges_table.hAlign = 'CENTER'
          document.append(charges_table)

You should provide some sample code so we know what you're trying to accomplish. Why do you want to know when the page has ended? To draw new content? To print out some diagnostic information?

Assuming you want to draw something after a page has been rendered, you can use the afterPage() method, which is provided in the BaseDocTemplate class. From ReportLab's documentation:

This is called after page processing, and immediately after the afterDrawPage method of the current page template. A derived class could use this to do things which are dependent on information in the page such as the first and last word on the page of a dictionary.

Basically, it's called by BaseDocTemplate after a page has been drawn. In the source code, it includes self , as it is part of the BaseDocTemplate class, so you can access its canvas!

You can override the class in your own script, and then draw onto the canvas directly.

from reportlab.platypus import BaseDocTemplate
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.units import inch
from reportlab.lib.pagesizes import A4
from reportlab.platypus import Paragraph

class MyDocTemplate(BaseDocTemplate):
    """Override the BaseDocTemplate class to do custom handle_XXX actions"""

    def __init__(self, *args, **kwargs):
        BaseDocTemplate.__init__(self, *args, **kwargs)

    def afterPage(self):
        """Called after each page has been processed"""

        # saveState keeps a snapshot of the canvas state, so you don't
        # mess up any rendering that platypus will do later.
        self.canv.saveState()

        # Reset the origin to (0, 0), remember, we can restore the
        # state of the canvas later, so platypus should be unaffected.
        self.canv._x = 0
        self.canv._y = 0

        style = getSampleStyleSheet()

        p = Paragraph("This is drawn after the page!", style["Normal"])

        # Wraps and draws the paragraph onto the canvas
        # You can change the last 2 parameters (canv, x, y)
        p.wrapOn(self.canv, 2*inch, 2*inch)
        p.drawOn(self.canv, 1*inch, 3*inch)

        # Now we restore the canvas back to the way it was.
        self.canv.restoreState()

Now you can use MyDocTemplate the same way you would use BaseDocTemplate in your main logic:

if __name__ == "__main__":

    doc = MyDocTemplate(
        'filename.pdf',
        pagesize=A4,
        rightMargin=.3*inch,
        leftMargin=.3*inch,
        topMargin=.3*inch, 
        bottomMargin=.3*inch
    )

    elements = [
        # Put your actual elements/flowables here, however you're generating them.
    ]

    doc.addPageTemplates([
        # Add your PageTemplates here if you have any, which you should!
    ])

    # Build your doc with your elements and go grab a beer
    doc.build(elements)

You have to count the lines used yourself. I use a procedure that includes:

lin += inc
if lin > 580:
    doc.append(PageBreak())
    lin = 5

By knowing how many lines a table uses you can know if it will fit in the rest of the page.

I use counting 'points' so I can deal with lines of different height.

Breaking a table over multiple pages requires using your own templates according to How to split ReportLab table across PDF page (side by side)?

Tables should break automatically when they reach the end of the page. But here's another example I found:

automatic split longtable to multiple page, like this:

from reportlab.platypus import LongTable, TableStyle, BaseDocTemplate, Frame, PageTemplate
from reportlab.lib.pagesizes import letter
from reportlab.lib import colors


def test():
    doc = BaseDocTemplate(
        "test.pdf",
        pagesize=letter,
        rightMargin=72,
        leftMargin=72,
        topMargin=72,
        bottomMargin=18,
        showBoundary=True)

    elements = []
    datas = []
    for i, x in enumerate(range(1, 50)):
        datas.append([i, x])
    t = LongTable(datas)

    tableStyle = [
        ('INNERGRID', (0, 0), (-1, -1), 0.25, colors.black),
        ('BOX', (0, 0), (-1, -1), 0.25, colors.black),
    ]
    t.setStyle(TableStyle(tableStyle))
    elements.append(t)

    frame = Frame(
        doc.leftMargin, doc.bottomMargin, doc.width, doc.height, id='normal')
    doc.addPageTemplates([PageTemplate(id='longtable', frames=frame)])
    doc.build(elements)


if __name__ == '__main__':
    test()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM