Você montou uma planilha exatamente do jeito certo. A faixa do cabeçalho está mesclada, as larguras das colunas se ajustam aos dados, as duas primeiras linhas estão congeladas, a área de impressão e as margens foram definidas para uma exportação A4 limpa, e a guia está colorida para o financeiro encontrá-la. Agora o relatório precisa de doze dessas, uma por região, todas começando do mesmo layout. Recriar essa planilha em código doze vezes é o tipo de coisa que faz surgir desvios sutis: a região 7 ganha uma coluna um ponto mais estreita, a região 11 perde o congelamento, e ninguém percebe até o PDF chegar à mesa de um gerente. O que você realmente quer é a versão programática do clique direito do Excel, Mover ou Copiar, Criar uma cópia: pegue a planilha pronta e gere duplicatas independentes
O mecanismo XLSX do HotXLS, uma biblioteca nativa de Delphi e C++Builder que lê e grava arquivos Excel sem automatizar o Excel em si, já conseguia mover planilhas, excluir planilhas e copiar intervalos de células entre planilhas. O que ele não fazia até a v2.91.0 era clonar uma planilha inteira em uma única chamada. Essa versão acrescenta dois pontos de entrada: TXLSXWorksheet.CopyFrom, que copia o estado da planilha de uma worksheet para outra, e TXLSXSheets.Duplicate, que cria uma nova planilha e executa CopyFrom para você. O interessante não é que ele copia coisas. É a linha deliberada entre o que é copiado em profundidade e o que não é, e por que essa linha fica exatamente ali
Uma chamada para duplicar uma planilha pronta
A operação de alto nível é Duplicate. Passe o índice 1-based da planilha de origem e ele retorna uma worksheet totalmente nova, espelhando o layout e os dados da original. A convenção de índice corresponde a Items[] no lado XLSX, então a primeira planilha tem índice 1, não 0; se você passar um índice fora do intervalo, recebe nil em vez de uma exceção, o mesmo contrato de falha usado pelo restante da coleção de planilhas XLSX
var
Book: TXLSXWorkbook;
Template, Copy: TXLSXWorksheet;
begin
Book := TXLSXWorkbook.Create;
try
Template := Book.Sheets.Add('Template');
Template.Cells[1, 1].Value := 'Quarterly Statement';
Template.Range['A1:C1'].Merge;
Template.ColWidth[1] := 18;
Template.FreezePanes(2, 1); // freeze top row + first column
Template.TabColorIsAuto := False;
Template.TabColor := $FF1F4E79;
// Clone with an explicit name...
Copy := Book.Sheets.Duplicate(1, 'Region-North');
// ...or let it pick the Excel-style default name.
Copy := Book.Sheets.Duplicate(1); // -> "Template (2)"
Book.SaveAs('regions.xlsx');
finally
Book.Free;
end;
end;
Duas coisas nesse trecho merecem atenção. Primeiro, FreezePanes recebe os argumentos na ordem linha primeiro, FreezePanes(ARow, ACol), então ele se alinha ao indexador Cells[Row, Col]; a cópia herda exatamente a mesma divisão congelada. Segundo, o método se chama Duplicate e não o mais óbvio Copy, e isso não é preferência de estilo. Copy é uma rotina padrão na unit System, usada o tempo todo com strings e arrays dinâmicos. Um método chamado Copy em uma classe o sombrearia dentro dos corpos dos métodos e criaria exatamente o tipo de ambiguidade de resolução que cobra a conta meses depois. Duplicate contorna o problema inteiro e faz sentido no ponto de chamada
O nome padrão segue a convenção do Excel
Quando você chama a sobrecarga com um argumento, ou passa uma string de nome vazia, a nova planilha recebe o nome da origem com o sufixo (2), e esse sufixo avança até o nome ficar único. Duplique a planilha Template uma vez e você obtém Template (2); duplique de novo e recebe Template (3), porque Template (2) já está ocupado. Isso espelha os nomes que o Excel gera com o próprio comando Criar uma cópia, então uma pasta de trabalho produzida pelo seu código fica com a aparência que um usuário esperaria de uma duplicação manual. A verificação de unicidade atua sobre a coleção de planilhas em uso, o que significa que ela também respeita nomes criados manualmente, não só os vindos de duplicações anteriores
Se você está gerando uma planilha por região ou por mês, prefira a sobrecarga com nome explícito. Um esquema previsível como Region-North e Region-South é mais fácil de endereçar depois do que uma sequência de sufixos (2), (3), e mantém seus nomes definidos e fórmulas entre planilhas legíveis
O que CopyFrom copia de forma profunda
Por baixo dos panos, Duplicate adiciona a planilha e então chama CopyFrom(ASource), que você também pode chamar diretamente quando quiser clonar sobre uma planilha já criada. CopyFrom protege de antemão os dois casos degenerados: copiar de nil ou copiar uma planilha sobre ela mesma. Em ambos os casos ele retorna imediatamente e não faz nada. Tudo depois disso é a cópia em si, e ela é deliberadamente ampla
Os dados das células vêm primeiro. CopyFrom pede à origem o UsedRange, o retângulo justo que contém as células preenchidas e as regiões mescladas, e reaproveita a infraestrutura existente de CopyRangeTo para levar todos os valores, fórmulas e índices de estilo de cada célula para o destino, começando em A1. Sobre as células, ele refaz toda a camada de estado da planilha que faz um modelo parecer finalizado:
- Regiões mescladas, recriadas por coordenada para que o banner ocupe o mesmo retângulo
- Larguras de coluna e alturas de linha, além das listas de oculto, recolhido e nível de estrutura, copiadas literalmente para que linhas e colunas fora do padrão se alinhem com precisão
- Congelamento de painéis e estado de visualização: nível de zoom, exibição de linhas de grade e de zeros, direção da direita para a esquerda e tipo de exibição
- Estado de proteção com suas opções de permissão por ação, para que um modelo bloqueado permaneça bloqueado do mesmo jeito
- Todo o bloco de configuração de página: margens, orientação, tamanho do papel, escala e ajuste à página, área de impressão, títulos de impressão, cabeçalhos e rodapés, além das flags de linhas de grade e títulos de impressão
- Intervalo de AutoFilter, cor da guia e visibilidade da planilha
O resultado é uma planilha que imprime, filtra e se apresenta exatamente como a origem. E, como as células, as mesclagens e as listas de dimensões são recriadas fisicamente na nova planilha, e não apenas apontadas para a mesma memória, a cópia é totalmente independente. Escreva 999 em uma célula da cópia e a origem mantém o valor original; essa independência é a propriedade mais importante de um clone pensado para relatórios regionais em paralelo, e o demo SheetCopy já a verifica explicitamente
O que permanece superficial, e por quê
Agora a parte honesta. Gráficos, imagens incorporadas, tabelas XLSX, validações de dados e regras de formatação condicional não são copiados. Essa é uma fronteira documentada e deliberada, não uma omissão, e vale entender o motivo para planejar em torno dela em vez de ser surpreendido
Cada uma dessas coleções carrega identidade e referências que não sobrevivem a uma cópia ingênua de campos. Um gráfico aponta para um intervalo de dados de origem e possui uma relação de desenho no pacote OOXML; clonar o objeto sem remapear a relação e as referências das séries produz um gráfico desenhado com os dados errados, ou um pacote que o Excel marca como necessitando reparo. Uma tabela tem um nome que precisa ser único dentro da pasta de trabalho, uma linha de cabeçalho ligada a colunas específicas e sua própria relação gerada automaticamente. Formatações condicionais e validações de dados se prendem a intervalos de coordenadas e, no caso da validação, podem referenciar outros intervalos por fórmula. Copiar em profundidade qualquer uma delas corretamente significa reescrever referências e gerar identidades novas, o que é trabalho real com modos reais de falha. Fazer isso pela metade, copiando o objeto mas não suas referências, é pior do que não copiar nada: resulta em um arquivo que abre com pedido de reparo e descarta conteúdo em silêncio. Então o mecanismo copia o que consegue copiar de forma limpa e deixa as coleções que carregam referência para o chamador, que sabe para onde o destino deve apontar
Na prática, isso significa que o fluxo para um modelo mais rico é: duplique a planilha para obter células, layout e configuração de impressão, depois recrie o gráfico, a tabela, as validações ou as formatações condicionais na cópia com a mesma API usada na primeira criação. Como você está recriando esses elementos sobre os intervalos da própria cópia, as referências saem corretas por construção. Para um gráfico que lê A1:C10, adicione um novo gráfico na cópia apontando para o A1:C10 da cópia; para um AutoFilter que você quer manter ativo, observe que o intervalo do filtro é preservado, então você só reaplica os critérios de coluna. As regras de formatação condicional e validação de dados que você reaplicaria pelas mesmas chamadas descritas no artigo sobre layout de células mescladas e modelos de relatório usam a tabela de mesclagem e o modelo de intervalo que a cópia herda
Como a duplicação entra no pipeline de relatórios
A duplicação de planilhas é a companheira natural da geração guiada por marcadores. A abordagem ancorada em tokens no guia de geração de relatórios a partir de modelos no Delphi resolve o problema de escrever dados em um layout que outras pessoas editam; a duplicação resolve o problema de precisar desse layout várias vezes em uma única pasta de trabalho. Combine as duas e o padrão fica limpo: mantenha uma planilha Template intacta, com seus tokens, mesclagens e configuração de impressão, depois, para cada região ou período, chame Duplicate, preencha os tokens da cópia com aquele recorte de dados e siga adiante. O modelo original nunca é modificado, então ele continua sendo uma fonte confiável para a próxima cópia, e cada planilha de saída começa com um layout idêntico byte a byte
Uma observação de sequência evita confusão. Duplique a planilha antes de despejar dados nela, não depois. Um modelo deve guardar estrutura e formatação, não os números do trimestre anterior, e clonar uma planilha vazia e estilizada significa que cada cópia começa limpa. Se você duplica uma planilha que já contém dados, esses dados vêm junto, porque CopyFrom copia fielmente o intervalo usado; às vezes é isso que você quer, mas, para um relatório em fan-out, normalmente não é
Um hábito rápido de verificação
Como a divisão entre cópia profunda e superficial fica invisível até que alguém a procure, coloque uma checagem de cinco linhas no processo em vez de confiar que tudo foi preservado. Depois de duplicar, leia de volta os sinais estruturais que a cópia deveria herdar e confirme que correspondem à origem
Copy := Book.Sheets.Duplicate(1, 'Region-North');
WriteLn(Format('merged=%d colA=%.1f freezeRow=%d tabAuto=%d',
[Copy.MergedCells.Count, Copy.ColWidth[1],
Copy.FreezeRow, Integer(Copy.TabColorIsAuto)]));
// Prove independence: mutate the copy, confirm the source is untouched.
Copy.Cells[2, 2].Value := 999;
// Template.Cells[2, 2].Value is still whatever it was.
The merge count, a column width, the freeze row, and the tab-colour flag tell you the layer that is copied actually made it. Separately, in any sheet that carried a chart, a table, validations, or conditional formats, treat those as a to-rebuild list on the copy: their absence is by design, and the fix is a few calls, not a bug report. That mental model, deep where it is safe and shallow where references would break, is the whole story of how to use this feature well
A duplicação de planilhas e a cópia de estado de planilha via CopyFrom descritas aqui fazem parte da v2.91.0 do componente de planilhas HotXLS para Delphi, junto com um exemplo executável SheetCopy que exercita o ciclo de clonar e alterar do início ao fim