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

使用PHP+FPDF生成PDF:复选框对齐与表格自适应问题求助

解决FPDF生成PDF的两个问题:复选框对齐与表格自适应列宽

以下是修复后的完整代码,同时解决了复选框对齐和表格自适应列宽的问题:

<?php
require('api/fpdf186/fpdf.php');

class PDF extends FPDF
{
    // Header function
    function Header()
    {
        $this->SetFillColor(173, 216, 230); // Light blue
        $this->Rect(10, 10, 190, 20, 'F');
        $this->SetFont('Arial', 'B', 16);
        $this->Cell(0, 10, 'Medical Report', 0, 1, 'C');
        $this->SetFont('Arial', 'I', 10);
        $this->Cell(0, 5, 'Patient Details and Doctor Summary', 0, 1, 'C');
        $this->Ln(10); // Gap after header
    }

    // Section Header with gap below
    function SectionHeader($title)
    {
        $this->Ln(5); // Gap after section header
        $this->SetFont('Arial', 'B', 12);
        $this->SetFillColor(230, 230, 230); // Light gray background
        $this->Cell(190, 8, $title, 0, 1, 'L', true);
        $this->Ln(5); // Gap after section header
    }

    // Form Field (label + underline for data)
    function FormField($label, $width)
    {
        $this->SetFont('Arial', '', 11);
        $this->Cell($width, 8, $label, 0, 0, 'L'); // Label
        $this->Cell(190 - $width, 8, '', 'B'); // Underline for data
        $this->Ln(8); // Line break after each field
    }

    // 修复后的复选框绘制函数,解决对齐问题
    function DrawCheckbox($label, $x, $y, $checked = false)
    {
        $cellHeight = 8;
        // 调整复选框Y坐标,使其垂直居中
        $checkboxY = $y + ($cellHeight - 5) / 2;
        
        // 绘制复选框
        $this->Rect($x, $checkboxY, 5, 5);
        
        // 标记选中状态
        if ($checked) {
            $this->SetFont('Arial', 'B', 8);
            $this->Text($x + 1, $checkboxY + 4, 'X'); // 精准定位X标记
            $this->SetFont('Arial', '', 11); // 恢复原字体
        }
        
        // 绘制标签,保持与左侧单元格高度一致
        $this->SetXY($x + 8, $y);
        $this->Cell(0, $cellHeight, $label, 0, 0, 'L');
    }

    // Diagnosis Table Header
    function DiagnosisTableHeader($widths)
    {
        $this->SetFont('Arial', 'B', 11);
        $this->SetFillColor(200, 200, 200); // Light gray background
        $this->Cell($widths[0], 8, 'Diagnosis', 1, 0, 'C', true); 
        $this->Cell($widths[1], 8, 'Result', 1, 0, 'C', true);
        $this->Ln();
    }

    // 修复后的诊断表格行,支持长文本换行
    function DiagnosisTableRow($diagnosis, $result, $widths)
    {
        $this->SetFont('Arial', '', 11);
        $currentY = $this->GetY();
        
        // 绘制第一列,自动换行
        $this->MultiCell($widths[0], 8, $diagnosis, 1);
        $column1Height = $this->GetY() - $currentY;
        
        // 回到当前行Y坐标,绘制第二列
        $this->SetXY($widths[0] + 10, $currentY);
        $this->MultiCell($widths[1], 8, $result, 1);
        $column2Height = $this->GetY() - $currentY;
        
        // 取最大高度,确保下一行对齐
        $this->SetY($currentY + max($column1Height, $column2Height));
    }

    // Prescription Table Header
    function PrescriptionTableHeader($widths)
    {
        $this->SetFont('Arial', 'B', 11);
        $this->SetFillColor(200, 200, 200); // Light gray background
        $this->Cell($widths[0], 8, 'Medicine Name', 1, 0, 'C', true); 
        $this->Cell($widths[1], 8, 'Dosage', 1, 0, 'C', true);
        $this->Cell($widths[2], 8, 'Explanation', 1, 0, 'C', true);
        $this->Cell($widths[3], 8, 'Availability', 1, 0, 'C', true);
        $this->Ln();
    }

    // 修复后的处方表格行,支持长文本换行
    function PrescriptionTableRow($medicine, $dosage, $explanation, $availability, $widths)
    {
        $this->SetFont('Arial', '', 11);
        $currentY = $this->GetY();
        
        // 第一列:药品名称
        $this->MultiCell($widths[0], 8, $medicine, 1);
        $h1 = $this->GetY() - $currentY;
        
        // 第二列:剂量
        $this->SetXY(10 + $widths[0], $currentY);
        $this->MultiCell($widths[1], 8, $dosage, 1);
        $h2 = $this->GetY() - $currentY;
        
        // 第三列:说明
        $this->SetXY(10 + $widths[0] + $widths[1], $currentY);
        $this->MultiCell($widths[2], 8, $explanation, 1);
        $h3 = $this->GetY() - $currentY;
        
        // 第四列:可用性
        $this->SetXY(10 + $widths[0] + $widths[1] + $widths[2], $currentY);
        $this->MultiCell($widths[3], 8, $availability ? '[x]' : '[ ]', 1, 'C');
        $h4 = $this->GetY() - $currentY;
        
        // 统一行高
        $this->SetY($currentY + max($h1, $h2, $h3, $h4));
    }

    // 改进的列宽计算函数,确保总宽度不超过页面
    function CalculateMaxWidths($data, $defaultWidths)
    {
        $pageWidth = 190;
        $widths = $defaultWidths;
        
        // 计算每列的最大内容宽度
        foreach ($data as $row) {
            foreach ($row as $key => $value) {
                if (!is_bool($value)) { // 跳过布尔值(可用性字段)
                    $textWidth = $this->GetStringWidth($value) + 6; // 增加内边距
                    if ($textWidth > $widths[$key]) {
                        $widths[$key] = $textWidth;
                    }
                }
            }
        }
        
        // 计算总宽度,若超过页面宽度则按比例缩放
        $totalWidth = array_sum($widths);
        if ($totalWidth > $pageWidth) {
            $scale = $pageWidth / $totalWidth;
            foreach ($widths as &$w) {
                $w = round($w * $scale);
            }
            // 微调确保总宽度等于页面宽度
            $diff = $pageWidth - array_sum($widths);
            $widths[count($widths)-1] += $diff;
        }
        
        return $widths;
    }

    // MultiCell wrapper to handle long text
    function MultiCellWrapped($width, $height, $text)
    {
        $this->MultiCell($width, $height, $text, 1);
    }
}

// Create PDF instance
$pdf = new PDF();
$pdf->AddPage();

// Part A: Patient's Information Section
$pdf->SectionHeader('Patient Information');

// Title field with checkboxes
$pdf->Cell(30, 8, 'Title:', 0, 0, 'L');
$pdf->DrawCheckbox('Mr', 45, $pdf->GetY(), true); // Checked by default
$pdf->DrawCheckbox('Mrs', 65, $pdf->GetY(), false);
$pdf->Ln(8); // Line break after checkboxes

// Full Name
$pdf->FormField('Full Name', 40);

// Birth Date
$pdf->FormField('Birth Date', 40);

// Address
$pdf->FormField('Address', 40);

// Diagnosis Table Data
$diagnosisData = [
    ['Fracture', 'Positive'],
    ['Concussion', 'Negative'],
    ['Bruising Bruising Bruising Bruising Bruising Bruising Bruising Bruising', 'Severe bruising around the leg area due to the impact of the accident Severe bruising around the leg area due to the impact of the accident Severe bruising around the leg area due to the impact of the accident Severe bruising around the leg area due to the impact of the accident']
];

// Calculate responsive widths for Diagnosis table
$defaultWidthsDiagnosis = [70, 120]; // Default width proportions
$diagnosisWidths = $pdf->CalculateMaxWidths($diagnosisData, $defaultWidthsDiagnosis);

// Diagnosis Table
$pdf->SectionHeader('Diagnosis');
$pdf->DiagnosisTableHeader($diagnosisWidths);
foreach ($diagnosisData as $row) {
    $pdf->DiagnosisTableRow($row[0], $row[1], $diagnosisWidths);
}

// Prescription Table Data
$prescriptionData = [
    ['Ibuprofen', '200mg', 'Take twice a day', true],
    ['Amoxicillin', '500mg', 'Take three times a day', false],
    ['Paracetamol', '500mg', 'Take as needed for pain, this is a very long explanation to test multi-line functionality', true]
];

// Calculate responsive widths for Prescription table
$defaultWidthsPrescription = [60, 40, 50, 30]; // Default width proportions
$prescriptionWidths = $pdf->CalculateMaxWidths($prescriptionData, $defaultWidthsPrescription);

// Prescription Table
$pdf->SectionHeader('Prescriptions');
$pdf->PrescriptionTableHeader($prescriptionWidths);
foreach ($prescriptionData as $row) {
    $pdf->PrescriptionTableRow($row[0], $row[1], $row[2], $row[3], $prescriptionWidths);
}

// Doctor's Explanation
$pdf->SectionHeader('Doctor\'s Explanation');
$pdf->MultiCellWrapped(190, 10, 'The patient has sustained multiple injuries from the accident. Treatment will continue for a period of six weeks and further diagnostics may be required to ensure a complete recovery.');

// Output the PDF
$pdf->Output();
?>

关键修改说明

1. 复选框对齐修复

  • 调整复选框的Y坐标,通过($cellHeight - 5) / 2计算偏移量,让复选框在单元格内垂直居中
  • 使用Text()方法精准绘制选中标记,避免Cell()导致的布局偏移
  • 统一单元格高度为8,与左侧"Title:"单元格保持一致,确保基线对齐

2. 表格自适应与长文本处理

  • 把表格行的Cell()替换为MultiCell(),自动处理长文本换行
  • 改进CalculateMaxWidths函数:
    • 跳过布尔值字段(如处方的可用性)的宽度计算
    • 增加内边距避免文本紧贴边框
    • 若列宽总和超过页面宽度,按比例缩放所有列宽,确保表格不会溢出页面
  • 记录每列的高度,取最大值作为行高,保证多行内容后下一行表格对齐

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 11:52:02