
一份典型的项目计划表,往往包含阶段名称、每个阶段下的若干任务,以及任务对应的负责人和工期。平铺展开时,读者要在几十行里自己找层次;而在汇报场景下,我们更希望先看到"有哪些阶段",需要时再展开某个阶段看细节。Excel 的分级显示(outline)就是为此设计的:被分组的行会在左侧出现加减号,左上角出现 1、2、3 层级按钮,点一下就能折叠或展开。
问题是,手工分组需要先框选行、再点"数据 → 创建组",层级一多就容易漏选,换一份文件还得重来。用 Python 可以把分组结构写进脚本,批量套用到结构相同的报表上。本文介绍用 Spire.XLS for Python 创建工作表分组、控制展开折叠状态以及取消分组的方法。
为什么用脚本做分组
- 层级由代码定义:哪几行属于哪个层级写在参数里,不需要反复框选。
- 批量一致:同一套分组规则可以套用到多份结构相同的计划表或月报。
- 状态可控:创建工作簿时就能决定哪些组默认折叠,打开文件即是最终视图。
环境准备
安装 Spire.XLS:
bash
pip install Spire.XLS
在脚本中导入需要的模块:
python
from spire.xls import *
from spire.xls.common import *
分组与分级显示的工作机制
分组通过工作表的 GroupByRows() 与 GroupByColumns() 完成,签名为:
text
GroupByRows(startRow, endRow, isCollapsed)
GroupByColumns(startColumn, endColumn, isCollapsed)
前两个参数是行号或列号的区间(从 1 开始,包含首尾),第三个参数决定创建后是否立即折叠。每调用一次,被选中的行或列就归入一个新的分级层级;对已在组内的行再次调用,就会在其内部生成下一级,由此形成嵌套。
按行分组
下面的例子把第 1 到第 5 行归为一组:
python
from spire.xls import *
from spire.xls.common import *
workbook = Workbook()
workbook.LoadFromFile("GroupRowsAndColumns.xls")
sheet = workbook.Worksheets[0]
# 将第 1 至 5 行分为一组,创建后保持展开
sheet.GroupByRows(1, 5, False)
workbook.SaveToFile("GroupRows.xlsx", ExcelVersion.Version2010)
workbook.Dispose()
保存后用 Excel 打开,工作表左侧会出现分级显示区域,第 1 至 5 行旁显示减号,点击即可收起。第三个参数传 False 表示创建后保持展开,传 True 则文件打开时该组已处于折叠状态。
创建多级嵌套分组
真实报表通常不止两级。下面的例子新建一份项目计划,把所有任务行归入一级组,再把两个阶段各自的任务归入二级组:
python
from spire.xls import *
from spire.xls.common import *
workbook = Workbook()
sheet = workbook.Worksheets[0]
# 定义标题样式
style = workbook.Styles.Add("style")
style.Font.Color = Color.get_CadetBlue()
style.Font.IsBold = True
# 让汇总行显示在明细上方
sheet.PageSetup.IsSummaryRowBelow = False
# 写入阶段与任务
sheet.Range["A1"].Value = "Project plan for project X"
sheet.Range["A1"].CellStyleName = style.Name
sheet.Range["A3"].Value = "Set up"
sheet.Range["A3"].CellStyleName = style.Name
sheet.Range["A4"].Value = "Task 1"
sheet.Range["A5"].Value = "Task 2"
sheet.Range["A4:A5"].BorderAround(LineStyleType.Thin)
sheet.Range["A4:A5"].BorderInside(LineStyleType.Thin)
sheet.Range["A7"].Value = "Launch"
sheet.Range["A7"].CellStyleName = style.Name
sheet.Range["A8"].Value = "Task 1"
sheet.Range["A9"].Value = "Task 2"
sheet.Range["A8:A9"].BorderAround(LineStyleType.Thin)
sheet.Range["A8:A9"].BorderInside(LineStyleType.Thin)
# 先建外层组,再在其内部建子组
sheet.GroupByRows(2, 9, False) # 一级:第 2 至 9 行
sheet.GroupByRows(4, 5, False) # 二级:"Set up" 的两个任务
sheet.GroupByRows(8, 9, False) # 二级:"Launch" 的两个任务
workbook.SaveToFile("CreateNestedGroup.xlsx", ExcelVersion.Version2013)
workbook.Dispose()
关键在于调用顺序:必须先建外层组(第 2 至 9 行),再建子组(第 4 至 5 行、第 8 至 9 行),由宽到窄最不容易出错。保存后工作表左上角会出现 1 2 两个层级按钮:点 1 只保留两个阶段名,点 2 展开到任务级。
sheet.PageSetup.IsSummaryRowBelow = False 的作用是把汇总行放在明细行上方------Excel 默认认为汇总行在明细下方,而阶段名通常写在任务之前,所以这里要显式改成 False。
按列分组
列分组与行分组完全对称,用于把宽表中相邻的明细列收起来:
python
from spire.xls import *
from spire.xls.common import *
workbook = Workbook()
workbook.LoadFromFile("GroupRowsAndColumns.xls")
sheet = workbook.Worksheets[0]
# 将第 1 至 3 列分为一组
sheet.GroupByColumns(1, 3, False)
workbook.SaveToFile("GroupColumns.xlsx", ExcelVersion.Version2010)
workbook.Dispose()
保存后列标题上方会出现分级显示区域,与行分组互不干扰,因此同一张表可以同时做行、列两种分组。
展开与折叠已有的分组
如果分组已经存在于文件中,可以通过区域对象控制其状态,而不需要重新分组:
python
from spire.xls import *
from spire.xls.common import *
workbook = Workbook()
workbook.LoadFromFile("Template_Xls_3.xlsx")
sheet = workbook.Worksheets[0]
# 展开第 16 至 19 行,并同时展开其所属的上级组
sheet.Range["A16:G19"].ExpandGroup(GroupByType.ByRows, ExpandCollapseFlags.ExpandParent)
# 折叠第 10 至 12 行
sheet.Range["A10:G12"].CollapseGroup(GroupByType.ByRows)
workbook.SaveToFile("ExpandAndCollapseGroups.xlsx", ExcelVersion.Version2013)
workbook.Dispose()
CollapseGroup() 与 ExpandGroup() 都作用于一个单元格区域,第二个参数 GroupByType.ByRows 指明按行处理(按列时用 GroupByType.ByColumns)。ExpandGroup() 还可接收第三个参数 ExpandCollapseFlags.ExpandParent:目标组嵌在更深层级时,只展开它本身仍会被外层折叠状态遮住,加上这个标志会连同上级组一起展开。
取消分组
不再需要的分组可以用 UngroupByRows() 移除,参数为行号区间:
python
from spire.xls import *
from spire.xls.common import *
workbook = Workbook()
workbook.LoadFromFile("Template_Xls_3.xlsx")
sheet = workbook.Worksheets[0]
# 取消第 10 至 12 行的分组
sheet.UngroupByRows(10, 12)
# 取消第 16 至 19 行的分组
sheet.UngroupByRows(16, 19)
workbook.SaveToFile("UngroupExcelCells.xlsx", ExcelVersion.Version2013)
workbook.Dispose()
取消分组只删除分级显示结构,单元格内容、样式和数值都不会受影响。
实用建议
- 先外后内:嵌套分组按行区间从大到小依次调用,层级关系最清晰。
- 行号从 1 开始:区间使用 Excel 行号并包含首尾,与 Python 列表的 0 起始索引不同。
- 折叠状态会被保存 :第三个参数决定文件打开时的初始视图,希望读者先看到折叠结构时传
True。 - 汇总行位置要显式设置 :阶段名在任务上方时,记得把
PageSetup.IsSummaryRowBelow设为False。 - 释放资源 :处理完一个工作簿后调用
workbook.Dispose()。
结语
本文介绍了使用 Python 在 Excel 中创建分组与分级显示的方法:用 GroupByRows() 和 GroupByColumns() 建立行、列分组及嵌套层级,通过 CollapseGroup()、ExpandGroup() 控制展开折叠状态(必要时配合 ExpandCollapseFlags.ExpandParent),用 PageSetup.IsSummaryRowBelow 调整汇总行位置,以及用 UngroupByRows() 移除分组。由于分组只影响视图而不改变数据,同一套代码可以在不触碰原始内容的前提下,把平铺的明细表整理成可折叠的层次结构。