Documentação do HotXLS

API de tabela dinâmica XLS clássico

O HotXLS oferece dois fluxos de trabalho clássicos de tabela dinâmica em XLS. As pastas de trabalho abertas no Excel mantêm a exibição dinâmica original e os registros do cache dinâmico para ciclos de ida e volta no salvamento. O código também pode inspecionar o modelo tipado de pivot e criar novas tabelas dinâmicas clássicas em XLS por meio de

Round-trip e modelo tipado

Quando uma pasta de trabalho já contém tabelas dinâmicas, o leitor preserva os registros BIFF brutos e também expõe um modelo tipado aproximado. As tabelas e os caches carregados de um arquivo mantêm FromRawBlobs = True, então a saída de salvamento reproduz os bytes originais para preservar a fidelidade. Os pivôs criados programaticamente usam o gravador tipado

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;
      

Pontos de entrada de planilha e pasta de trabalho

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 registra uma string de formato numérico e retorna seu índice ifmt BIFF8, que é o que TXLSPivotDataField.NumberFormat e TXLSPivotCacheField.NumberFormat esperam; registrar a mesma string duas vezes retorna o mesmo índice

DestRow e DestCol são baseadas em 1, como Cells[Row, Col], então AddPivotTable('Data!A1:C9', 3, 1, 'SalesPivot') ancora a tabela dinâmica em A3. As posições em TXLSPivotTable (FirstRow .. FirstDataCol) e o intervalo de origem em TXLSPivotCache também são baseadas em 1, igual ao mecanismo XLSX; uma âncora fora da planilha de 65,536 x 256 retorna nil

Criar um layout de tabela dinâmica com arrastar e soltar

TXLSPivotDesigner é um modelo de layout não visual que pode dar suporte a interfaces de lista de campos em VCL, FMX, web ou linha de comando sem acoplar a lógica da tabela dinâmica a um único toolkit de UI

Cada campo informa uma zona disponível, de linha, de coluna, de filtro ou de valor, além de sua posição determinística; MoveField aplica um drop, SetAggregation altera um campo de valor, Validate informa layouts incompletos, e Apply valida e materializa o resultado por meio do escritor de tabela dinâmica normal

Novos campos de valor numéricos e de data têm padrão xlpaSum, enquanto campos de texto, Boolean, erro, vazio e mistos têm padrão xlpaCount

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;
      

Criar uma tabela dinâmica

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;
      

Exibir valores como

Defina ShowDataAs em cada campo de dados antes de chamar Make ou salvar a pasta de trabalho. Difference, Percente PercentDiff exigem um índice de campo dinâmico BaseField com base 0 mais um BaseItem. RunTotal exige apenas BaseField. Os modos de linha, coluna, total e índice derivam seus denominadores dos registros de origem com a agregação configurada

Um BaseItem explícito é um índice de item com base 0 dentro do campo dinâmico base. Use xlPivotBaseItemPrevious ou xlPivotBaseItemNext para comparações com itens adjacentes. Interseções de comparação ausentes permanecem em branco, enquanto um denominador zero presente produz #DIV/0!

DataField := Pivot.AddDataFieldByName('Revenue', xlpaSum);
DataField.ShowDataAs := xlpsdaPercentDiff;
DataField.BaseField := 0;
DataField.BaseItem := xlPivotBaseItemPrevious;
CellsWritten := Pivot.Make(ResultWriter.WriteCell);
      

Filtragem, agrupamento e classificação

Make aplica itens ocultos e seleções de página antes da construção do domínio, depois avalia filtros de legenda, data, contagem, porcentagem, soma e valor. Intervalos numéricos, grupos de calendário e grupos discretos usam metadados de agrupamento de cache-field antes da agregação. SortType seleciona a ordenação estável de rótulos, enquanto SortDataField seleciona o campo de valor (base 0) para a ordenação estável por valores de dados

Expressões calculadas

Campos de cache calculados executam uma vez por registro de origem, itens calculados executam entre agregados de itens irmãos, e membros calculados com MemberType = 'data' adicionam campos de valor virtuais depois da agregação de origem. Nomes de fórmula não diferenciam maiúsculas e podem vir entre colchetes ou aspas. Há suporte para aritmética, comparações, porcentagens, parênteses e funções numéricas e lógicas comuns, com passadas repetidas de dependências para definições calculadas acíclicas

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';
      

Subtotais e totais gerais

Cada campo de linha ou coluna pode materializar qualquer função de subtotal configurada acima ou abaixo dos seus itens de detalhe por meio de Subtotals e SubtotalTop. RowGrandTotals e ColumnGrandTotals controlam a política salva na pasta de trabalho, enquanto MaterializeGrandTotalRow e MaterializeGrandTotalColumn fazem os callbacks de resultado incluírem a saída explícita de total geral sem revarrer os registros de origem

Modos estendidos de exibição de valores

ExtendedShowDataAs oferece porcentagem do pai, porcentagem da linha pai, porcentagem da coluna pai, porcentagem do total acumulado e classificação crescente ou decrescente. Esses modos usam o modelo de extensão XLSX e não emitem valores clássicos de campo de dados BIFF não suportados

Inspecionar uma pasta de trabalho dinâmica existente

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;
      

Tópicos relacionados