Home > Net >  Vertically align reportlab table within frame, or stretch table to fill the frame
Vertically align reportlab table within frame, or stretch table to fill the frame

Time:07-27

How can I achieve the horizontal align result with a Reportlab table vertically? As seen below, the table correctly aligns horizontally by filling the available space within the frame and then centering the cells within that space. I want the table to fill the frame vertically the same way it does horizontally well and then center the cells accordingly. Or, a possible alternative could be centering the table itself within the frame. Table is vertically aligned at the top not the middle

Current code:

from reportlab.lib.pagesizes import letter
from reportlab.lib.units import inch
from reportlab.lib import colors

from reportlab.platypus import (
    Frame, Flowable, PageTemplate, 
    BaseDocTemplate, TableStyle, Table,
    NextPageTemplate, 
)


class Square(Flowable):
    def __init__(self):
        super().__init__()
        self.width = inch
        self.height = inch
    

    def __repr__(self):
        return "Square"


    def draw(self):
        """
        draw the line
        """
        self.canv.setFillColorRGB(255, 0, 0) 
        self.canv.rect(0, 0, self.width, self.height, fill=True)
        
        

medium_margin = inch * .5 
small_margin = inch * .25

segment_table_width = letter[0] - medium_margin * 2
segment_table_height = inch * 3
segment_table_frame = Frame(
    medium_margin, 
    medium_margin, 
    segment_table_width,
    segment_table_height,
    showBoundary=True,
    leftPadding=0,
    bottomPadding=0,
    rightPadding = 0,
    topPadding=0
)


segment_cover = PageTemplate(
    "segment-cover", 
    frames=[
        segment_table_frame
    ],
    pagesize=letter
)


template = BaseDocTemplate(
    filename = "example.pdf",
    pageTemplates=[segment_cover],
    pageSize = letter
)


story = []

table_data = [[Square() for j in range(5)] for i in range(20)]
table_style = TableStyle([
    ('ALIGN', (0,0), (-1,-1), 'CENTER'), 
    ("BACKGROUND", (0,0), (-1,-1), colors.green)
])

table = Table(table_data, style=table_style)

parts = table.split(segment_table_width, segment_table_height)

table1, table2 = parts


story.append(NextPageTemplate("segment-cover"))
story.append(table1)

template.build(story)

CodePudding user response:

Ended up creating a custom flowable for vertically centering a flowable within a frame. Only works if there is only one flowable in the frame.

def get_frame_size(frame : Frame):
    return (frame._width, frame._height)
    

class CenterFlowable(Flowable):
    """
    center flowable vertically within a frame 
    
    frame : the frame it is being centered in 
    flowable : the floawable that is being centered
    """
    def __init__(self, frame : Frame, flowable : Flowable):
        super().__init__()
        self.frame = frame 
        self.flowable = flowable  
        
        self.width, self.height = get_frame_size(frame)
        
        
    def draw(self):
        table_style = TableStyle([
            ("ALIGN", (0,0), (-1,-1), "CENTER"), 
            ("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
            ("BOTTOMPADDING", (0, 0), (-1, -1), 0),
            ("TOPPADDING", (0, 0), (-1, -1), 0),
        ])
        table = Table(
            [[self.flowable]], 
            colWidths=self.width, 
            rowHeights=self.height, 
            style=table_style
        )
        table.wrapOn(self.canv, 0, 0)
        table.drawOn(self.canv, 0, 0)

Can be used by wrapping it around the flowable you want to center:

story = [] #document story
story.append(CenterFlowable(frame, flowable_i_want_to_center_in_frame))
  • Related