Die*_* Gc 2 python datatable pdf-generation reportlab
我正在尝试在使用 ReportLab 生成的 PDF 文件中构建一个日程规划器。根据一天中的不同时间,时间表将具有不同的行:从上午 8:00 开始、上午 8:15、上午 8:30 等。
\n我做了一个循环,其中将自动计算时间并填写时间表。但是,由于我的表格太长,它不能完全适合页面。(虽然行程应该在晚上7:30结束,但在下午2:00就被剪掉了)
\n期望的结果是当表中有大约 20 个活动时有一个分页符。在下一页上,标题应该与第一页和下面的表格完全相同。每次有必要时都应重复该过程,直到表结束。
\n\nPython代码如下:
\nfrom reportlab.pdfgen.canvas import Canvas\nfrom datetime import datetime, timedelta\nfrom reportlab.platypus import Table, TableStyle\nfrom reportlab.lib import colors\nfrom reportlab.lib.pagesizes import letter, landscape\n\n\nclass Vendedor:\n """\n Informaci\xc3\xb3n del Vendedor: Nombre, sucursal, meta de venta\n """\n def __init__(self, nombre_vendedor, sucursal, dia_reporte):\n self.nombre_vendedor = nombre_vendedor\n self.sucursal = sucursal\n self.dia_reporte = dia_reporte\n\n\nclass Actividades:\n """\n Informaci\xc3\xb3n de las Actividades realizadas: Hora de actividad y duraci\xc3\xb3n, cliente atendido,\n tipo de actividad, resultado, monto venta (mxn) + (usd), monto cotizaci\xc3\xb3n (mxn) + (usd),\n solicitud de apoyo y comentarios adicionales\n """\n def __init__(self, hora_actividad, duracion_actividad, cliente, tipo_actividad, resultado,\n monto_venta_mxn, monto_venta_usd, monto_cot_mxn, monto_cot_usd, requiero_apoyo, comentarios_extra):\n self.hora_actividad = hora_actividad\n self.duracion_actividad = duracion_actividad\n self.cliente = cliente\n self.tipo_actividad = tipo_actividad\n self.resultado = resultado\n self.monto_venta_mxn = monto_venta_mxn\n self.monto_venta_usd = monto_venta_usd\n self.monto_cot_mxn = monto_cot_mxn\n self.monto_cot_usd = monto_cot_usd\n self.requiero_apoyo = requiero_apoyo\n self.comentarios_extra = comentarios_extra\n\n\nclass PDFReport:\n """\n Crea el Reporte de Actividades diarias en archivo de formato PDF\n """\n def __init__(self, filename):\n self.filename = filename\n\n\nvendedor = Vendedor(\'John Doe\', \'Stack Overflow\', datetime.now().strftime(\'%d/%m/%Y\'))\n\nfile_name = \'cronograma_actividades.pdf\'\ndocument_title = \'Cronograma Diario de Actividades\'\ntitle = \'Cronograma Diario de Actividades\'\nnombre_colaborador = vendedor.nombre_vendedor\nsucursal_colaborador = vendedor.sucursal\nfecha_actual = vendedor.dia_reporte\n\n\ncanvas = Canvas(file_name)\ncanvas.setPageSize(landscape(letter))\ncanvas.setTitle(document_title)\n\n\ncanvas.setFont("Helvetica-Bold", 20)\ncanvas.drawCentredString(385+100, 805-250, title)\ncanvas.setFont("Helvetica", 16)\ncanvas.drawCentredString(385+100, 785-250, nombre_colaborador + \' - \' + sucursal_colaborador)\ncanvas.setFont("Helvetica", 14)\ncanvas.drawCentredString(385+100, 765-250, fecha_actual)\n\ntitle_background = colors.fidblue\nhour = 8\nminute = 0\nhour_list = []\n\ndata_actividades = [\n {\'Hora\', \'Cliente\', \'Resultado de \\nActividad\', \'Monto Venta \\n(MXN)\', \'Monto Venta \\n(USD)\',\n \'Monto Cotizaci\xc3\xb3n \\n(MXN)\', \'Monto Cotizaci\xc3\xb3n \\n(USD)\', \'Comentarios \\nAdicionales\'},\n]\n\ni = 0\nfor i in range(47):\n\n if minute == 0:\n if hour <= 12:\n time = str(hour) + \':\' + str(minute) + \'0 a.m.\'\n else:\n time = str(hour-12) + \':\' + str(minute) + \'0 p.m.\'\n else:\n if hour <= 12:\n time = str(hour) + \':\' + str(minute) + \' a.m.\'\n else:\n time = str(hour-12) + \':\' + str(minute) + \' p.m.\'\n\n if minute != 45:\n minute += 15\n else:\n hour += 1\n minute = 0\n hour_list.append(time)\n\n # I TRIED THIS SOLUTION BUT THIS DIDN\'T WORK\n # if i % 20 == 0:\n # canvas.showPage()\n\n data_actividades.append([hour_list[i], i, i, i, i, i, i, i])\n\n i += 1\n\n table_actividades = Table(data_actividades, colWidths=85, rowHeights=30, repeatRows=1)\n tblStyle = TableStyle([\n (\'BACKGROUND\', (0, 0), (-1, 0), title_background),\n (\'TEXTCOLOR\', (0, 0), (-1, 0), colors.whitesmoke),\n (\'ALIGN\', (1, 0), (1, -1), \'CENTER\'),\n (\'GRID\', (0, 0), (-1, -1), 1, colors.black)\n ])\n\n rowNumb = len(data_actividades)\n for row in range(1, rowNumb):\n if row % 2 == 0:\n table_background = colors.lightblue\n else:\n table_background = colors.aliceblue\n\n tblStyle.add(\'BACKGROUND\', (0, row), (-1, row), table_background)\n\n table_actividades.setStyle(tblStyle)\n\n width = 150\n height = 150\n table_actividades.wrapOn(canvas, width, height)\n table_actividades.drawOn(canvas, 65, (0 - height) - 240)\n\ncanvas.save()\nRun Code Online (Sandbox Code Playgroud)\n我尝试添加:
\nif i % 20 == 0:\n canvas.showPage()\nRun Code Online (Sandbox Code Playgroud)\n然而这并没有达到预期的结果。
\n其他快速说明:虽然我专门对表格的列标题进行了编码。运行程序后,列标题的顺序由于某种原因被修改(请参阅粘贴的图像)。知道为什么会发生这种情况吗?
\ndata_actividades = [\n {\'Hora\', \'Cliente\', \'Resultado de \\nActividad\', \'Monto Venta \\n(MXN)\', \'Monto Venta \\n(USD)\',\n \'Monto Cotizaci\xc3\xb3n \\n(MXN)\', \'Monto Cotizaci\xc3\xb3n \\n(USD)\', \'Comentarios \\nAdicionales\'},\n]\nRun Code Online (Sandbox Code Playgroud)\n预先非常感谢您,祝您有美好的一天!
\n您应该使用模板,如官方文档第 5 章“PLATYPUS - 页面布局和版式使用脚本”中的建议。
\n基本思想是使用框架,并将您想要添加的所有信息添加到列表元素中。在我的例子中,我将其称为“内容”,使用命令“ contents.append(FrameBreak())”,您可以离开框架并处理下一个框架,另一方面,如果您想更改模板的类型,可以使用命令“\n contents.append(NextPageTemplate(\'<template_name>\'))”
我的建议:
\n对于您的情况,我使用了两个模板,第一个模板包含带有工作表信息的标题和表格的第一部分,另一个模板对应于其余内容。这些模板的名称为firstpage和laterpage。代码如下:
\nfrom reportlab.pdfgen.canvas import Canvas\nfrom datetime import datetime, timedelta\nfrom reportlab.platypus import Table, TableStyle\nfrom reportlab.lib import colors\nfrom reportlab.lib.pagesizes import letter, landscape\nfrom reportlab.platypus import BaseDocTemplate, Frame, Paragraph, PageBreak, \\\n PageTemplate, Spacer, FrameBreak, NextPageTemplate, Image\nfrom reportlab.lib.pagesizes import letter,A4\nfrom reportlab.lib.units import inch, cm\nfrom reportlab.lib.styles import getSampleStyleSheet\nfrom reportlab.lib.enums import TA_JUSTIFY, TA_CENTER,TA_LEFT,TA_RIGHT\nclass Vendedor:\n """\n Informaci\xc3\xb3n del Vendedor: Nombre, sucursal, meta de venta\n """\n def __init__(self, nombre_vendedor, sucursal, dia_reporte):\n self.nombre_vendedor = nombre_vendedor\n self.sucursal = sucursal\n self.dia_reporte = dia_reporte\n\n\nclass Actividades:\n """\n Informaci\xc3\xb3n de las Actividades realizadas: Hora de actividad y duraci\xc3\xb3n, cliente atendido,\n tipo de actividad, resultado, monto venta (mxn) + (usd), monto cotizaci\xc3\xb3n (mxn) + (usd),\n solicitud de apoyo y comentarios adicionales\n """\n def __init__(self, hora_actividad, duracion_actividad, cliente, tipo_actividad, resultado,\n monto_venta_mxn, monto_venta_usd, monto_cot_mxn, monto_cot_usd, requiero_apoyo, comentarios_extra):\n self.hora_actividad = hora_actividad\n self.duracion_actividad = duracion_actividad\n self.cliente = cliente\n self.tipo_actividad = tipo_actividad\n self.resultado = resultado\n self.monto_venta_mxn = monto_venta_mxn\n self.monto_venta_usd = monto_venta_usd\n self.monto_cot_mxn = monto_cot_mxn\n self.monto_cot_usd = monto_cot_usd\n self.requiero_apoyo = requiero_apoyo\n self.comentarios_extra = comentarios_extra\n\nclass PDFReport:\n """\n Crea el Reporte de Actividades diarias en archivo de formato PDF\n """\n def __init__(self, filename):\n self.filename = filename\n\n\nvendedor = Vendedor(\'John Doe\', \'Stack Overflow\', datetime.now().strftime(\'%d/%m/%Y\'))\n\nfile_name = \'cronograma_actividades.pdf\'\ndocument_title = \'Cronograma Diario de Actividades\'\ntitle = \'Cronograma Diario de Actividades\'\nnombre_colaborador = vendedor.nombre_vendedor\nsucursal_colaborador = vendedor.sucursal\nfecha_actual = vendedor.dia_reporte\n\n\ncanvas = Canvas(file_name, pagesize=landscape(letter))\n\ndoc = BaseDocTemplate(file_name)\ncontents =[]\nwidth,height = A4\n\nleft_header_frame = Frame(\n 0.2*inch, \n height-1.2*inch, \n 2*inch, \n 1*inch\n )\n\nright_header_frame = Frame(\n 2.2*inch, \n height-1.2*inch, \n width-2.5*inch, \n 1*inch,id=\'normal\'\n )\n\nframe_later = Frame(\n 0.2*inch, \n 0.6*inch, \n (width-0.6*inch)+0.17*inch, \n height-1*inch,\n leftPadding = 0, \n topPadding=0, \n showBoundary = 1,\n id=\'col\'\n )\n\nframe_table= Frame(\n 0.2*inch, \n 0.7*inch, \n (width-0.6*inch)+0.17*inch, \n height-2*inch,\n leftPadding = 0, \n topPadding=0, \n showBoundary = 1,\n id=\'col\'\n )\nlaterpages = PageTemplate(id=\'laterpages\',frames=[frame_later])\n\nfirstpage = PageTemplate(id=\'firstpage\',frames=[left_header_frame, right_header_frame,frame_table],)\n\ncontents.append(NextPageTemplate(\'firstpage\'))\nlogoleft = Image(\'logo_power.png\')\nlogoleft._restrictSize(1.5*inch, 1.5*inch)\nlogoleft.hAlign = \'CENTER\'\nlogoleft.vAlign = \'CENTER\'\n\ncontents.append(logoleft)\ncontents.append(FrameBreak())\nstyleSheet = getSampleStyleSheet()\nstyle_title = styleSheet[\'Heading1\']\nstyle_title.fontSize = 20 \nstyle_title.fontName = \'Helvetica-Bold\'\nstyle_title.alignment=TA_CENTER\n\nstyle_data = styleSheet[\'Normal\']\nstyle_data.fontSize = 16 \nstyle_data.fontName = \'Helvetica\'\nstyle_data.alignment=TA_CENTER\n\nstyle_date = styleSheet[\'Normal\']\nstyle_date.fontSize = 14\nstyle_date.fontName = \'Helvetica\'\nstyle_date.alignment=TA_CENTER\n\ncanvas.setTitle(document_title)\n\ncontents.append(Paragraph(title, style_title))\ncontents.append(Paragraph(nombre_colaborador + \' - \' + sucursal_colaborador, style_data))\ncontents.append(Paragraph(fecha_actual, style_date))\ncontents.append(FrameBreak())\n\ntitle_background = colors.fidblue\nhour = 8\nminute = 0\nhour_list = []\n\ndata_actividades = [\n {\'Hora\', \'Cliente\', \'Resultado de \\nActividad\', \'Monto Venta \\n(MXN)\', \'Monto Venta \\n(USD)\',\n \'Monto Cotizaci\xc3\xb3n \\n(MXN)\', \'Monto Cotizaci\xc3\xb3n \\n(USD)\', \'Comentarios \\nAdicionales\'},\n]\n\ni = 0\nfor i in range(300):\n\n if minute == 0:\n if hour <= 12:\n time = str(hour) + \':\' + str(minute) + \'0 a.m.\'\n else:\n time = str(hour-12) + \':\' + str(minute) + \'0 p.m.\'\n else:\n if hour <= 12:\n time = str(hour) + \':\' + str(minute) + \' a.m.\'\n else:\n time = str(hour-12) + \':\' + str(minute) + \' p.m.\'\n\n if minute != 45:\n minute += 15\n else:\n hour += 1\n minute = 0\n hour_list.append(time)\n\n # I TRIED THIS SOLUTION BUT THIS DIDN\'T WORK\n # if i % 20 == 0:\n \n\n data_actividades.append([hour_list[i], i, i, i, i, i, i, i])\n\n i += 1\n\n table_actividades = Table(data_actividades, colWidths=85, rowHeights=30, repeatRows=1)\n tblStyle = TableStyle([\n (\'BACKGROUND\', (0, 0), (-1, 0), title_background),\n (\'TEXTCOLOR\', (0, 0), (-1, 0), colors.whitesmoke),\n (\'ALIGN\', (1, 0), (1, -1), \'CENTER\'),\n (\'GRID\', (0, 0), (-1, -1), 1, colors.black)\n ])\n\n rowNumb = len(data_actividades)\n for row in range(1, rowNumb):\n if row % 2 == 0:\n table_background = colors.lightblue\n else:\n table_background = colors.aliceblue\n\n tblStyle.add(\'BACKGROUND\', (0, row), (-1, row), table_background)\n\n table_actividades.setStyle(tblStyle)\n\n width = 150\n height = 150\n \ncontents.append(NextPageTemplate(\'laterpages\'))\ncontents.append(table_actividades)\n\n\ncontents.append(PageBreak())\n\n\ndoc.addPageTemplates([firstpage,laterpages])\ndoc.build(contents)\nRun Code Online (Sandbox Code Playgroud)\n结果
\n有了这个,你可以添加任意数量的记录,我尝试了 300 条。该表并不完全可见,因为为了方便我制作了 A4 尺寸的 pdf。但是,任何尺寸的原理都是相同的,因此您必须调整框架的尺寸和 pdf 页面的尺寸。
\n\n额外,在每个页面上添加标题
\n由于现在只需要一个模板,因此应删除“first_page”模板,因为它对于所有页面都是相同的。按照您在开始时提出的相同方式,我每 21 条记录剪切一次表(以包括表的标题),并将其分组在一个列表中,然后在每个周期中迭代添加带有徽标的标题。逻辑切割语句中也包含记录数未达到21但记录数即将结束的情况。代码如下:
\ncanvas = Canvas(file_name, pagesize=landscape(letter))\n\ndoc = BaseDocTemplate(file_name)\ncontents =[]\nwidth,height = A4\n\nleft_header_frame = Frame(\n 0.2*inch, \n height-1.2*inch, \n 2*inch, \n 1*inch\n )\n\nright_header_frame = Frame(\n 2.2*inch, \n height-1.2*inch, \n width-2.5*inch, \n 1*inch,id=\'normal\'\n )\n\nframe_table= Frame(\n 0.2*inch, \n 0.7*inch, \n (width-0.6*inch)+0.17*inch, \n height-2*inch,\n leftPadding = 0, \n topPadding=0, \n showBoundary = 1,\n id=\'col\'\n )\n\nlaterpages = PageTemplate(id=\'laterpages\',frames=[left_header_frame, right_header_frame,frame_table],)\n\nlogoleft = Image(\'logo_power.png\')\nlogoleft._restrictSize(1.5*inch, 1.5*inch)\nlogoleft.hAlign = \'CENTER\'\nlogoleft.vAlign = \'CENTER\'\n\n\nstyleSheet = getSampleStyleSheet()\nstyle_title = styleSheet[\'Heading1\']\nstyle_title.fontSize = 20 \nstyle_title.fontName = \'Helvetica-Bold\'\nstyle_title.alignment=TA_CENTER\n\nstyle_data = styleSheet[\'Normal\']\nstyle_data.fontSize = 16 \nstyle_data.fontName = \'Helvetica\'\nstyle_data.alignment=TA_CENTER\n\nstyle_date = styleSheet[\'Normal\']\nstyle_date.fontSize = 14\nstyle_date.fontName = \'Helvetica\'\nstyle_date.alignment=TA_CENTER\n\ncanvas.setTitle(document_title)\n\n\ntitle_background = colors.fidblue\nhour = 8\nminute = 0\nhour_list = []\n\ndata_actividades = [\n {\'Hora\', \'Cliente\', \'Resultado de \\nActividad\', \'Monto Venta \\n(MXN)\', \'Monto Venta \\n(USD)\',\n \'Monto Cotizaci\xc3\xb3n \\n(MXN)\', \'Monto Cotizaci\xc3\xb3n \\n(USD)\', \'Comentarios \\nAdicionales\'},\n]\n\ni = 0\ntable_group= []\nsize = 304\n\ncount = 0\nfor i in range(size):\n\n if minute == 0:\n if hour <= 12:\n time = str(hour) + \':\' + str(minute) + \'0 a.m.\'\n else:\n time = str(hour-12) + \':\' + str(minute) + \'0 p.m.\'\n else:\n if hour <= 12:\n time = str(hour) + \':\' + str(minute) + \' a.m.\'\n else:\n time = str(hour-12) + \':\' + str(minute) + \' p.m.\'\n\n if minute != 45:\n minute += 15\n else:\n hour += 1\n minute = 0\n hour_list.append(time) \n\n data_actividades.append([hour_list[i], i, i, i, i, i, i, i])\n\n i += 1\n\n table_actividades = Table(data_actividades, colWidths=85, rowHeights=30, repeatRows=1)\n tblStyle = TableStyle([\n (\'BACKGROUND\', (0, 0), (-1, 0), title_background),\n (\'TEXTCOLOR\', (0, 0), (-1, 0), colors.whitesmoke),\n (\'ALIGN\', (1, 0), (1, -1), \'CENTER\'),\n (\'GRID\', (0, 0), (-1, -1), 1, colors.black)\n ])\n\n rowNumb = len(data_actividades)\n for row in range(1, rowNumb):\n if row % 2 == 0:\n table_background = colors.lightblue\n else:\n table_background = colors.aliceblue\n\n tblStyle.add(\'BACKGROUND\', (0, row), (-1, row), table_background)\n\n table_actividades.setStyle(tblStyle)\n\n if ((count >= 20) or (i== size) ):\n count = 0\n table_group.append(table_actividades)\n data_actividades = [\n {\'Hora\', \'Cliente\', \'Resultado de \\nActividad\', \'Monto Venta \\n(MXN)\', \'Monto Venta \\n(USD)\',\n \'Monto Cotizaci\xc3\xb3n \\n(MXN)\', \'Monto Cotizaci\xc3\xb3n \\n(USD)\', \'Comentarios \\nAdicionales\'},]\n width = 150\n height = 150\n count += 1\n if i > size:\n\n break\n\ncontents.append(NextPageTemplate(\'laterpages\'))\n\nfor table in table_group:\n\n contents.append(logoleft)\n contents.append(FrameBreak())\n contents.append(Paragraph(title, style_title))\n contents.append(Paragraph(nombre_colaborador + \' - \' + sucursal_colaborador, style_data))\n contents.append(Paragraph(fecha_actual, style_date))\n contents.append(FrameBreak()) \n contents.append(table)\n contents.append(FrameBreak())\n\ndoc.addPageTemplates([laterpages,])\ndoc.build(contents)\nRun Code Online (Sandbox Code Playgroud)\n额外结果:
\n\n| 归档时间: |
|
| 查看次数: |
4260 次 |
| 最近记录: |