代码之家  ›  专栏  ›  技术社区  ›  Ralf

reportlab SimpleDocTemplate-设置具有可变行数的表的固定高度

  •  0
  • Ralf  · 技术社区  · 7 年前

    我试图在中生成PDF发票 Python 使用 reportlab

    发票将只有一页,不会有比这一页上的空间更多的详细信息;我的代码在生成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 在表之后;这个间隔的高度必须根据表中的行数来计算(更多的行意味着间隔将更小;更少的行产生更大的间隔)。但如果其中一行环绕并占用的空间超过一行,则此操作将失败。

    我的问题是: 简单模板 ?

    This similar question 简单模板

    0 回复  |  直到 7 年前
        1
  •  1
  •   Jaco    7 年前

    使用“TopPadder”尝试这个可行的示例(结果是总数被推到框架的底部,我假设您可以在下面添加一个缓冲垫,以控制从底部开始的高度):

    ########################################################################
    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
    
        2
  •  0
  •   Ralf    7 年前

    ...
    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))