Python Reportlab中的动态帧大小

Python Reportlab中的动态帧大小,reportlab,python,pdf,pdf-generation,Reportlab,Python,Pdf,Pdf Generation,我试图用Python生成一个发货列表。 我试图使用鸭嘴兽框架将所有部分(如发送者地址、接收者地址、表)放在适当的位置 我遇到的第一个问题是,我需要大量的帧来正确定位所有东西,有没有更好的方法使用鸭嘴兽? 因为我希望发件人地址和我的地址位于同一高度,如果我只是将它们添加到我的story=[]中,它们就会一个接一个地对齐 下一个问题是,我正在绘制的表的大小是动态的,当我到达帧的末尾时(我希望表的空间),它只会在下一帧中执行分帧,并且是连续的。那么,我如何才能使框架(我的表格的空间)动态化呢?您的用例

我试图用Python生成一个发货列表。 我试图使用鸭嘴兽
框架
将所有部分(如发送者地址、接收者地址、表)放在适当的位置

我遇到的第一个问题是,我需要大量的
来正确定位所有东西,有没有更好的方法使用鸭嘴兽? 因为我希望发件人地址和我的地址位于同一高度,如果我只是将它们添加到我的
story=[]
中,它们就会一个接一个地对齐


下一个问题是,我正在绘制的表的大小是动态的,当我到达
帧的末尾时(我希望表的空间),它只会在下一帧中执行
分帧
,并且是连续的。那么,我如何才能使
框架
(我的表格的空间)动态化呢?

您的用例非常常见,因此Reportlab有一个系统可以帮助您

如果您阅读了关于鸭嘴兽的用户指南,它将向您介绍4个主要概念:

DocTemplates
文档的最外层容器

PageTemplates
各种页面布局规范

框架
页面中可包含流动文本或图形的区域规范

Flowables
使用
PageTemplates
您可以以合理的方式将页面上的“静态”内容与动态内容相结合,例如徽标、地址等

您已经发现了
Flowables
Frames
,但可能还没有开始使用fancy
PageTemplates
DocTemplates
。这是有意义的,因为对于大多数简单的文档来说,它不是必需的。遗憾的是,发货清单不是一个简单的文件,它包含地址、标识和重要信息,必须在每一页上。这就是
PageTemplates
的用武之地

那么如何使用这些模板呢?概念很简单,每个页面都有特定的结构,不同页面之间可能会有所不同,例如,在第一页上,您希望放置地址,然后启动表,而在第二页上,您只需要表。这应该是这样的:

第1页:

第2页:

示例如下所示:

(如果Reportlab有一个SO文档,这将非常适合SO文档)

from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.units import cm
from reportlab.lib import colors
from reportlab.platypus import BaseDocTemplate, Frame, PageTemplate, NextPageTemplate, Paragraph, PageBreak, Table, \
    TableStyle


class ShippingListReport(BaseDocTemplate):
    def __init__(self, filename, their_adress, objects, **kwargs):
        super().__init__(filename, page_size=A4, _pageBreakQuick=0, **kwargs)
        self.their_adress = their_adress
        self.objects = objects

        self.page_width = (self.width + self.leftMargin * 2)
        self.page_height = (self.height + self.bottomMargin * 2)


        styles = getSampleStyleSheet()

        # Setting up the frames, frames are use for dynamic content not fixed page elements
        first_page_table_frame = Frame(self.leftMargin, self.bottomMargin, self.width, self.height - 6 * cm, id='small_table')
        later_pages_table_frame = Frame(self.leftMargin, self.bottomMargin, self.width, self.height, id='large_table')

        # Creating the page templates
        first_page = PageTemplate(id='FirstPage', frames=[first_page_table_frame], onPage=self.on_first_page)
        later_pages = PageTemplate(id='LaterPages', frames=[later_pages_table_frame], onPage=self.add_default_info)
        self.addPageTemplates([first_page, later_pages])

        # Tell Reportlab to use the other template on the later pages,
        # by the default the first template that was added is used for the first page.
        story = [NextPageTemplate(['*', 'LaterPages'])]

        table_grid = [["Product", "Quantity"]]
        # Add the objects
        for shipped_object in self.objects:
            table_grid.append([shipped_object, "42"])

        story.append(Table(table_grid, repeatRows=1, colWidths=[0.5 * self.width, 0.5 * self.width],
                           style=TableStyle([('GRID',(0,1),(-1,-1),0.25,colors.gray),
                                             ('BOX', (0,0), (-1,-1), 1.0, colors.black),
                                             ('BOX', (0,0), (1,0), 1.0, colors.black),
                                             ])))

        self.build(story)

    def on_first_page(self, canvas, doc):
        canvas.saveState()
        # Add the logo and other default stuff
        self.add_default_info(canvas, doc)

        canvas.drawString(doc.leftMargin, doc.height, "My address")
        canvas.drawString(0.5 * doc.page_width, doc.height, self.their_adress)

        canvas.restoreState()

    def add_default_info(self, canvas, doc):
        canvas.saveState()
        canvas.drawCentredString(0.5 * (doc.page_width), doc.page_height - 2.5 * cm, "Company Name")

        canvas.restoreState()


if __name__ == '__main__':
    ShippingListReport('example.pdf', "Their address", ["Product", "Product"] * 50)