
把一张宽表导出成 PDF 或送去打印时,Excel 会按纸张尺寸自动分页。默认的换行位置由列宽、字号和纸张决定,一旦某个单元格的高度挤在边界上,一行数据就可能被切成上下两半,标题行也不会在第二页重复。
分页符(Page Break)提供了一种确定性的做法:在指定的行或列之前强制断开页面,让每一页的边界完全由脚本决定。水平分页符负责按行切分,垂直分页符负责按列切分,两者可以组合使用。本文用 Spire.XLS for Python 演示分页符的添加、读取、移除,并说明如何把它和打印区域、重复标题行等打印设置配合起来。
环境准备
安装 Spire.XLS 并引入模块:
bash
pip install Spire.XLS
python
from spire.xls import *
from spire.xls.common import *
分页符挂在工作表对象上:sheet.HPageBreaks 是水平分页符集合,sheet.VPageBreaks 是垂直分页符集合,两者提供的方法完全一致。
添加水平分页符
水平分页符决定"从哪一行开始另起一页"。下面的示例生成一张 30 行的数据表,并在第 11 行和第 21 行之前各插入一个分页符:
python
from spire.xls import *
from spire.xls.common import *
workbook = Workbook()
workbook.CreateEmptySheets(1)
sheet = workbook.Worksheets[0]
for r in range(1, 31):
sheet.Range[r, 1].Text = f"Region {r}"
sheet.Range[r, 2].Text = f"2026-{((r - 1) % 12) + 1:02d}"
sheet.Range[r, 3].NumberValue = (r * 37) % 500
# Break before row 11 and before row 21.
sheet.HPageBreaks.Add(sheet.Range["A11"])
sheet.HPageBreaks.Add(sheet.Range["A21"])
# Keep the file in the normal view; the preview is only for checking the layout.
sheet.ViewMode = ViewMode.Normal
print("count:", sheet.HPageBreaks.Count)
print("manual count:", sheet.HPageBreaks.ManualBreakCount)
print("first break row:", sheet.HPageBreaks.get_Item(0).Row)
workbook.SaveToFile("PageBreaksHorizontal.xlsx", ExcelVersion.Version2013)
workbook.Dispose()
这里有两个容易忽略的细节。
其一,Add() 接收的是一个单元格区域,真正起作用的是它的行 :Range["A11"] 表示在第 11 行之前断页,也就是第 11 行成为新一页的第一行。
其二,分页符在文件里记录的是一个 0 起始的行号,所以 get_Item(0).Row 返回的是 10 而不是 11------读到的索引比插入时指定的行号小 1。Count 是分页符总数,ManualBreakCount 只统计脚本或用户手动插入的分页符,两者可能不同,因为 Excel 自己也会根据纸张尺寸插入自动分页符。
添加垂直分页符
垂直分页符决定"从哪一列开始另起一页",用法与水平分页符完全对称,只是起作用的是列:
python
from spire.xls import *
from spire.xls.common import *
workbook = Workbook()
workbook.CreateEmptySheets(1)
sheet = workbook.Worksheets[0]
for r in range(1, 31):
sheet.Range[r, 1].Text = f"Region {r}"
sheet.Range[r, 2].Text = f"2026-{((r - 1) % 12) + 1:02d}"
sheet.Range[r, 3].NumberValue = (r * 37) % 500
# Rows 11 and 21 start a new printed page.
sheet.HPageBreaks.Add(sheet.Range["A11"])
sheet.HPageBreaks.Add(sheet.Range["A21"])
# Columns C and E start a new printed page.
sheet.VPageBreaks.Add(sheet.Range["C1"])
sheet.VPageBreaks.Add(sheet.Range["E1"])
print("horizontal:", sheet.HPageBreaks.Count, "vertical:", sheet.VPageBreaks.Count)
sheet.ViewMode = ViewMode.Normal
workbook.SaveToFile("PageBreaksBoth.xlsx", ExcelVersion.Version2013)
workbook.Dispose()
写传参时把行列分清楚:水平分页符传 "A11",表示第 11 行;垂直分页符传 "C1",表示 C 列。传错会让分页符落在意料之外的位置上。
移除分页符
移除有两个粒度:RemoveAt(index) 删掉指定位置的一个分页符,Clear() 清空整个集合:
python
from spire.xls import *
workbook = Workbook()
workbook.LoadFromFile("PageBreaksBoth.xlsx")
sheet = workbook.Worksheets[0]
print("before -> horizontal:", sheet.HPageBreaks.Count, "vertical:", sheet.VPageBreaks.Count)
# Remove the first horizontal break by index.
sheet.HPageBreaks.RemoveAt(0)
print("after RemoveAt ->", sheet.HPageBreaks.Count)
# Remove every vertical break at once.
sheet.VPageBreaks.Clear()
print("after -> horizontal:", sheet.HPageBreaks.Count, "vertical:", sheet.VPageBreaks.Count)
workbook.SaveToFile("PageBreaksRemoved.xlsx", ExcelVersion.Version2013)
workbook.Dispose()
移除第一个水平分页符后,另一个分页符仍然留在原位,位置不受影响;Clear() 之后垂直分页符数量归零,而水平分页符不受影响------两个集合彼此独立。
需要重建一套分页规则时,先 Clear() 再按新规则 Add(),比逐个 RemoveAt() 更省事,也不容易漏删。
用分页预览检查排版
分页符的效果只在分页视图里才看得见。把视图模式切到 ViewMode.Preview,文件打开后就直接进入分页预览,可以直接确认每页切在哪里:
python
from spire.xls import *
from spire.xls.common import *
workbook = Workbook()
workbook.LoadFromFile("PageBreaksBoth.xlsx")
sheet = workbook.Worksheets[0]
# Open the file in page-break preview so the breaks are visible.
sheet.ViewMode = ViewMode.Preview
sheet.ZoomScalePageBreakView = 80
print("view mode is preview:", sheet.ViewMode == ViewMode.Preview)
workbook.SaveToFile("PageBreakPreview.xlsx", ExcelVersion.Version2013)
workbook.Dispose()
ZoomScalePageBreakView 设置预览视图的缩放比例,默认值偏小,页面多的时候看起来费劲,调到 80 左右比较合适。
与打印设置配合
分页符解决"在哪里断开",打印设置解决"每页印什么"。两者通常要一起写:
python
from spire.xls import *
from spire.xls.common import *
workbook = Workbook()
workbook.LoadFromFile("PageBreaksBoth.xlsx")
sheet = workbook.Worksheets[0]
pageSetup = sheet.PageSetup
# Only print A1:C30.
pageSetup.PrintArea = "A1:C30"
# Repeat the first row at the top of every page.
pageSetup.PrintTitleRows = "$1:$1"
# A4 paper in landscape orientation.
pageSetup.PaperSize = PaperSizeType.PaperA4
pageSetup.Orientation = PageOrientationType.Landscape
# Fit the width to one page, keep the height automatic.
pageSetup.FitToPagesWide = 1
pageSetup.FitToPagesTall = 0
sheet.ViewMode = ViewMode.Preview
sheet.ZoomScalePageBreakView = 80
workbook.SaveToFile("PageBreakPrintSetup.xlsx", ExcelVersion.Version2013)
workbook.Dispose()
几个需要留意的组合:
- 打印区域决定分页符的生效范围 。
PrintArea之外的列不会进入打印,分页符设在打印区域之外也就没有意义。 - 重复标题行 (
PrintTitleRows)让表头在每一页重新出现,配合按行切分的水平分页符,长表格才不会翻页后失去上下文。 - 缩放设置会盖过分页符的直观效果 。
FitToPagesTall = 1表示把所有内容压进一页,与手动分页符的意图正好相反;如果只希望"宽度缩到一页",就把FitToPagesWide设为 1、FitToPagesTall保持 0。
实用技巧
- 先定数据,再插分页符:分页符记录的是固定行号,数据行数变化后原来的位置就不再对应业务分段,建议按实际行数在脚本里计算插入位置。
- 行列分清:水平分页符传行、垂直分页符传列,传错会让分页落在别处。
- 重建用 Clear + Add :比逐个
RemoveAt()干净,也避免残留旧规则。 - 区分手动与自动分页符 :
Count含自动分页符,ManualBreakCount只统计手动插入的。 - 缩放与分页符一起调试 :
FitToPagesWide、FitToPagesTall改一下,页面边界就会跟着变,改完最好切到分页预览确认一次。 - 及时释放资源 :工作簿用完调用
Dispose()。
结论
分页符把"页在哪里断开"从 Excel 的自动计算变成脚本的明确规则:HPageBreaks.Add() 和 VPageBreaks.Add() 分别按行和按列插入分页符,Count、ManualBreakCount 与 get_Item(i).Row 用来读取现状,RemoveAt() 与 Clear() 负责清理,ViewMode.Preview 与 ZoomScalePageBreakView 让结果可以直接在文件里核对。
把分页符与 PrintArea、PrintTitleRows、PaperSize、Orientation、FitToPagesWide 这些打印设置组合起来,脚本就能稳定地产出符合要求的打印稿或 PDF------每一页从哪里开始、印哪些列、表头是否重复,全部由代码决定。