我想在Python中生成带有表格、页眉、页脚和可调整单元格数据的多页PDF报告(使用reportlab)
但是,由于奇怪的原因,字体大小并没有随着表格内容而改变...... 我尝试在这里改变: ('FONTSIZE', (0, 1), (-1, -1), 24), # 内容的字体大小
但什么也没发生
import time
from reportlab.lib.pagesizes import landscape, letter
from reportlab.lib import colors
from reportlab.lib.units import inch
from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, PageTemplate, Frame
from reportlab.lib.styles import getSampleStyleSheet
# Function to add header and footer
def add_header_footer(canvas, doc):
canvas.saveState()
# Header
header_text = "Report Header"
canvas.setFont('Helvetica-Bold', 14)
text_width = canvas.stringWidth(header_text, 'Helvetica-Bold', 14)
canvas.drawCentredString(doc.pagesize[0] / 2, doc.pagesize[1] - 80, header_text) # Adjusted position
# Footer
footer_text = f"Page {doc.page}"
canvas.setFont('Helvetica', 10)
text_width = canvas.stringWidth(footer_text, 'Helvetica', 10)
canvas.drawString((doc.pagesize[0] - text_width) / 2, 40, footer_text)
canvas.restoreState()
# Function to generate PDF with ordered data in a table format
def generate_pdf(data, pdf_filename):
# Create the document
doc = SimpleDocTemplate(pdf_filename, pagesize=landscape(letter), topMargin=1.5*inch) # Adjust topMargin here
# Define the table data
table_data = [['Parameter Name', 'Expected Value', 'Your INI Value']]
# Get the sample style sheet
styles = getSampleStyleSheet()
styleN = styles['Normal']
# Add "Results for the Ini file:" text as a paragraph before the table
results_text = "Results for the Ini file:"
results_paragraph = Paragraph(results_text, styles['Heading2'])
# Calculate the height of the results paragraph
results_paragraph_height = results_paragraph.wrap(doc.width, doc.topMargin)[1]
# Populate the table with data
for i in range(len(data['Parameter_Name'])):
# Ensure each cell in the row is a Paragraph object
row = [
Paragraph(data['Parameter_Name'][i], styleN),
Paragraph(data['Expected_Value'][i], styleN),
Paragraph(data['Your_INI_Value'][i], styleN)
]
table_data.append(row)
# Create the table
table = Table(table_data, colWidths=[2.5 * inch, 3.0 * inch, 3.0 * inch], repeatRows=1) # use repeatRows=1 if you want the header of the table to be repetad in teh table in the next pages
# Add style to the table
style = TableStyle([
('BACKGROUND', (0, 0), (-1, 0), colors.grey),
('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
('ALIGN', (0, 0), (-1, -1), 'CENTER'),
('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
('FONTSIZE', (0, 0), (-1, 0), 14), # For header in table
('BOTTOMPADDING', (0, 0), (-1, 0), 8),
('BACKGROUND', (0, 1), (-1, -1), colors.beige),
('GRID', (0, 0), (-1, -1), 1, colors.black),
('FONTNAME', (0, 1), (-1, -1), 'Helvetica'),
('FONTSIZE', (0, 1), (-1, -1), 24), # Font size for content
('VALIGN', (0, 0), (-1, -1), 'TOP'), # Ensure text starts from the top of the cell
])
table.setStyle(style)
# Apply conditional styling for rows where values differ
for i in range(1, len(table_data)): # Start from 1 to skip header row
expected_value = data['Expected_Value'][i-1]
your_ini_value = data['Your_INI_Value'][i-1]
if expected_value != your_ini_value:
# Apply red background and white text for differing rows
table.setStyle(TableStyle([
('BACKGROUND', (0, i), (-1, i), colors.red),
('TEXTCOLOR', (0, i), (-1, i), colors.white)
]))
# Define the frame for the page template
frame = Frame(doc.leftMargin, doc.bottomMargin + 5 + results_paragraph_height, doc.width, doc.height - 5 - results_paragraph_height, id='normal')
# frame = Frame(doc.leftMargin, doc.bottomMargin + 100 + results_paragraph_height, doc.width, doc.height - 100 - results_paragraph_height, id='normal')
# Add the PageTemplate with header and footer
template = PageTemplate(id='test', frames=frame, onPage=add_header_footer)
doc.addPageTemplates([template])
# # Calculate row heights for each row in the table
# row_heights = []
# for row in table_data:
# # Ensure all elements in row are Paragraph objects
# if all(isinstance(cell, Paragraph) for cell in row):
# row_heights.append(max([p.wrap(doc.width, doc.height)[1] for p in row]))
# # Remove the header row height
# if row_heights:
# header_row_height = row_heights.pop(0)
# else:
# header_row_height = 0
# Build the PDF
elements = [results_paragraph, table]
doc.build(elements, onFirstPage=add_header_footer, onLaterPages=add_header_footer)
if __name__ == '__main__':
# Example data (20 parameters with fictitious names and values)
data = {
'Parameter_Name': [
'Parameter 1', 'Parameter 2', 'Parameter 3', 'Parameter 4', 'Parameter 5',
'Parameter 6', 'Parameter 7', 'Parameter 8', 'Parameter 9', 'Parameter 10',
'Parameter 11', 'Parameter 12', 'Parameter 13', 'Parameter 14', 'Parameter 15',
'Parameter 16', 'Parameter 17', 'Parameter 18', 'Parameter 19', 'Parameter 20'
],
'Expected_Value': [
'Value 1', 'Expected Value 2', 'Expected Value 3', 'Expected Value 4', 'Expected Value 5',
'Expected Value 6', 'Value 7', 'Expected Value 8', 'Expected Value 9', 'Expected Value 10',
'Expected Value 11', 'Expected Value 12', 'Expected Value 13', 'Expected Value 14', 'Expected Value 15',
'Expected Value 16', 'Value 17', 'Expected Value 18', 'Expected Value 19', 'Expected Value 20'
],
'Your_INI_Value': [
'Value 1', 'Your INI Value 2', 'Your INI Value 3', 'Your INI Value 4', 'Your INI Value 5',
'Your INI Value 6', 'Value 7', 'Your INI Value 8', 'Example of large data for a cell, and autoadjust for Your INI Value 9', 'Your INI Value 10',
'Your INI Value 11', 'Your INI Value 12', 'Your INI Value 13', 'Your INI Value 14', 'Your INI Value 15',
'Your INI Value 16', 'Value 17', 'Your INI Value 18', 'Your INI Value 19', 'Your INI Value 20'
]
}
# PDF filename with timestamp
# pdf_filename = f"ordered_data_{time.strftime('%Y%m%d%H%M%S')}.pdf"
pdf_filename = f"ordered_data.pdf"
# Generate the PDF with ordered data
generate_pdf(data, pdf_filename)
print(pdf_filename)
任何解决方案??
我注意到,因为每个单元格该行是一个 Paragraph 对象,它需要设置该对象的 Fontsize,所以我基本上修改了这个变量“styleN”,所以现在它可以工作:
# Define a custom style for table cells
styleN = ParagraphStyle(
name='CellStyle',
parent=styles['Normal'],
fontName='Times-Roman',
fontSize=12, # Set the desired font size here for the cells
leading=12
)
说的对,问题出在将每个单元格内容包装在
Paragraph
对象中,但没有为这些段落设置字体大小。找到了一种通过修改
styleN
来解决此问题的有效方法。
以下是改进后的代码,并附带解释:
import time
from reportlab.lib.pagesizes import landscape, letter
from reportlab.lib import colors
from reportlab.lib.units import inch
from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, PageTemplate, Frame
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
# Function to add header and footer
def add_header_footer(canvas, doc):
canvas.saveState()
# Header
header_text = "Report Header"
canvas.setFont('Helvetica-Bold', 14)
text_width = canvas.stringWidth(header_text, 'Helvetica-Bold', 14)
canvas.drawCentredString(doc.pagesize[0] / 2, doc.pagesize[1] - 80, header_text)
# Footer
footer_text = f"Page {doc.page}"
canvas.setFont('Helvetica', 10)
text_width = canvas.stringWidth(footer_text, 'Helvetica', 10)
canvas.drawString((doc.pagesize[0] - text_width) / 2, 40, footer_text)
canvas.restoreState()
# Function to generate PDF with ordered data in a table format
def generate_pdf(data, pdf_filename):
# Create the document
doc = SimpleDocTemplate(pdf_filename, pagesize=landscape(letter), topMargin=1.5*inch)
# Define the table data
table_data = [['Parameter Name', 'Expected Value', 'Your INI Value']]
# Get the sample style sheet
styles = getSampleStyleSheet()
# Define a custom style for table cells with desired font size
styleN = ParagraphStyle(
name='CellStyle',
parent=styles['Normal'],
fontName='Times-Roman',
fontSize=12, # Set the desired font size here
leading=14 # Add leading for better readability
)
# Add "Results for the Ini file:" text as a paragraph before the table
results_text = "Results for the Ini file:"
results_paragraph = Paragraph(results_text, styles['Heading2'])
# Calculate the height of the results paragraph
results_paragraph_height = results_paragraph.wrap(doc.width, doc.topMargin)[1]
# Populate the table with data, using the defined style for cells
for i in range(len(data['Parameter_Name'])):
row = [
Paragraph(data['Parameter_Name'][i], styleN),
Paragraph(data['Expected_Value'][i], styleN),
Paragraph(data['Your_INI_Value'][i], styleN)
]
table_data.append(row)
# Create the table
table = Table(table_data, colWidths=[2.5 * inch, 3.0 * inch, 3.0 * inch], repeatRows=1)
# Add style to the table
style = TableStyle([
('BACKGROUND', (0, 0), (-1, 0), colors.grey),
('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
('ALIGN', (0, 0), (-1, -1), 'CENTER'),
('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
('FONTSIZE', (0, 0), (-1, 0), 14),
('BOTTOMPADDING', (0, 0), (-1, 0), 8),
('BACKGROUND', (0, 1), (-1, -1), colors.beige),
('GRID', (0, 0), (-1, -1), 1, colors.black),
('VALIGN', (0, 0), (-1, -1), 'TOP'),
])
table.setStyle(style)
# Apply conditional styling for rows where values differ
for i in range(1, len(table_data)):
expected_value = data['Expected_Value'][i-1]
your_ini_value = data['Your_INI_Value'][i-1]
if expected_value != your_ini_value:
table.setStyle(TableStyle([
('BACKGROUND', (0, i), (-1, i), colors.red),
('TEXTCOLOR', (0, i), (-1, i), colors.white)
]))
# Define the frame for the page template
frame = Frame(doc.leftMargin, doc.bottomMargin + 5 + results_paragraph_height,
doc.width, doc.height - 5 - results_paragraph_height, id='normal')
# Add the PageTemplate with header and footer
template = PageTemplate(id='test', frames=frame, onPage=add_header_footer)
doc.addPageTemplates([template])
# Build the PDF
elements = [results_paragraph, table]
doc.build(elements, onFirstPage=add_header_footer, onLaterPages=add_header_footer)
if __name__ == '__main__':
# ... (rest of your code remains the same)
解释:
-
ParagraphStyle
for Cells: 我们创建了一个名为styleN
的自定义ParagraphStyle
,它继承自styles['Normal']
并设置了所需的fontSize
。 -
Applying the Style:
在创建
Paragraph
对象来填充表格单元格时,我们使用了这个styleN
来确保每个单元格都具有指定的字体大小。 -
Removing Redundant Styles:
从
TableStyle
中删除了'FONTNAME'
和'FONTSIZE'
,因为我们现在在ParagraphStyle
中处理字体样式。
通过这种方式,的表格单元格现在将使用在
styleN
中定义的字体大小,并且可以根据需要轻松调整。