简体   繁体   中英

Reportlab Table split

I am new to ReportLab, page templates. I have to create a report where I have 2 page templates- first page uses header page template and all other pages have common template. Report has to split a table onto multiple pages. On first page table has to be displayed on a less wider frame and then remaining table on wider frames on rest of the pages.

How can I change column widths and table style when table splits among different pages?

EDIT: Here I am putting some code which successfully splits but keeps the table at same width across all pages

# ReportLab PDF Generation Library
from reportlab.pdfgen        import canvas
from reportlab.lib.units     import inch, cm
from reportlab.lib.pagesizes import letter, landscape
from reportlab.lib           import colors

from reportlab.lib.styles import getSampleStyleSheet
from reportlab.platypus import BaseDocTemplate, Frame, Paragraph, NextPageTemplate, PageBreak, PageTemplate, Spacer
from reportlab.platypus.tables import Table, TableStyle

# Constants
Font_Leading = 10
Word_Spacing = 0.0
Char_Spacing = 0.08

#global table
data= [['DATE', 'NAME', 'ITEM', 'AMOUNT', 'BALANCE'],
    ['01/12/15', 'William', 'ITEM1 RELATED STUFF', '365.00', '43.30']
    # CONSIDER MANY MORE ITEMS HERE
    # NUMBER FO ITMES VARYING IN WAY TO CAUSE 1 OR MORE PAGES
    # 3RD COLUMN WILL HAVE DESCRIPTIVE ITEM
    # WHICH WILL REPLACE WITH PARAGARPHS LATER ON
  ]
t=Table(data,repeatRows=1,
  colWidths=[.7*inch, 1*inch, 2.4*inch, .8*inch, .8*inch])
 #The top left cell is (0, 0) the bottom right is (-1, -1).
tStyle = TableStyle([
    # All Cells
    ('FONTSIZE', (0,0), (-1,-1), 8),
    ('TOPPADDING', (0,0), (-1,-1), 0),
    ('BOTTOMPADDING', (0,0), (-1,-1), 0),
    ('VALIGN', (0,0), (-1,-1), 'TOP'),
    ('LEADING', (0,0), (-1,-1), 10),
    # Top row
    ('BACKGROUND', (0,0), (-1,0), colors.maroon),
    ('TEXTCOLOR', (0,0), (-1,0), colors.white),
    ('ALIGN', (0,0), (-1,0), 'CENTRE'),
    # 3RD and 4th column,
    ('ALIGN', (3,0), (4,-1), 'RIGHT'),
    # Line commands
    # All
    ('BOX',(0,0),(-1,-1),.5,colors.black),
    # top row
    ('GRID',(0,0),(-1,0),.5,colors.black),
    # all columns
    ('LINEBEFORE',(0,0),(-1,-1),.5,colors.black),
    # last column
    ('LINEAFTER',(-1,0),(-1,-1),.5,colors.black),
    # last row
    ('LINEBELOW',(0,-1),(-1,-1),.5,colors.black)])
t.setStyle(tStyle)

def othPg(c, doc):
  t.colWidths = [.2*inch, .2*inch,4*inch, .2*inch, .2*inch]
  tStyle.add('BACKGROUND',(0,0),(-1,-1),colors.lightblue)
  x=1

def pgHdr(c, doc):
  width,height = letter
  c.saveState()
  c.translate(.3 * inch, 0 * inch)

# STUFF RELATED TO 2 INCH STTIC HEADER FOR FIRST PAGE
  c.restoreState()


def main():
  pdf_file = 'stmt.pdf'
  Elements = []
  doc = BaseDocTemplate(pdf_file,
                        pagesize=letter,
                        leftMargin=.3*inch,
                        rightMargin= .1 * inch,
                        topMargin= .1 * inch,
                        bottomMargin=.3 * inch,
                        showBoundary=1)
  #normal frame as for SimpleFlowDocument
  frameT = Frame(doc.leftMargin + 2*inch, doc.bottomMargin, doc.width - 2.01*inch, doc.height - 4.1*inch, id='normal', showBoundary=0)
  frameB = Frame(doc.leftMargin+2, doc.bottomMargin, 7.5*inch, 10*inch, id='small', showBoundary=1)



  doc.addPageTemplates([PageTemplate(id='First',frames=frameT,onPage=pgHdr),
                        PageTemplate(id='Later',frames=frameB,onPage=othPg)
                      ])
  Elements.append(NextPageTemplate('Later'))
  Elements.append(t)
  doc.build(Elements)

if __name__ == "__main__":
    sys.exit(main())

With the normal Table it seems that is not possible to do so automatically (based on the source code ). It is made to retain the column width when split, which makes sense as changing the layout of a table after a pagebreak would make it rather confusing for the end-user.

You could make your own version of a Table that does change the column size but this would involve overwriting the rather complex split function of the Table .

Thus in your case the easiest and probably most viable solution would be to make the frames in both templates the same width. Then you don't have to change the column width at all.

Edit: On request of OP I looked into options to indeed adept the style and column width for the laterpages. Based on this I created the following class based on Reportlabs Table :

class LaterPagesTable(Table):
    def __init__(self, data, laterColWidths=None, laterStyle=None, **kwargs):
        Table.__init__(self, data, **kwargs)

        self._later_column_widths = laterColWidths
        self._later_style = laterStyle


    def split(self, availWidth, availHeight):
        self._calc(availWidth, availHeight)
        if self.splitByRow:
            if not rl_config.allowTableBoundsErrors and self._width>availWidth: return []
            tables = self._splitRows(availHeight)

            if len(tables):
                self.onLaterPages(tables[1])
            return tables
        else:
            raise NotImplementedError


    def onLaterPages(self, T):
        if self._later_column_widths:
            T._argW = self._later_column_widths

        if self._later_style:
            T.setStyle(self._later_style)

This class allows the user to specify the style and columnwidth for the later pages using the keyword arguments laterColWidths and laterStyle of which the syntax is exactly the same as for the normal colWidths and style but will only be used on the parts of the table that placed outside the original page.

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