Artigo Técnico

HotXLS: Proteção de Folhas, Configuração de Página e Impressão em Delphi

Existem três conjuntos de definições de folhas de cálculo que em nada dependem dos valores das células, mas definem inteiramente o comportamento do documento assim que este sai do seu código: a proteção de folhas determina quais as células que um utilizador pode editar após a entrega do livro; a configuração de página fixa a orientação, o tamanho do papel e as margens; e as opções de impressão (como a repetição de cabeçalhos, a escala e as quebras de página manuais) controlam como uma tabela de comprimento variável é impressa. Nenhuma das três é visível numa visualização simples de dados no ecrã, mas todas falham silenciosamente na prática se configuradas incorretamente. O HotXLS, uma biblioteca nativa Delphi e C++Builder para folhas de cálculo, expõe a totalidade destas definições para formatos .xls e .xlsx, o que significa que também reproduz todas as regras menos intuitivas do Excel

A primeira destas regras surpreende a maioria dos programadores na primeira tentativa de proteger uma folha gerada por código: ao invocar Protect, todas as células ficam inacessíveis, impedindo a escrita mesmo nas colunas de dados destinadas à edição pelo utilizador. Nada no seu código alterou essas colunas, e é precisamente por essa razão que o bloqueio ocorre

Todas as células nascem bloqueadas

A especificação ECMA-376 define a propriedade locked (bloqueada) como parte do registo de formatação da célula e não como um atributo da proteção em si, tendo por padrão o valor verdadeiro. A proteção da folha de cálculo funciona apenas como o interruptor que ativa a validação deste marcador. Como tal, toda a grelha carrega o marcador de bloqueio de forma latente desde a sua criação, e a chamada a Protect ativa-os a todos em simultâneo. A solução consiste em seguir uma ordem lógica: construa o layout, desbloqueie explicitamente os intervalos que o utilizador deve editar e aplique a proteção no final

Book := TXLSXWorkbook.Create;
try
  Sheet := Book.Sheets.Add('Timesheet');
  // ... header row, name column, and rate formulas written here ...
  Sheet.Range['B2:B50'].SetLocked(False);         // os utilizadores inserem as horas aqui
  Sheet.Range['F2:F50'].SetFormulaHidden(True);   // ocultar a fórmula de cálculo da taxa
  Sheet.Protect('review-2026');                   // os marcadores de bloqueio são agora ativados
  Book.SaveAs('timesheet.xlsx');
finally
  Book.Free;
end;

O método SetFormulaHidden realiza uma operação distinta e fácil de omitir: enquanto a proteção se mantém ativa, a célula exibe o seu valor calculado mas a barra de fórmulas permanece vazia. Isto é útil se uma fórmula contiver taxas de faturação, margens ou ponderações que não pretenda partilhar com os destinatários do relatório. Na interface XLS, o mesmo comportamento é definido por intervalo através das propriedades IXLSRange.Locked e FormulaHidden. A folha de cálculo XLS disponibiliza também quinze marcadores do tipo Allow* (como AllowSort, AllowAutoFilter, AllowFormatCells e afins), permitindo ordenar e filtrar a folha protegida sem a bloquear por completo

O que a palavra-passe de proteção realmente protege

Ambos os formatos guardam a palavra-passe de proteção de folhas e livros sob a forma de um hash legado de 4 dígitos hexadecimais. A validação com dezasseis bits significa que inúmeras strings de texto colidem com a palavra-passe e existem ferramentas simples para a remover. Considere a proteção como um cinto de segurança contra alterações acidentais e não como controlo de acessos. É a ferramenta certa para evitar que os revisores escrevam sobre a coluna de fórmulas, mas incorreta para qualquer cenário que exija confidencialidade real

No nível seguinte, o método ProtectWorkbook na interface XLSX bloqueia a estrutura do livro, impedindo a adição, renomeação, eliminação ou reordenação de folhas. Defina esta opção se a lista de folhas for crítica para o analisador de dados que consome o ficheiro a jusante e identifica as folhas pelo nome ou posição. Renomear uma folha corrompe a importação de dados no destino da mesma forma que eliminar uma coluna. A faceta XLS replica esta hierarquia com TXLSWorkbook.Protect ao nível do livro, chamadas a Protect por folha e a propriedade isProtected para código que necessite de validar um ficheiro antes de o alterar

Sempre que a confidencialidade real for um requisito, o mecanismo a adotar é distinto: o método SaveAsEncrypted/_SaveAsEncrypted/SaveAsEncrypted/_SaveAsEncrypted (aqui mantemos SaveAsEncrypted) produz um pacote cifrado via AES sob o padrão ECMA-376 (Standard Encryption), detalhado no guia de saída XLSX protegida com AES; por sua vez, a faceta XLS legada lê e escreve ficheiros .xls cifrados com RC4 através da propriedade EncryptionPassword e da sobrecarga com palavra-passe do método Open. Esta distinção é fundamental: uma folha apenas protegida é guardada em texto simples (qualquer ferramenta zip consegue ler os valores das células), ao passo que um ficheiro cifrado é ilegível sem a palavra-passe. Uma regra de auditoria que defina "o ficheiro de vencimentos deve estar protegido" refere-se quase sempre a cifragem, independentemente da terminologia usada

A configuração de página é parte da especificação do documento

As definições de impressão não são visíveis no ecrã, razão pela qual falham frequentemente. Quando o utilizador final imprime a tabela ou a converte para PDF, a orientação das margens, o tamanho e as áreas de repetição passam a ser requisitos obrigatórios. No lado XLSX, estas opções são expostas na folha:

Sheet.PageLandscape := True;
Sheet.PaperSize := xlsxPaperA4;
Sheet.SetPageMargins(0.5, 0.5, 0.75, 0.75, 0.3, 0.3);
Sheet.CenterHeader := 'Monthly Timesheet';
Sheet.RightFooter := 'Page &P of &N';
Sheet.PrintArea := '$A$1:$F$60';     // referência simples: sem indicar o nome da folha
Sheet.PrintTitleRows := '$1:$1';     // a linha de cabeçalho repete-se em cada página
Sheet.FitToWidth := 1;
Sheet.FitToHeight := 0;              // expandir verticalmente à medida que os dados crescem
Sheet.PrintGridlines := False;

Duas destas linhas escondem armadilhas. As strings de cabeçalho e rodapé utilizam os códigos de formatação do Excel: &P para a página atual, &N para o total de páginas e as opções &L, &C e &R para definir as três secções do alinhamento. A outra armadilha reside em PrintArea, que recebe intencionalmente uma referência de célula simples. O HotXLS armazena-a sem qualificadores e adiciona-lhe o nome da folha ao gravar o ficheiro; assim, passar a string 'Timesheet!$A$1:$F$60' gerará uma referência malformada e duplamente qualificada. O mesmo cuidado aplica-se a nomes definidos: a área de impressão e os títulos repetidos são guardados no documento como os nomes internos _xlnm.Print_Area e _xlnm.Print_Titles, pelo que nunca os deve adicionar manualmente através de DefinedNames para evitar conflitos de slot

Escala que suporta volumes de dados reais de produção

A combinação FitToWidth := 1 com FitToHeight := 0 traduz-se em "ajustar as colunas à largura de uma página e expandir em comprimento nas páginas necessárias", constituindo a abordagem correta para relatórios de dimensão variável. A armadilha reside em ajustar uma percentagem fixa ou forçar o número de páginas com base num ficheiro de teste com trinta linhas: aplicar as mesmas definições a uma tabela de seiscentas linhas em produção fragmentará o documento em dezenas de páginas cortadas ou reduzirá a escala até o tornar ilegível. Redimensione a largura, permita o crescimento vertical e repita a linha de cabeçalho através de PrintTitleRows para manter a legibilidade nas páginas seguintes

As quebras manuais de página seguem o mesmo ciclo de regeneração que o resto do livro gerado por código. O método AddRowBreak(BeforeRow) inicia uma nova página antes do limite de uma secção; contudo, se o gerador for executado novamente e as linhas se deslocarem, uma quebra desatualizada ficará posicionada no meio da tabela. Invoque primeiro ClearAllPageBreaks e volte a adicionar as quebras calculadas com base nos contadores de linhas do gerador em vez de tentar corrigir as posições antigas. Na interface XLS, as opções correspondentes residem em Sheet.PageSetup (orientação, tamanho do papel, margens, strings de cabeçalho e rodapé, ajuste de páginas), com as propriedades RepeatRows e RepeatColumns a gerirem a repetição de títulos

Validar o resultado antes do cliente final

Falhas na proteção ou na configuração de impressão partilham uma característica: são simples de detetar manualmente, mas raramente validadas. Abra o ficheiro gerado no Excel e valide-o durante breves momentos: escreva numa célula editável e valide se a escrita é aceite; tente escrever numa célula bloqueada e valide o surgimento do aviso de proteção; e confirme que as fórmulas ocultadas deixam a respetiva barra de fórmulas vazia. Em seguida, execute a Pré-visualização de Impressão sobre um conjunto de dados de produção real (e não sobre a amostra de trinta linhas) para conferir o número de páginas, a repetição do cabeçalho e a numeração do rodapé. A pré-visualização é uma fase crítica, pois a geometria de impressão depende de definições sem representação visual no ecrã e, tirando a impressão física, é o único local onde erros de escala se tornam visíveis

Uma última definição completa o processo: o método FreezePane(ACol, ARow) mantém o cabeçalho visível enquanto o utilizador percorre a folha (scroll). Trata-se de um comportamento de ecrã e não de impressão, mas o utilizador avalia o documento na sua totalidade. Um livro estruturado com base num modelo desenhado manualmente herda a maioria destas definições de forma transparente: o fluxo de geração de relatórios com modelos mantém as configurações de página no próprio modelo (onde foram afinadas para impressão real), restando ao seu código apenas preencher os dados e aplicar a proteção após a montagem do layout

O HotXLS é uma biblioteca nativa Object Pascal de folhas de cálculo para Delphi e C++Builder; a referência completa da API de proteção e configuração de página está disponível na página do produto HotXLS Component