You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python导出PDF:Anaconda可运行VS报错求助

问题描述

在Anaconda环境的Jupyter中运行Python导出PDF的代码一切正常,但在Visual Studio中运行时出现多个错误:

  • TypeError: FPDF.set_font() missing 1 required positional argument: 'family'
  • multi_cell不存在ln参数
相关代码
from fpdf import FPDF
import pytz
from datetime import datetime
from tkinter import filedialog

class PDF(FPDF):
    def footer(self):
        # 设置页脚位置
        self.set_y(-10)
        # 设置字体大小
        self.set_font('Arial', 'I', 8)
        # 添加页码
        self.cell(0, 10, f'Page {self.page_no()}/{{nb}}', 0, 0, 'C')
        
    def create_table(self,table_data, title='', data_size = 10, title_size=12, align_data='L', align_header='L', cell_width='even', x_start='x_default',emphasize_data=[], emphasize_style=None, emphasize_color=(0,0,0)):
        default_style = self.font_style
        if emphasize_style == None:
            emphasize_style = default_style
            
        # 获取列宽
        def get_col_widths():
            col_width = cell_width
            if col_width == 'even':
                col_width = self.epw / len(data[0]) - 1  # 平均分配宽度(epw是页面有效宽度,不含边距)
            elif col_width == 'uneven':
                col_widths = []
                # 遍历列,找出每列最宽单元格的宽度
                for col in range(len(table_data[0])):
                    longest = 0
                    for row in range(len(table_data)):
                        cell_value = str(table_data[row][col])
                        value_length = self.get_string_width(cell_value)
                        if value_length > longest:
                            longest = value_length
                    col_widths.append(longest + 4) # 加4作为内边距
                col_width = col_widths
            elif isinstance(cell_width, list):
                col_width = cell_width
            else:
                col_width = int(col_width)
            return col_width
            
        if isinstance(table_data, dict):
            header = [key for key in table_data]
            data = []
            for key in table_data:
                value = table_data[key]
                data.append(value)
            # 转置数据,让格式符合表格要求
            data = [list(a) for a in zip(*data)]
        else:
            header = table_data[0]
            data = table_data[1:]
            
        line_height = self.font_size * 2.5
        col_width = get_col_widths()
        self.set_font(size=title_size)
        
        # 获取表格的X起始位置(用于居中表格)
        if x_start == 'C':
            table_width = 0
            if isinstance(col_width, list):
                for width in col_width:
                    table_width += width
            else:
                table_width = col_width * len(table_data[0])
            margin_width = self.w - table_width
            center_table = margin_width / 2
            x_start = center_table
            self.set_x(x_start)
        elif isinstance(x_start, int):
            self.set_x(x_start)
        elif x_start == 'x_default':
            x_start = self.set_x(self.l_margin)
            
        # 生成PDF内容
        self.set_font(size=10)
        self.multi_cell(0, 2, 'Bộ Giáo dục và Đào tạo', border=0, align='L', ln=3, max_line_height=self.font_size)
        self.ln(5)
        self.multi_cell(0, 2, 'Trường ', border=0, align='L', ln=3, max_line_height=self.font_size)
        self.ln(5)
        self.multi_cell(0, 2, 'Địa chỉ:', border=0, align='L', ln=3, max_line_height=self.font_size)
        self.ln(10)
        
        # 添加标题
        self.set_font(size=15)
        if title != '':
            self.multi_cell(0, line_height, title, border=0, align='c', ln=3, max_line_height=self.font_size)
            self.ln(8)
            
        # 获取越南时区当前时间
        tz_VN = pytz.timezone('Asia/Ho_Chi_Minh')
        datetime_VN = datetime.now(tz_VN)
        now_vn = datetime_VN.strftime("%d/%m/%Y")
        self.set_font(size=10)
        self.multi_cell(0, 2, f'Ngày: {now_vn}', border=0, align='r', ln=3, max_line_height=self.font_size)
        self.ln(10)
        
        self.set_font(size=data_size)
        # 添加表头
        y1 = self.get_y()
        x_left = x_start if x_start else self.get_x()
        x_right = self.epw + x_left
        
        if not isinstance(col_width, list):
            if x_start:
                self.set_x(x_start)
            for datum in header:
                self.multi_cell(col_width, line_height, datum, border=0, align=align_header, ln=3, max_line_height=self.font_size)
                x_right = self.get_x()
            self.ln(line_height)
            y2 = self.get_y()
            self.line(x_left,y1,x_right,y1)
            self.line(x_left,y2,x_right,y2)
            
            # 添加表格数据
            for row in data:
                if x_start:
                    self.set_x(x_start)
                for datum in row:
                    if datum in emphasize_data:
                        self.set_text_color(*emphasize_color)
                        self.set_font(style=emphasize_style)
                        self.multi_cell(col_width, line_height, datum, border=0, align=align_data, ln=3, max_line_height=self.font_size)
                        self.set_text_color(0,0,0)
                        self.set_font(style=default_style)
                    else:
                        self.multi_cell(col_width, line_height, datum, border=0, align=align_data, ln=3, max_line_height=self.font_size)
                self.ln(line_height)
        else:
            if x_start:
                self.set_x(x_start)
            for i in range(len(header)):
                datum = header[i]
                self.multi_cell(col_width[i], line_height, datum, border=0, align=align_header, ln=3, max_line_height=self.font_size)
                x_right = self.get_x()
            self.ln(line_height)
            y2 = self.get_y()
            self.line(x_left,y1,x_right,y1)
            self.line(x_left,y2,x_right,y2)
            
            # 添加表格数据
            for row in data:
                if x_start:
                    self.set_x(x_start)
                for i in range(len(row)):
                    datum = str(row[i]) if not isinstance(row[i], str) else row[i]
                    adjusted_col_width = col_width[i]
                    if datum in emphasize_data:
                        self.set_text_color(*emphasize_color)
                        self.set_font(style=emphasize_style)
                        self.multi_cell(adjusted_col_width, line_height, datum, border=0, align=align_data, ln=3, max_line_height=self.font_size)
                        self.set_text_color(0,0,0)
                        self.set_font(style=default_style)
                    else:
                        self.multi_cell(adjusted_col_width, line_height, datum, border=0, align=align_data, ln=3, max_line_height=self.font_size)
                self.ln(line_height)
        y3 = self.get_y()
        self.line(x_left,y3,x_right,y3)

# 生成PDF示例(需提前定义表格数据data)
data = [
    ["STT", "Tên", "Điểm"],
    ["1", "Nguyễn Văn A", "8.5"],
    ["2", "Trần Thị B", "9.0"]
]

pdf = PDF()
pdf.add_page()
pdf.add_font('DejaVu', '', r'ttf\DejaVuSansCondensed.ttf', uni=True)
pdf.set_font("DejaVu","",12)
pdf.alias_nb_pages()
pdf.create_table(table_data = data,title='Báo cáo', cell_width='uneven',x_start='C')
filename = filedialog.asksaveasfilename(defaultextension='.pdf')
if filename:
    pdf.output(filename, 'F')
解决方案

问题根源

两个环境的FPDF库版本不兼容:

  • Jupyter环境安装的是fpdf2(新版库,API更灵活,支持省略set_font的family参数、multi_cell的ln/max_line_height参数)
  • Visual Studio环境安装的是旧版fpdf(即fpdf1.x,API严格,缺少新版的参数支持)

修复步骤

  1. 统一库版本
    在VS的Python环境中执行以下命令,卸载旧版并安装新版fpdf2:
pip uninstall -y fpdf
pip install fpdf2
  1. 代码兼容检查
  • 若self.font_style报错,直接替换为default_style = ''(fpdf2默认字体样式为空字符串)
  • 确认字体文件路径正确,可改为绝对路径避免相对路径问题
  • 确保安装了pytz依赖:pip install pytz(Windows系统默认自带tkinter,Linux/macOS需单独安装时执行sudo apt-get install python3-tk或对应系统命令)
  1. 测试运行
    重新在VS中运行代码,即可消除版本不兼容导致的错误。

内容的提问来源于stack exchange,提问作者Matt John

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 11:38:10