Pivottabells-API
HotXLS stödjer typad granskning, upphov och materialisering av pivottabellsresultat för XLS- och XLSX-arbetsböcker. Relationsdriven XLSX-inläsning löser upp godtyckliga paketdelnamn och återställer cacheposter, delade objekt, fältmetadata, filter, gruppering, beräknade definitioner, format och tillägg i den publika modellen. Klassiska XLS-källor behåller sina ursprungliga pivotposter för trogna spar-roundtrips
Roundtrip och typad modell
När en klassisk arbetsbok redan innehåller pivottabeller bevarar läsaren de råa BIFF-posterna och exponerar samtidigt en typad modell. Tabeller och cacheposter som lästs från en klassisk fil behåller FromRawBlobs = True, så att sparutdata spelar upp originalbytena för trohet. XLSX-pivoter läses in och sparas via sina ägande paketrelationer, medan programmatiskt skapade pivoter använder den typade skrivaren
const
xlPivotBaseItemPrevious = $7FFB;
xlPivotBaseItemNext = $7FFC;
type
TXLSPivotFieldAxis = (xlpfaNone, xlpfaRowField, xlpfaColumnField, xlpfaPageField, xlpfaDataField);
TXLSPivotAggregation = (xlpaSum, xlpaCount, xlpaAverage, xlpaMax, xlpaMin, xlpaProduct, xlpaCountNums, xlpaStdDev, xlpaStdDevP, xlpaVar, xlpaVarP);
TXLSPivotShowDataAs = (xlpsdaNormal, xlpsdaDifference, xlpsdaPercent, xlpsdaPercentDiff, xlpsdaRunTotal, xlpsdaPercentOfRow, xlpsdaPercentOfCol, xlpsdaPercentOfTotal, xlpsdaIndex);
TXLSPivotExtendedShowDataAs = (xlpesdaNone, xlpesdaPercentOfParent, xlpesdaPercentOfParentRow, xlpesdaPercentOfParentColumn, xlpesdaPercentOfRunningTotal, xlpesdaRankAscending, xlpesdaRankDescending);
TXLSPivotSubtotal = (xlpsDefault, xlpsSum, xlpsCount, xlpsAverage, xlpsMax, xlpsMin, xlpsProduct, xlpsCountNums, xlpsStdDev, xlpsStdDevP, xlpsVar, xlpsVarP);
TXLSPivotSubtotals = set of TXLSPivotSubtotal;
TXLSPivotDesignerZone = (xlpdzAvailable, xlpdzRows, xlpdzColumns, xlpdzFilters, xlpdzValues);
TXLSPivotCacheValue = record
ValueType: TXLSPivotCacheFieldType;
end;
TXLSPivotCacheField = class
property Name: WideString;
property FieldType: TXLSPivotCacheFieldType;
property ItemCount: Integer;
property Items[Index: Integer]: TXLSPivotCacheItem;
end;
TXLSPivotCache = class
property CacheId: Integer;
property SourceRangeSheet: WideString;
property SourceFirstRow: Integer;
property SourceFirstCol: Integer;
property SourceLastRow: Integer;
property SourceLastCol: Integer;
property RecordCount: Integer;
property FieldCount: Integer;
property Fields[Index: Integer]: TXLSPivotCacheField;
property RecordIndices[RecordIdx, FieldIdx: Integer]: Integer;
property FromRawBlobs: Boolean;
end;
TXLSPivotCaches = class
function Add: TXLSPivotCache;
function FindByCacheId(ACacheId: Integer): TXLSPivotCache;
property Count: Integer;
property Items[Index: Integer]: TXLSPivotCache;
end;
TXLSPivotField = class
function AddItem: TXLSPivotItem;
function AddCalculatedItem(const AName, AFormula: WideString): TXLSPivotCalculatedItem;
property Name: WideString;
property Axis: TXLSPivotFieldAxis;
property CacheFieldIndex: Integer;
property ItemCount: Integer;
property Items[Index: Integer]: TXLSPivotItem;
property SubtotalMask: Word;
property Subtotals: TXLSPivotSubtotals;
property PageItemIndex: Integer;
property SortType: TXLSPivotFieldSortType;
property SortDataField: Integer;
property Filters: TXLSPivotFilters;
end;
TXLSPivotDataField = class
property Field: TXLSPivotField;
property Aggregation: TXLSPivotAggregation;
property NumberFormat: Word;
property DisplayName: WideString;
property ShowDataAs: TXLSPivotShowDataAs;
property ExtendedShowDataAs: TXLSPivotExtendedShowDataAs;
property BaseField: Integer;
property BaseItem: Integer;
end;
TXLSPivotSupplementalRecord = class
property RecID: Word;
property BodyLength: Integer;
property Body[Index: Integer]: Byte;
end;
TXLSPivotTable = class
function AddField(const AName: WideString; ACacheFieldIndex: Integer): TXLSPivotField;
function FindFieldByName(const AName: WideString): TXLSPivotField;
function SetFieldAxis(const AName: WideString; AAxis: TXLSPivotFieldAxis): TXLSPivotField;
function AddRowField(const AName: WideString): TXLSPivotField;
function AddColumnField(const AName: WideString): TXLSPivotField;
function AddPageField(const AName: WideString): TXLSPivotField;
function AddDataField(AField: TXLSPivotField; AAggregation: TXLSPivotAggregation): TXLSPivotDataField;
function AddDataFieldByName(const AName: WideString; AAggregation: TXLSPivotAggregation = xlpaSum): TXLSPivotDataField;
function AddCalculatedMember(const AName, AFormula: WideString): TXLSPivotCalculatedMember;
function AddSupplementalRecord(ARecID: Word; const ABody: TBytes): TXLSPivotSupplementalRecord;
function Make(AWriter: TlxPivotResultWriter): Integer;
property Name: WideString;
property DataCaption: WideString;
property CacheId: Integer;
property Cache: TXLSPivotCache;
property FieldCount: Integer;
property Fields[Index: Integer]: TXLSPivotField;
property DataFieldCount: Integer;
property DataFields[Index: Integer]: TXLSPivotDataField;
property RowGrandTotals: Boolean;
property ColumnGrandTotals: Boolean;
property MaterializeGrandTotalRow: Boolean;
property MaterializeGrandTotalColumn: Boolean;
property SupplementalRecordCount: Integer;
property SupplementalRecords[Index: Integer]: TXLSPivotSupplementalRecord;
property FromRawBlobs: Boolean;
end;
TXLSPivotDesigner = class
constructor Create(APivotTable: TXLSPivotTable = nil);
procedure ClearLayout;
function MoveField(const AName: WideString; AZone: TXLSPivotDesignerZone; APosition: Integer = -1): Boolean;
function SetAggregation(const AName: WideString; AAggregation: TXLSPivotAggregation): Boolean;
function Validate(out ErrorText: WideString): Boolean;
function Apply(AWriter: TlxPivotResultWriter): Integer;
property PivotTable: TXLSPivotTable;
property FieldCount: Integer;
property Fields[Index: Integer]: TXLSPivotDesignerField;
end;
TXLSPivotTables = class
function Add: TXLSPivotTable;
function FindByName(const AName: WideString): TXLSPivotTable;
property Count: Integer;
property Items[Index: Integer]: TXLSPivotTable;
end;
Startpunkter i kalkylblad och arbetsbok
type
TXLSWorksheet = class
function AddPivotTable(const SourceRangeA1: WideString; DestRow, DestCol: Integer; const Name: WideString): TXLSPivotTable;
function PivotSetDataFieldFormat(DataField: TXLSPivotDataField; const FormatStr: WideString): Word;
property PivotTables: TXLSPivotTables;
end;
TXLSWorkbook = class
property PivotCaches: TXLSPivotCaches;
function RegisterNumFormat(const FormatStr: WideString): Word;
end;
RegisterNumFormat registrerar en talformatsträng och returnerar dess BIFF8-ifmt-index, vilket är vad TXLSPivotDataField.NumberFormat och TXLSPivotCacheField.NumberFormat förväntar sig; registreras samma sträng två gånger returneras samma index
DestRow och DestCol är ettbaserade, precis som Cells[Row, Col], så AddPivotTable('Data!A1:C9', 3, 1, 'SalesPivot') förankrar pivottabellen i cell A3. Även positionerna på TXLSPivotTable (FirstRow .. FirstDataCol) och källområdet på TXLSPivotCache är ettbaserade, precis som i XLSX-motorn; en förankring utanför 65,536 x 256-kalkylbladet returnerar nil
Bygg en dra-och-släpp-layout för pivottabellen
TXLSPivotDesigner är en icke-visuell layoutmodell som kan ligga bakom VCL-, FMX-, webb- eller kommandoradsgränssnitt för fältlistor, utan att koppla pivotlogiken till ett enskilt UI-ramverk
Varje fält redovisar en tillgänglig-, rad-, kolumn-, filter- eller värdezonsplacering plus sin deterministiska position; MoveField genomför ett släpp, SetAggregation ändrar ett värdefält, Validate rapporterar ofullständiga layouter, och Apply validerar och materialiserar resultatet via den normala pivotskrivaren
Nya numeriska och datumbaserade värdefält får xlpaSum som standard, medan text-, Boolean-, fel-, tomma och blandade fält får xlpaCount som standard
var
Designer: TXLSPivotDesigner;
ErrorText: WideString;
begin
Designer := TXLSPivotDesigner.Create(Pivot);
try
Designer.MoveField('Region', xlpdzRows);
Designer.MoveField('Quarter', xlpdzColumns);
Designer.MoveField('Closed', xlpdzFilters);
Designer.MoveField('Revenue', xlpdzValues);
Designer.SetAggregation('Revenue', xlpaAverage);
if Designer.Validate(ErrorText) then
Designer.Apply(ResultWriter.WriteCell);
finally
Designer.Free;
end;
end;
Skapa en pivottabell
uses lxHandle;
var
Workbook: TXLSWorkbook;
SourceSheet, PivotSheet: TXLSWorksheet;
Pivot: TXLSPivotTable;
RowField: TXLSPivotField;
DataField: TXLSPivotDataField;
begin
Workbook := TXLSWorkbook.Create;
try
SourceSheet := Workbook.Sheets[1];
SourceSheet.Name := 'SalesData';
SourceSheet.Cells[1, 1].Value := 'Region';
SourceSheet.Cells[1, 2].Value := 'Product';
SourceSheet.Cells[1, 3].Value := 'Revenue';
PivotSheet := Workbook.Sheets.Add;
PivotSheet.Name := 'PivotReport';
Pivot := PivotSheet.AddPivotTable('SalesData!A1:C20', 4, 1, 'SalesPivot');
RowField := Pivot.AddRowField('Region');
Pivot.AddColumnField('Product');
DataField := Pivot.AddDataFieldByName('Revenue', xlpaSum);
RowField.Subtotals := [xlpsSum];
PivotSheet.PivotSetDataFieldFormat(DataField, '$#,##0.00');
Workbook.SaveAs('pivot-report.xls');
finally
Workbook.Free;
end;
end;
Visa värden som
Sätt ShowDataAs på varje värdefält innan du anropar Make eller sparar arbetsboken. Difference, Percent och PercentDiff kräver ett nollbaserat BaseField-pivotfältindex plus en BaseItem. RunTotal kräver bara BaseField. Rad-, kolumn-, total- och indexlägena härleder sina nämnare från källposterna med den konfigurerade aggregeringen
En uttrycklig BaseItem är ett nollbaserat objektindex inuti baspivotfältet. Använd xlPivotBaseItemPrevious eller xlPivotBaseItemNext för jämförelser med angränsande objekt. Saknade jämförelsesnitt lämnas tomma, medan en befintlig nollnämnare ger #DIV/0!
DataField := Pivot.AddDataFieldByName('Revenue', xlpaSum);
DataField.ShowDataAs := xlpsdaPercentDiff;
DataField.BaseField := 0;
DataField.BaseItem := xlPivotBaseItemPrevious;
CellsWritten := Pivot.Make(ResultWriter.WriteCell);
Filtrering, gruppering och sortering
Make tillämpar dolda objekt och sidourval innan domänen byggs upp, och utvärderar därefter rubrik-, datum-, antal-, procent-, summa- och värdefilter. Numeriska intervall, kalendergrupper och diskreta grupper använder cachefältens grupperingsmetadata före aggregeringen. SortType väljer stabil etikettordning, medan SortDataField väljer det nollbaserade värdefältet för stabil ordning efter datavärden
Beräknade uttryck
Beräknade cachefält körs en gång per källpost, beräknade objekt körs över syskonobjektens aggregat, och beräknade medlemmar med MemberType = 'data' lägger till virtuella värdefält efter källaggregeringen. Formelnamn är skiftlägesokänsliga och får vara hakparenteserade eller citerade. Aritmetik, jämförelser, procent, parenteser och vanliga numeriska och logiska funktioner stöds, med upprepade beroendepass för acykliska beräknade definitioner
ProfitField := Pivot.Cache.AddField('Profit', xlpcftNumber);
ProfitField.Formula := '=Revenue-Cost';
ProfitField.DatabaseField := False;
Pivot.AddDataField(Pivot.AddField('Profit', 4), xlpaSum);
RegionField.AddCalculatedItem('Combined', '=North+South');
Pivot.AddCalculatedMember('Margin', '=Profit/Revenue').MemberType := 'data';
Delsummor och totalsummor
Varje rad- eller kolumnfält kan materialisera vilken som helst av de konfigurerade delsummfunktionerna ovanför eller under sina detaljobjekt via Subtotals och SubtotalTop. RowGrandTotals och ColumnGrandTotals styr den sparade arbetsbokens policy, medan MaterializeGrandTotalRow och MaterializeGrandTotalColumn låter resultatanropen få uttryckliga totalsummor utan att källposterna behöver ses över igen
Utökade visa-värden-som-lägen
ExtendedShowDataAs tillhandahåller procent av överordnad, procent av överordnad rad, procent av överordnad kolumn, procent av löpande summa samt stigande eller fallande rang. Dessa lägen använder XLSX-tilläggsmodellen och skriver inte ut klassiska BIFF-värdefältvärden som inte stöds
Inspektera en befintlig pivottabellsarbetsbok
Workbook.Open('excel-authored-pivot.xls');
for SheetIndex := 1 to Workbook.Sheets.Count do
begin
Sheet := Workbook.Sheets[SheetIndex];
for PivotIndex := 0 to Sheet.PivotTables.Count - 1 do
begin
Pivot := Sheet.PivotTables[PivotIndex];
Writeln(Pivot.Name);
Writeln(Pivot.FieldCount);
if Assigned(Pivot.Cache) then
Writeln(Pivot.Cache.SourceRangeSheet);
end;
end;