我尝试在Python中使用reportlab生成送货清单。
我试图通过使用Platypus Frames
来放置所有部分(如发件人地址,收件人地址,表格)。
我遇到的第一个问题是我需要很多Frames
以正确的方式定位所有内容,使用Platypus有更好的方法吗?
因为我希望发件人地址和我的地址处于同一高度,如果我只是将它们添加到我的story = []
,那么它们就会一个接一个地对齐。
下一个问题是我正在绘制的表格是动态的,当我到达Frame
的末尾(我希望表格去的空间)时,它就是一个FrameBreak
并在下一帧中连续。那么如何才能使Frame
(我桌子的空间)变得动态?
答案 0 :(得分:5)
您的用例非常常见,因此Reportlab有一个系统可以帮助您。
如果您阅读有关platypus
的用户指南,它将向您介绍4个主要概念:
DocTemplates
文档的最外层容器;页面中可包含流动文本或图形的区域的
PageTemplates
各种页面布局的规范;
Frames
规范。
Flowables
使用PageTemplates
,你可以结合"静态"以合理的方式在页面上使用动态内容,例如徽标,地址等。
您已经发现了Flowables
和Frames
,但您可能尚未开始使用PageTemplates
或DocTemplates
。这是有道理的,因为大多数简单文档都不需要它。令人遗憾的是,发货清单不是一个简单的文件,它包含必须在每个页面上的地址,徽标和重要信息。这是PageTemplates
进来的地方。
那么你如何使用这些模板?概念很简单,每个页面都有一定的结构可能会在页面之间有所不同,例如在第一页上要放置地址,然后在第二页上启动表格,只需要表格。这将是这样的:
示例如下所示:
(如果有一个Reportlab,这对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)