lxOutline 单元为行和列分级显示提供与引擎无关的几何结构和变更计划
它只存储已具体化的区段,通过相邻的分级显示级别转换识别汇总节点,并为汇总在后与汇总在前两种布局创建压缩的状态变更,而无需为每个工作表坐标分配条目
核心类型
TXLSOutlineAxis = (xoaRows, xoaColumns);
TXLSOutlineChildMode = (xocPreserve, xocCollapse, xocExpand);
TXLSOutlineMutationPlan = class
constructor Create(AAxis: TXLSOutlineAxis);
procedure Clear;
property Axis: TXLSOutlineAxis;
property Count: Integer;
property Changes[Index: Integer]: TXLSOutlineStateChange;
end;
TXLSOutlineGeometry = class
constructor Create(AAxis: TXLSOutlineAxis;
ASummaryAfter: Boolean);
procedure Clear;
property Axis: TXLSOutlineAxis;
property SpanCount: Integer;
procedure AddSpan(AFirstIndex, ALastIndex, ALevel: Integer;
AHidden, ACollapsed: Boolean);
function TryGetNode(ANodeIndex: Integer;
out ANode: TXLSOutlineNode): Boolean;
function TryBuildNodeCollapsePlan(ANodeIndex: Integer;
ACollapsed: Boolean; AChildMode: TXLSOutlineChildMode;
APlan: TXLSOutlineMutationPlan): Boolean;
procedure BuildDisplayLevelPlan(ADisplayLevel: Integer;
AChildMode: TXLSOutlineChildMode;
APlan: TXLSOutlineMutationPlan);
end;
行和列索引从 1 开始,分级显示级别为非负数,区段必须以严格递增且互不重叠的顺序添加
级别、隐藏和折叠状态完全相同的相邻区段会自动合并;被省略的索引隐含级别为零、可见状态,并且没有折叠标记
两个类都会记住构造时的 Axis,Clear 清空计划或几何结构以便重用而不重新分配内部缓冲区,SpanCount 报告几何结构当前持有的合并后区段数量
节点语义
| NodeIndex | 调用方查询的物理汇总行或列 |
| FirstDetailIndex / LastDetailIndex | 级别比汇总项更深的连续明细范围 |
| SummaryLevel | 存储在汇总项上的分级显示级别,当该项未具体化时为零 |
| Level | 节点表示的组级别,等于 SummaryLevel + 1 |
| SummaryHidden | 存储在汇总项上的隐藏状态 |
| Collapsed | 存储在汇总项上的显式折叠标记 |
| SummaryAfter | 明细位于汇总项之前时为 True,明细跟随其后时为 false |
嵌套组保持相互独立,因为每次查询都会在第一个级别不比所选汇总项更深的相邻区段处停止
间隙同样会终止明细范围,因此稀疏元数据不会意外地把未使用的坐标桥接进同一个组
变更计划
变更计划包含有序的从 1 开始的范围和一个字段掩码,用于指示每个范围改变的是隐藏状态、折叠状态还是两者;相邻的等价变更会自动合并
| xocPreserve | 更改所选节点,同时保留后代的折叠标记,这是默认的嵌套组行为 |
| xocCollapse | 当后代节点位于所选节点内部或隐藏在所请求显示级别之下时,把它们标记为折叠 |
| xocExpand | 当后代节点位于所选节点内部或隐藏在所请求显示级别之下时,清除它们的折叠标记 |
使用 xocPreserve 展开父级会显示直接明细,而属于已折叠子级的明细保持隐藏;在已折叠的祖先内部展开子级不会通过该祖先暴露内容
显示级别从 1 开始:级别 1 折叠所有顶层组,每个更高的值会多显示一个分级显示级别,同时设置对应的边界节点标记
从已经包含所请求状态的几何结构构建相同状态会产生空计划,查询非节点时返回 false 和空计划
节点操作不会改变所选汇总项的独立隐藏状态,显示级别计划也不会取消隐藏在分级显示组之外被隐藏的零级别项
工作表适配器
function TryGetOutlineNode(AAxis: TXLSOutlineAxis;
ANodeIndex: Integer; out ANode: TXLSOutlineNode): Boolean;
function SetOutlineNodeCollapsed(AAxis: TXLSOutlineAxis;
ANodeIndex: Integer; ACollapsed: Boolean;
AChildMode: TXLSOutlineChildMode = xocPreserve): Boolean;
procedure SetOutlineDisplayLevel(AAxis: TXLSOutlineAxis;
ADisplayLevel: Integer;
AChildMode: TXLSOutlineChildMode = xocPreserve);
TXLSWorksheet 和 TXLSXWorksheet 公开相同的三种方法,调用方无需手动构建几何结构即可查询或更改从 1 开始的行或列汇总节点
经典适配器只读取已分配的行块和已赋值的列元数据,而 XLSX 适配器会合并其稀疏的分级显示级别、隐藏和折叠列表,然后在单个写入事务中应用一个压缩的变更计划
OpenDocument 的行组和列组保留其原生的嵌套 table:display 状态;直接的元数据编辑和结构性的行或列更改会把该状态安全地投影到逻辑汇总节点上,转换为 XLSX 时会把折叠标记写在 XLSX 汇总项上,而不是每个组成员上
现有的 TXLSXWorksheet.ToggleRowGrouped 和 ToggleColGrouped 方法仍作为兼容包装器提供;它们的参数是第一个明细行或列,包装器会在切换之前解析感知方向的汇总节点
Delphi 示例
Geometry := TXLSOutlineGeometry.Create(xoaRows, True);
Plan := TXLSOutlineMutationPlan.Create(xoaRows);
try
Geometry.AddSpan(2, 4, 1, False, False);
Geometry.AddSpan(5, 5, 0, False, False);
if Geometry.TryGetNode(5, Node) then
UseOutlineNode(Node.FirstDetailIndex,
Node.LastDetailIndex, Node.Collapsed);
if Geometry.TryBuildNodeCollapsePlan(5, True,
xocPreserve, Plan) then
ApplyOutlineChanges(Plan);
finally
Plan.Free;
Geometry.Free;
end;
C++Builder 示例
Lxoutline::TXLSOutlineGeometry *geometry =
new Lxoutline::TXLSOutlineGeometry(Lxoutline::xoaColumns, false);
try {
geometry->AddSpan(3, 3, 0, false, true);
geometry->AddSpan(4, 7, 1, true, false);
Lxoutline::TXLSOutlineNode node;
if (geometry->TryGetNode(3, node))
UseOutlineNode(node.FirstDetailIndex, node.LastDetailIndex,
node.Collapsed);
}
__finally {
delete geometry;
}
性能与范围
节点查找使用一次二分查找,之后只处理所选组跨越的相邻已具体化区段,对于 n 个区段和 k 个被访问区段,工作量为 O(log n + k)
批量变更计划通过一次线性的单调栈扫描发现每个已具体化的节点,合并折叠可见性区间,并发出压缩的范围变更,而不访问未使用的坐标
构建器接受最后一个 XLSX 工作表行,同时只保留提供的区段,因此高坐标并不意味着百万条目的分配或扫描
工作表适配器回归门槛在第 8 行和第 1,048,576 行附近对六个已具体化的行条目运行相同的 32,768 次节点查询和 2,048 次折叠或展开变更,要求零单元格具体化,并以低坐标基线为高坐标成本设定界限
TXLSOutlineGeometry 从不直接写入工作簿数据;引擎适配器负责验证并应用返回的计划,使几何结构分析和状态变更保持分离
另请参阅