明细表超过二三十行后,读者往往只关心每组的第一行。月度报表按部门收起明细、项目计划按阶段折叠任务、宽表把中间几列临时藏起来,本质都是在工作表上加一层分级显示:左侧或上方出现层级按钮,点一下把一组行或列折叠成一行,再点一次展开。Excel 里这对应「组合」功能,落到代码上就是 GroupByRows 与 GroupByColumns 两个方法,再配合 CollapseGroup / ExpandGroup 控制初始状态。
本文使用 Free Spire.XLS for Python,安装命令:
- pip install Spire.XLS.Free
复制代码
需要先弄清对象模型。分组挂在 Worksheet 上,按行或按列成组;每组的折叠状态由区域方法与 GroupByType 决定;汇总行的位置在 PageSetup 上。具体分工是:Workbook 是工作簿容器,提供 Worksheets 与 SaveToFile;Worksheet 是行分组和列分组的入口;CellRange 代表参与分组的区域,提供 CollapseGroup、ExpandGroup、RowGroupLevel 等成员;PageSetup 负责打印与大纲设置,其中 IsSummaryRowBelow 决定折叠标记的朝向。
GroupByRows(start, end, collapsed) 的三个参数依次是起始行、结束行和「建组时是否折叠」。这里的行号是工作表上的真实行号,从 1 起算,与按区域内偏移计数的参数不同。RowGroupLevel 用于读回某行所属层级,未参与分组的行返回 0。
一、基础行分组:把明细收进一组
给连续行建组后,左侧会出现分级条与折叠按钮,左上角显示层级按钮 1、2:
- from spire.xls import *
- from spire.xls.common import *
- workbook = Workbook()
- workbook.CreateEmptySheets(1)
- sheet = workbook.Worksheets[0]
- rows = [
- ["阶段", "任务", "工时"],
- ["阶段一", "需求梳理", 12],
- ["阶段一", "接口设计", 18],
- ["阶段一", "页面开发", 26],
- ["阶段二", "联调测试", 20],
- ["阶段二", "性能验证", 14],
- ["阶段二", "上线准备", 9],
- ]
- for r, row in enumerate(rows, start=1):
- for c, value in enumerate(row, start=1):
- cell = sheet.Range[r, c]
- if isinstance(value, str):
- cell.Text = value
- else:
- cell.NumberValue = value
- sheet.GroupByRows(2, 4, False)
- sheet.GroupByRows(5, 7, False)
- workbook.SaveToFile("grouped.xlsx", ExcelVersion.Version2016)
- workbook.Dispose()
复制代码
两个组分别覆盖第 2–4 行与第 5–7 行,第三个参数为 False,建组后保持展开。表头留在第 1 行且不参与分组,因此它的 RowGroupLevel 为 0。
二、建组时就收起
把第三个参数改成 True,建组的同时收起明细,只留一行占位。沿用上面的数据填充代码,只替换末尾的分组调用:
- sheet.GroupByRows(2, 4, True)
- sheet.GroupByRows(5, 7, False)
复制代码
第一组收起后,行号从 1 直接跳到 5,折叠位置留一个加号按钮;第二组仍展开。整张表只剩四行可见,点开加号后明细回到原位。行号跳过的位置就是被隐藏的行,数据本身没有被删除。
三、多级嵌套:先外层,再内层
先给大范围建组,再给其中的子范围建组,层级会依次加深:外层为第 1 级,内层为第 2 级,左上角的层级按钮随之变成 1、2、3。
- sheet.GroupByRows(2, 7, False)
- sheet.GroupByRows(2, 4, False)
- sheet.GroupByRows(5, 7, False)
复制代码
此时第 2–7 行读回的 RowGroupLevel 为 2,外层对应 1。最深层级为 2 时,左上角出现 1、2、3 三个按钮,按级别控制展开深度;分组越深,按钮越多。
四、统一收起与展开
建好的组可以随时折叠或展开。CollapseGroup 与 ExpandGroup 按区域操作,用 GroupByType.ByRows 指明方向:
- sheet.GroupByRows(2, 7, False)
- sheet.GroupByRows(2, 4, False)
- sheet.GroupByRows(5, 7, False)
- sheet.Range["A2:C7"].CollapseGroup(GroupByType.ByRows)
复制代码
收起后整段明细隐去,只留第 1 行与折叠位置的一个加号;ExpandGroup 是反向操作,把该层重新打开,展开子组时可用 ExpandCollapseFlags.ExpandParent 一并展开外层。这两个方法作用于该范围所在的层级:折叠内层时外层随之收起,展开时同一层的分组一起打开。如果想让某一组展开、另一组收起,状态应在建组时就定下来——GroupByRows 的第三个参数按组分别取值。批量报表里常见的做法是建组时全部收起,再按当期数据把需要看的那一层展开。
五、汇总行位置决定按钮落在哪一端
大纲的折叠按钮默认落在明细的下方。把 PageSetup.IsSummaryRowBelow 设为 False 后,折叠标记移到组的上方,适合「小计在上、明细在下」的报表:
- sheet.GroupByRows(2, 7, False)
- sheet.PageSetup.IsSummaryRowBelow = False
复制代码
这里改的是大纲的汇总方向,不是数据顺序:行的先后不变,只是折叠按钮从组的下沿移到上沿,层级按钮 1、2 仍留在左上角。
六、列分组:把中间的列收起来
列方向用法相同,入口换成 GroupByColumns,分级条出现在列标上方:
- rows = [
- ["阶段", "任务", "工时", "备注"],
- ["阶段一", "需求梳理", 12, "常规"],
- ["阶段一", "接口设计", 18, "常规"],
- ["阶段一", "页面开发", 26, "加急"],
- ["阶段二", "联调测试", 20, "常规"],
- ["阶段二", "性能验证", 14, "加急"],
- ["阶段二", "上线准备", 9, "常规"],
- ]
- for r, row in enumerate(rows, start=1):
- for c, value in enumerate(row, start=1):
- cell = sheet.Range[r, c]
- if isinstance(value, str):
- cell.Text = value
- else:
- cell.NumberValue = value
- sheet.GroupByColumns(2, 3, False)
复制代码
第 2–3 列成组后,列标上方多出一条横向分级条,折叠时这两列收起,阶段与备注仍并排显示。列分组同样支持嵌套与折叠状态,第三个参数的语义与行分组一致。
七、API 速查
核心类:Workbook 是工作簿对象,提供工作表集合;Worksheet 是工作表,行分组与列分组的入口;CellRange 是区域,用于折叠、展开与读取层级;PageSetup 负责页面与大纲设置。
常用方法与属性:Worksheet.GroupByRows(start, end, collapsed) 对第 start 至 end 行建组;Worksheet.GroupByColumns(start, end, collapsed) 对第 start 至 end 列建组;CellRange.CollapseGroup(GroupByType.ByRows) 收起区域所在的组;CellRange.ExpandGroup(GroupByType.ByRows, flags) 展开区域所在的组;CellRange.RowGroupLevel 返回该行所属层级,未分组为 0;CellRange.ColumnGroupLevel 返回该列所属层级;CellRange.IsGroupedByRow 判断该行是否参与分组;PageSetup.IsSummaryRowBelow 指定汇总行是否在明细下方。
枚举与常量:GroupByType.ByRows 按行方向操作;GroupByType.ByColumns 按列方向操作;ExpandCollapseFlags.ExpandParent 展开子组时一并展开外层。
八、小结与注意点
分组由两类参数决定:给哪一段行或列建组,以及建组时收不收。行号与列号都是工作表上的真实位置,从 1 起算;先建外层再建内层,RowGroupLevel 就逐级加深,层级按钮的数量随之增加。建组之后的状态可以用 CollapseGroup 与 ExpandGroup 按层级调整,IsSummaryRowBelow 决定折叠标记落在组的上沿还是下沿。
分组只改变显示层级,不删除也不移动单元格:折叠时行号跳过的位置仍是原来的数据,展开后回到原位。需要整表一次性收起或展开时,遍历各组对应的区域逐个调用即可。上述行为在保存为 ExcelVersion.Version2016 格式后,用 Excel 打开即可看到左侧或上方的分级条与层级按钮。 |