Python与ReportLab:PDF表格中的列宽和对齐错误

8 投票
1 回答
8744 浏览
提问于 2025-04-18 05:51

我在使用Python 2.7(iOS上的Pythonista应用)和reportlab 2.7模块来创建一个包含表格的PDF文件。一切都运行得很好。ReportLab会自动调整列的宽度。但是在两个情况下,我不太明白为什么ReportLab会这样格式化输出,以及我该如何得到我想要的格式。

案例1:几乎都符合我的要求……

+-----+----------+---------------+----------+---------------------------------------------------------------------------------------------------------------+
| Day | Date     | Time          | Duration | Notes                                                                                                         |
+-----+----------+---------------+----------+---------------------------------------------------------------------------------------------------------------+
| Tue | 01.04.14 | 14:00 - 17:15 | 3.25     | Here are some notes.                                                                                          |
+-----+----------+---------------+----------+---------------------------------------------------------------------------------------------------------------+
| Wed | 02.04.14 | 18:00 - 20:15 | 2.25     | Sometime these notes are a little longer text so there must be a line break to let the whole note be visible! |
+-----+----------+---------------+----------+---------------------------------------------------------------------------------------------------------------+
| Thu | 02.04.14 | 14:00 - 17:15 | 3.25     | And sometimes these notes are only a few words.                                                               |
+-----+----------+---------------+----------+---------------------------------------------------------------------------------------------------------------+

案例2:我尝试对齐小数点

在帮助下

TableStyle([('ALIGN', (3,1), (3,-1), 'DECIMAL'),])

我试着让每个小数点都在同一条垂直线上。虽然成功了,但在“持续时间”这一列,所有的数字都被强行靠右对齐,以至于“备注”这一列的部分数字被遮住了(而且“持续时间”值的左边还有很多空白)。看起来右侧的填充是针对小数点或小数点前的数字设置的,而不是整个数值。

+-----+----------+---------------+-----------+-------------------------------------------------+
| Day | Date     | Time          | Duration  | Notes                                           |
+-----+----------+---------------+-----------+-------------------------------------------------+
| Tue | 01.04.14 | 14:00 - 17:15 |        3.2|5Here are some notes.                            |
+-----+----------+---------------+-----------+-------------------------------------------------+
| Wed | 02.04.14 | 14:00 - 17:15 |        3.2|5And sometimes these notes are only a few words. |
+-----+----------+---------------+-----------+-------------------------------------------------+

在帮助下

TableStyle([('RIGHTPADDING', (3,1), (3,-1), 18),])

我得到了更好的结果,但我觉得应该有更好的方法!?

案例3:尝试换行备注文本。

当我使用段落来插入备注文本时,文本会换行,但列的宽度让我很惊讶。我无法让下面的例子与实际输出完全一致。

整个表格的宽度适合文档(DIN A4,不包括边距)。但看起来每一列的宽度都是一样的。这样“日期”、“时间”和“持续时间”这几列就比实际需要的宽得多,而“备注”这一列则比实际需要的窄得多。这两点我在下面的示例表格中无法如我所愿地展示,但我相信你们可以想象到 ;-)。

+-----+----------+---------------+----------+----------------------+
| Day | Date     | Time          | Duration | Notes                |
+-----+----------+---------------+----------+----------------------+
| Tue | 01.04.14 | 14:00 - 17:15 | 3.25     | Here are some notes. |
+-----+----------+---------------+----------+----------------------+
| Wed | 02.04.14 | 18:00 - 20:15 | 2.25     | Sometime these       |
|     |          |               |          | notes are a          |
|     |          |               |          | little longer        |
|     |          |               |          | text so there        |
|     |          |               |          | must be a line       |
|     |          |               |          | break to let         |
|     |          |               |          | the whole note       |
|     |          |               |          | be visible!          |
+-----+----------+---------------+----------+----------------------+
| Thu | 02.04.14 | 14:00 - 17:15 | 3.25     | And sometimes        |
|     |          |               |          | these notes are      |
|     |          |               |          | only a few words.    |
+-----+----------+---------------+----------+----------------------+

这是我使用的代码:

import pipista
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.platypus import SimpleDocTemplate, Paragraph, Table, TableStyle

styleSheet = getSampleStyleSheet()

def makeReportData(n):
  monthreport = []
  monthreport += ('Day', '', 'Time', 'Duration', 'Notes'),
  monthreport += ('Tue', '01.04.14', '14:00 - 17:15', '3.25', n[0]),
  monthreport += ('Wed', '02.04.14', '14:00 - 17:15', '3.25', n[1]),
  monthreport += ('Thu', '03.04.14', '14:00 - 17:15', '3.25', n[2]),
  return monthreport

notes = ['Here are some notes.',
         'Sometime these notes are a little longer text so there must be a line break to let the whole note be visible!',
         'And sometimes these notes are only a few words.']

paranote = []
for note in notes:
  paranote += (Paragraph(note, styleSheet["BodyText"]),)

tstyle = [('INNERGRID', (0,0), (-1,-1), 0.25, colors.black),
          ('BOX', (0,0), (-1,-1), 0.25, colors.black),]

case1 = []
t = Table(makeReportData(notes))
t.setStyle(TableStyle(tstyle))
case1.append(t)
doc = SimpleDocTemplate('Table normal.pdf', pagesize = A4)
doc.build(case1)

case2 = []
tstyledez = tstyle + [('ALIGN', (3,1), (3,-1), 'DECIMAL'),]
t.setStyle(TableStyle(tstyledez))
case2.append(t)
doc = SimpleDocTemplate('Table align decimal.pdf', pagesize = A4)
doc.build(case2)

case3 = []
t = Table(makeReportData(paranote))
tstylepara = tstyle + [('VALIGN',(0,1),(3,-1),'TOP'),]
t.setStyle(TableStyle(tstylepara))
case3.append(t)
doc = SimpleDocTemplate('Table Paragraph.pdf', pagesize = A4)
doc.build(case3)

我希望有人能给我指个方向。

1 个回答

13

好的,查看文档总是个好主意!来自ReportLab的说明:

如果一个单元格的值是一个可流动的对象(Flowable)或者是可流动对象的列表,这些对象要么必须有确定的宽度,要么它们所在的列必须有固定的宽度。

解决方案:

from reportlab.lib.units import mm

t = Table(makeReportData(paranote), colWidths=(None, None, None, None, 100*mm))

我原以为DECIMAL对齐的问题(情况2)也可以用同样的方法解决,但结果并没有成功。

撰写回答