Artigo Técnico

Comentários Encadeados em Ficheiros do Excel com Delphi e o HotXLS

Ao gerar um livro a partir de Delphi, adicionar anotações com as APIs de comentários clássicas faz com que o Excel 365 classifique as mensagens como Notas (caixas amarelas sem campos de resposta, avatars de autor ou botões para concluir). O HotXLS permite escrever comentários encadeados reais do Excel 365 utilizando as funções AddThreadedComment and AddThreadedReply no motor XLSX, gerando a secção correspondente xl/threadedComments/threadedCommentN.xml por folha e registando os autores no ficheiro de utilizadores (person) do livro. Assim, a conversação criada por código funciona exatamente como o objeto que um revisor responde no Excel

Esta diferença é fundamental, dado que as funcionalidades são distintas. Uma nota é apenas uma caixa de texto flutuante, ao passo que o comentário encadeado consiste num registo de conversação estruturado (com identificadores estáveis, árvore de respostas, registo de autores e estados de conclusão), aspetos críticos em fluxos de revisão. Este artigo descreve a estrutura OOXML correspondente para explicar as variações de comportamento no Excel

Por que razão os meus comentários surgem como notas no Excel 365?

Em suma: coexistem duas gerações de comentários na mesma grelha, guardadas em secções diferentes do pacote. O modelo antigo (gerido por AddComment) guarda o texto em xl/comments1.xml (tipo de conteúdo application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml) e define a posição geométrica num elemento de desenho VML homólogo, xl/drawings/vmlDrawing1.vml. Esta estrutura é anterior à barra de ferramentas (ribbon); o Excel 365 suporta a leitura del formato, mas exibe o resultado como uma "nota" sem interface para respostas (dado que não existem referências lógicas no ficheiro). O autor é apenas uma string de texto e a posição traduz-se numa forma VML

Os comentários encadeados (introduzidos no Excel 365) prescindem da camada VML. Cada folha com interações possui o ficheiro xl/threadedComments/threadedCommentN.xml (tipo de conteúdo application/vnd.openxmlformats-officedocument.spreadsheetml.threadedComments+xml) e o livro partilha a tabela xl/person/person.xml (tipo ...spreadsheetml.people+xml) com a lista de participantes. O HotXLS disponibiliza ambas as variantes na mesma folha: AddComment escreve a estrutura antiga e AddThreadedComment escreve as novas secções. Se as anotações surgirem como notas, utilizou a primeira rotina em vez da segunda. O modelo antigo continua a ser útil em alguns fluxos, descritos no artigo sobre comentários clássicos e hiperligações, mas não suporta cadeias de resposta

Estrutura gravada pelo HotXLS no pacote

O HotXLS representa cada resposta na classe TXLSXThreadedComment, que contém a âncora da célula (Ref), identificador GUID (Id), ID do pai opcional (ParentId), ID do autor (AuthorId, validado na lista de participantes), nome a exibir (DisplayName), corpo do texto, estado de conclusão (Done) e timestamp ISO-8601 (DateTime). Na gravação, cada registo converte-se no elemento <threadedComment>, onde o atributo t identifica o ID, dT indica a data e hora e parentT (usado apenas em respostas filhas) define o ID do pai correspondente. O Excel reconstrói a árvore de interações associando os caminhos de parentT a t, sem aninhamentos físicos no XML

A secção de utilizadores (person) é um requisito crítico que implementações básicas tendem a omitir. Todos os authorId nos comentários encadeados necessitam de um registo <person> em xl/person/person.xml (declarado nas relações do livro com tipo de conteúdo explícito), caso contrário o Excel não exibirá o nome do autor. O HotXLS gere esta associação automaticamente: a rotina AddThreadedComment pesquisa o nome do autor na coleção Persons do livro, criando um novo GUID se necessário. Desta forma, mensagens consecutivas do mesmo utilizador partilham a mesma identidade de autor. As relações e manifestos de tipos de conteúdo são atualizados pelo motor sem intervenção no código

Construir cadeias de resposta com AddThreadedComment e AddThreadedReply

O método AddThreadedComment cria a mensagem inicial da conversação (com ParentId vazio). A função AddThreadedReply aceita o argumento ParentRef (célula onde reside o comentário de origem), localiza a mensagem inicial na coordenada correspondente e associa o ID lógico do pai. Ambas as rotinas retornam a instância de TXLSXThreadedComment, permitindo redefinir aspetos de data e estados de conclusão:

var
  Book: TXLSXWorkbook;
  Sheet: TXLSXWorksheet;
  Root: TXLSXThreadedComment;
begin
  Book := TXLSXWorkbook.Create;
  try
    Book.Open('forecast.xlsx');
    Sheet := Book.Sheets[0];

    // Mensagem inicial; ParentId mantém-se vazio
    Root := Sheet.AddThreadedComment(8, 3,
      'Q3 figure looks low against the pipeline export', 'Maria Ortiz');
    Root.DateTime := '2026-07-06T09:12:00Z';

    // As respostas ancoram na mesma célula; ParentRef indica a célula de origem
    Sheet.AddThreadedReply(8, 3, Root.Ref,
      'Pipeline export missed the EMEA renewals, re-running', 'Jan Kowalski');
    Sheet.AddThreadedReply(8, 3, Root.Ref,
      'Confirmed, refreshed figure lands tomorrow', 'Maria Ortiz');

    Book.SaveAs('forecast-reviewed.xlsx');
  finally
    Book.Free;
  end;
end;

Particularidades da rotina: primeiro, é recomendável passar Root.Ref em vez de strings manuais para garantir que a referência de procura em AddThreadedReply coincide com o registo do objeto. Segundo, os autores são declarados apenas pelo nome a exibir, sendo as lógicas de registo de utilizadores e identidades GUID tratadas internamente pelo motor. Ao abrir o ficheiro no Excel 365, as âncoras, ordens de respostas e identidades são interpretadas nativamente, permitindo continuar a conversação via botão Responder

Leitura de comentários em ciclos de modificação

O HotXLS suporta a preservação de comentários encadeados (desde a versão 2.122.0): a leitura de um ficheiro repõe a lista de conversações de cada folha e a coleção de utilizadores do livro, mantendo IDs, ordenações e nomes. O analisador processa a secção person.xml antes da folha de cálculo para associar os authorId aos nomes no carregamento. As identidades originais são preservadas na sua redação original, mantendo a consistência dos autores em sucessivos ciclos de modificação entre o código e o Excel

var
  i: Integer;
  Cmt: TXLSXThreadedComment;
begin
  Book.Open('forecast-reviewed.xlsx');
  Sheet := Book.Sheets[0];
  for i := 0 to Sheet.ThreadedComments.Count - 1 do
  begin
    Cmt := Sheet.ThreadedComments[i];
    if Cmt.ParentId = '' then
      Writeln('Inicial em ', Cmt.Ref, ' por ', Cmt.DisplayName, ': ', Cmt.Text)
    else
      Writeln('  resposta por ', Cmt.DisplayName, ': ', Cmt.Text);
  end;
  Writeln('Participantes: ', Book.Persons.Count);
end;

O modelo de dados reflete a estrutura física: ThreadedComments enumera as respostas por ordem de gravação, identificando-se as mensagens iniciais por ParentId vazio. Para extrair dados estruturados sob a forma de árvore, agrupe os elementos por Ref e ordene associando ParentId a Id na célula. Esta política de preservação de leitura aplica-se a todo o pacote, conforme abordado no artigo sobre preservação e compatibilidade do calc chain, temas e extension lists

Estados de conclusão, timestamps e utilizadores

Existem três atributos para gestão de revisões nas instâncias. O campo Done mapeia para o atributo XML correspondente (no Excel, interações concluídas surgem minimizadas com a hiperligação Reabrir). O campo DateTime indica o timestamp ISO-8601 UTC (dT); se deixado em branco, o HotXLS preenche um valor de salvaguarda para assegurar a conformidade da estrutura XML (sendo recomendável declarar a data explicitamente para manter o histórico coerente). Em utilizadores, a classe TXLSXPerson expõe as propriedades ProviderId (geralmente None em registos locais) e UserId (para UPN ou email):

var
  Root: TXLSXThreadedComment;
  Person: TXLSXPerson;
begin
  Root := Sheet.ThreadedComments.FindAt('D9');
  if Root <> nil then
    Root.Done := True;   // gravado como done="1"; o Excel exibe a conversação como concluída

  Person := Book.Persons.FindByDisplayName('Maria Ortiz');
  if Person <> nil then
    Person.UserId := 'maria.ortiz@example.com';
end;

Nota técnica: o HotXLS não implementa menções (o elemento <mentions> é exportado vazio). A estrutura de menções com @ (que identifica utilizadores no Microsoft 365 e gera alertas por email) não é modelada, sendo o carácter @ lido e gravado apenas como texto simples. Se o fluxo de trabalho requerer estes alertas, as menções correspondentes deverão ser introduzidas manualmente no Excel. A gestão de autores associa-se aos metadados do livro analisados no artigo sobre propriedades e metadados de documentos

O que fazem versões antigas do Excel com comentários encadeados?

O Excel 2016 e versões anteriores são anteriores a este modelo, pelo que ignoram os blocos XML correspondentes. Quando o Excel 365 grava comentários encadeados, escreve também notas clássicas redundantes (com a string "[Threaded comment]...") para garantir retrocompatibilidade. O HotXLS escreve apenas as estruturas encadeadas reais sem dados de salvaguarda clássicos. Desta forma, ficheiros gerados por código não exibirão notas se abertos no Excel 2016. Se requerer suporte para estas versões, a rotina antiga AddComment constitui a alternativa compatível. Evite duplicar ambas as abordagens na mesma célula sem validação prévia de comportamento nos diversos leitores

Limitação do formato de ficheiro: os comentários encadeados pertencem à estrutura OOXML (não contendo suporte no padrão binário BIFF8), pelo que o formato legatário .xls do HotXLS está limitado a notas clássicas. Resumindo: ao gerar .xlsx para Excel 365 ou leitores web/mobile, utilize AddThreadedComment para suportar diálogos; em ficheiros .xls ou compatibilidade com Excel 2016, use AddComment. Ao ler ficheiros, é aconselhável validar as propriedades ThreadedComments e Comments. A documentação completa das rotinas integra a página do HotXLS Delphi Excel Component