Reportlab: Align, vAlign Table to the 'BOTTOM&

2019-08-31 01:40发布

问题:

I have problem to align a Table object to the bottom of a Frame, hAlign 'RIGHT' and 'LEFT' works, but it seem to be stuck in 'TOP', how do I vAlign the Table down to 'MIDDLE' or the 'BOTTOM' of the Frame? Below is a complete and run-able example. Please note it is table within the Frame that should be on the bottom, meaning the table is in the bottom right corner (now, below table is on TOP of the frame).

from reportlab.lib.pagesizes import letter
from reportlab.lib import colors
from reportlab.platypus import Frame, PageTemplate
from reportlab.lib.units import cm
from reportlab.platypus import (Table, TableStyle, BaseDocTemplate)

########################################################################

def create_pdf():
    """
    Create a pdf
    """

    # Create a frame
    CatBox_frame = Frame(
        x1=14.00 * cm,  # From left
        y1=1.5 * cm,  # From bottom
        height=9.60 * cm,
        width=5.90 * cm,
        leftPadding=0 * cm,
        bottomPadding=0 * cm,
        rightPadding=0 * cm,
        topPadding=0 * cm,
        showBoundary=1,
        id='CatBox_frame')

    # Create a table
    CatBox = Table([
        ['', '', '', 'A'],
        ['', '', '', 'B'],
        ['', '', '', 'C'],
        ['AA', 'BB', 'CC', '']], 1.2 * cm, 1.2 * cm, vAlign='BOTTOM')

    # Style the table
    CatBox.setStyle(TableStyle([
        ('SIZE', (0, 0), (-1, -1), 7),
        ('SIZE', (0, 0), (0, 0), 5.5),
        ('TEXTCOLOR', (0, 0), (-1, -1), colors.black),
        ('GRID', (0, 0), (-1, -1), 0.5, colors.black),
        ('VALIGN', (0, 0), (-1, -1), 'BOTTOM'),
    ]))

    # Trying to tell the table to be a bottom align object (when later put in frame)
    CatBox.Align = 'BOTTOM'
    CatBox.vAlign = 'BOTTOM'

    # Building the story
    story = [CatBox] # adding CatBox table (alternative, story.add(CatBox))

    # Establish a document
    doc = BaseDocTemplate("BottomAlignTable.pdf", pagesize=letter)

    # Creating a page template 
    frontpage = PageTemplate(id='FrontPage',
                             frames=[CatBox_frame]
                             )
    # Adding the story to the template and template to the document
    doc.addPageTemplates(frontpage)

    # Building doc
    doc.build(story)


# ----------------------------------------------------------------------
if __name__ == "__main__":
    create_pdf() # Printing the pdf

UPDATE: I found something called TopPadder in flowables.py, but yet no clue howto use it (and would feel like a hack/ a weird application when the Align 'BOTTOM' ought to be the logical completion of right, left, top and middle). (as illustrated on page 4 in this document: https://www.reportlab.com/examples/rml/test/test_008_tables.pdf )

class TopPadder(Flowable): '''wrap a single flowable so that its first bit will be padded to fill out the space so that it appears at the bottom of its frame'''

UPDATE II: Yes, I solved it, the solution was:

from reportlab.platypus.flowables import TopPadder

story = [TopPadder(CatBox)]

回答1:

Maybe should be like this:

doc = SimpleDocTemplate('CatBox.pdf')

CatBox = []
table = Table([
    ['', '', '', 'A'],
    ['', '', '', 'B'],
    ['', '', '', 'C'],
    ['AA', 'BB', 'CC', '']], 1.2 * cm, 1.2 * cm, vAlign='BOTTOM')

table.setStyle(TableStyle([
    ('SIZE', (0, 0), (-1, -1), 7),
    ('SIZE', (0, 0), (0, 0), 5.5),
    ('TEXTCOLOR', (0, 0), (-1, -1), colors.black),
    ('GRID', (0, 0), (-1, -1), 0.5, colors.black),
    ('VALIGN', (0, 0), (-1, -1), 'BOTTOM'),
]))

table.Align = 'BOTTOM'
table.vAlign = 'BOTTOM'

table_frame = Frame(
    x1=7.0 * cm,  # From left
    y1=1.5 * cm,  # From bottom
    height=9.60 * cm,
    width=5.90 * cm,
    leftPadding=0 * cm,
    bottomPadding=0 * cm,
    rightPadding=0 * cm,
    topPadding=0 * cm,
    showBoundary=1,
    id='CatBox_frame'
)

CatBox.append(table)

template = PageTemplate(id='all', frames=table_frame)
doc.addPageTemplates([template])

doc.build(CatBox)

An alternative based on http://www.blog.pythonlibrary.org/2014/03/10/reportlab-how-to-create-custom-flowables/ could be:

doc = SimpleDocTemplate('CatBox.pdf')
doc.build([CatBox(x=5, y=25)])

class CatBox(Flowable):

    def __init__(self, x=0, y=0):
        Flowable.__init__(self)
        self.x = x
        self.y = y

    #----------------------------------------------------------------------
    def coord(self, x, y, unit=1):
        """
        http://stackoverflow.com/questions/4726011/wrap-text-in-a-table-reportlab
        Helper class to help position flowables in Canvas objects
        """
        x, y = x * unit, self.height - y * unit
        return x, y

    #----------------------------------------------------------------------
    def draw(self):
        """
        Draw the shape, text, etc
        """

        table = Table([
            ['', '', '', 'A'],
            ['', '', '', 'B'],
            ['', '', '', 'C'],
            ['AA', 'BB', 'CC', '']], 1.2 * cm, 1.2 * cm, vAlign='BOTTOM')

        table.setStyle(TableStyle([
            ('SIZE', (0, 0), (-1, -1), 7),
            ('SIZE', (0, 0), (0, 0), 5.5),
            ('TEXTCOLOR', (0, 0), (-1, -1), colors.black),
            ('GRID', (0, 0), (-1, -1), 0.5, colors.black),
            ('VALIGN', (0, 0), (-1, -1), 'BOTTOM'),
        ]))

        table.Align = 'BOTTOM'
        table.vAlign = 'BOTTOM'

        table.wrapOn(self.canv, self.width, self.height)
        table.drawOn(self.canv, *self.coord(self.x, self.y, cm))