Search code examples
pythonpdfreportlab

How to add a table with dynamic height inside a box in a PDF template file using ReportLab


I want to draw a table inside a box in a PDF template file. Because the box has fixed height, if number of rows of table exceed specific number (for example 4), the table overflow from the box. Is there any way to dynamically specify the height of the table when drawing it with reportlab package?

def add_table(self, data: list[list[str]]):
        
        t = Table(data)
        
        t.setStyle(TableStyle([
            ("FACE", (0, 0), (-1, -1), "Times-Roman"),
            ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
            ("VALIGN", (0, 0), (-1, -1), "BOTTOM"),
            ('FONTSIZE', (0,0), (-1,-1), 4),
            ('INNERGRID',(0,0),(-1,-1), 1, colors.lightgrey),
            ('OUTLINE', (0, 0), (-1, -1), 1, colors.lightgrey),
            ("LEFTPADDING", (0, 0), (-1, -1), 0),
            ("RIGHTPADDING", (0, 0), (-1, -1), 5),
            ("BOTTOMPADDING", (0, 0), (-1, -1), 0),
            ("TOPPADDING", (0, 0), (-1, -1), 0),
            ])
        )
    
        t.wrap(0, 0)
        t.drawOn(self.c, 72, 200)
        self.c.save()

Solution

  • I used this code to solve my problem.

    COL_WIDTHS = [40, 50, 30, 40, 45, 40, 45, 40, 40, 40, 40, 45, 45, 40, 40, 40, 40]
    
    TABLE_STYLE = [
            ('GRID', (0, 0), (-1, -1), 0.5, colors.lightgrey),
            ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
            ("HALIGN", (0, 0), (-1, -1), "MIDDLE"),
            ("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
            ('LEFTPADDING', (0, 0), (-1, -1), 0.5),
            ('RIGHTPADDING', (0, 0), (-1, -1), 0),
            ('TOPPADDING', (0, 0), (-1, -1), 0),
            ('BOTTOMPADDING', (0, 0), (-1, -1), 0),
            ('FONTNAME', (0, 0), (-1, 0), 'Times-Roman-Bold'),
            ('LEADING', (0, 0), (-1, -1), 8.2),
        ]
            
    def get_styled_table(self, data: list[list[str]]) -> Table:
                    
        # My table has 17 columns and variable number of rows
        t = Table(data, colWidths=COL_WIDTHS, rowHeights=[20] * len(data))
                    
        t.setStyle(TableStyle(TABLE_STYLE))
            
        row_heights = 20
        while True:
            # Break loop if height of table is smaller than box size (e.g. 160)
            if t.wrapOn(self.c, 730, 160)[1] < 160:
               break
            
            # Decrease rows height if height of table is bigger than box size
            row_heights -= 0.5
            
            # Define table with new row heights 
            t = Table(data, colWidths=COL_WIDTHS, rowHeights=[row_heights] * len(data))
            
            # Set font size to accommodate cells content inside them
            t.setStyle(TableStyle(TABLE_STYLE + [('FONTSIZE', (0,0), (-1,-1), 0.5 * row_heights)]))
                
        return t
            
    def add_table(self, data: list[list[str]]):
            
            t = self.get_styled_table(data)
            
            t.wrapOn(self.c, 730, 160)
            t.drawOn(self.c, 43, 408)