reportlab SimpleDocTemplate-使用可变的行数设置表格的固定高度

时间:2019-02-22 10:22:10

标签: python python-3.x reportlab

我尝试使用Pythonreportlab中生成PDF发票。

发票将仅一页,并且任何细节都不会超过一页上的空白;我的代码在生成PDF之前检查了详细信息的最大数量。

现在,我正在使用SimpleDocTemplate将所有内容添加到页面中,并使用Table构建详细信息。 这是简化的代码示例:

from reportlab.lib.units import mm
from reportlab.platypus import Paragraph, Spacer, Table, TableStyle
from reportlab.platypus import SimpleDocTemplate

# add invoice header
flowable_list = [
    Spacer(1, 5*mm),
    Paragraph('Date: ...', pg_style_1),
    Spacer(1, 5*mm),
]

# add invoice details
detail_list = [
    ('Item 1', 8, 45),
    ('Item 2', 1, 14),
]
row_list = [
    [
        Paragraph(desc, pg_style_1),
        quantity,
        amount,
    ]
    for desc, quantity, amount in detail_list]
story.append(
    Table(
        data=row_list,
        colWidths=[100*mm, 40*mm, 40*mm],
        style=TableStyle([
            ('VALIGN', (0, 0), (-1, -1), 'TOP'),
            ... some other options ...
        ])))

# add invoice footer; this should be at a specific position on the page
flowable_list.append(Spacer(1, 5*mm))
flowable_list.append(Paragraph('Total: 0', pg_style_1))

# build PDF
buffer = io.BytesIO()
doc = SimpleDocTemplate(buffer)
doc.build(flowable_list)

我的问题:每次底部的总金额都必须位于特定的位置(底部的x*mm之类),但是详细信息的数量可变导致明细表的高度不固定。

我当前的解决方案:在表格后添加Spacer;必须根据表格中的行数来计算此分隔符的高度(更多行表示分隔符将变小;较少的行将产生较大的分隔符)。但是,如果其中一行环绕并且比单个行占用更多空间,则此操作将失败。

我的问题:有没有一种方法可以为明细表设置固定的高度,无论将有多少行,但仍继续使用SimpleDocTemplate

This similar question显示了一种将所有内容手动绘制到画布上的解决方案,但我希望有一种方法可以继续使用SimpleDocTemplate

2 个答案:

答案 0 :(得分:1)

使用“ TopPadder”尝试这个可行的示例,(结果是Total被推到了框架的底部,我假设您可以在其下方添加一个缓冲垫,以控制底部的高度): / p>

########################################################################
from reportlab.lib.units import mm
from reportlab.platypus import Paragraph, Spacer, Table, TableStyle
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.platypus import SimpleDocTemplate
from reportlab.platypus.flowables import TopPadder
import io

def create_pdf():

    styles=getSampleStyleSheet()

    # add invoice header
    flowable_list = [
        Spacer(1, 5 * mm),
        Paragraph(f'Date: ...', styles['Normal']),
        Spacer(1, 5 * mm),
    ]

    # add invoice details
    detail_list = [
        ('Item 1', 8, 45),
        ('Item 2', 1, 14),
    ]
    row_list = [
        [
            Paragraph(f'desc', styles['Normal']),
            # quantity,
            # amount,
        ]
        for desc, quantity, amount in detail_list]

    story = []
    story.append(
        Table(
            data=row_list,
            colWidths=[100 * mm, 40 * mm, 40 * mm],
            style=TableStyle([
                ('VALIGN', (0, 0), (-1, -1), 'TOP'),
                # ... some other options...
            ])))

    # add invoice footer; this should be at a specific position on the page
    flowable_list.append(Spacer(1, 5 * mm))
    flowable_list.append(TopPadder(Paragraph(f'Total: 0', styles['Normal'])))

    # build PDF
    buffer = io.BytesIO()
    doc = SimpleDocTemplate("test2.pdf")
    doc.build(flowable_list)

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

答案 1 :(得分:0)

我还没有找到更好的方法,因此我将添加当前的解决方案;也许它将帮助将来的读者遇到类似的问题。

...
story.append(
    Table(
        data=row_list,
        colWidths=[100*mm, 40*mm, 40*mm],
        style=TableStyle([
            ('VALIGN', (0, 0), (-1, -1), 'TOP'),
            ... some other options ...
        ])))

# calculate real height of details table, so we can add a 'Spacer' for the missing
# part to have the invoice totals at the correct height at the bottom of the page
_, real_height = story[-1].wrap(doc_width, doc_height)
height_reserved_for_details = 100*mm
remaining_height = max(0, height_reserved_for_details - real_height)
story.append(Spacer(1, remaining_height))

flowable_list.append(Paragraph('Total: 0', pg_style_1))