Pokud vygenerujete sešit v Delphi a přidáte k buňce poznámku pomocí klasického API pro komentáře, Excel 365 váš text uloží pod položku Poznámky: staromódní žluté textové pole bez pole pro odpověď, avataru autora a tlačítka pro vyřešení. Komponenta HotXLS zapisuje skutečné vláknové komentáře (threaded comments) z Excelu 365 pomocí metod AddThreadedComment a AddThreadedReply v motoru XLSX, čímž vygeneruje vyhrazenou část xl/threadedComments/threadedCommentN.xml pro každý list a zaregistruje každého autora v celosešitové části person. Konverzace vytvořená vaším kódem je tak naprosto stejným objektem, na který pak recenzent odpovídá přímo v Excelu
Tento rozdíl je zásadní, protože obě funkce se podobají pouze na pohled. Klasická poznámka je plovoucí textové pole, zatímco vláknový komentář představuje záznam konverzace se stabilními identifikátory, stromem odpovědí, registrem autorů a příznakem vyřešení — tedy vším, na čem reálně stojí schvalovací postupy. Tento článek se nejprve věnuje struktuře OOXML, protože jakmile uvidíte oba modely ukládání vedle sebe, jakékoli rozdíly v chování Excelu přestanou být záhadou
Proč se mé komentáře v Excelu 365 zobrazují jako poznámky?
Stručná odpověď: dvě generace komentářů sdílejí jednu tabulku, ale nacházejí se v naprosto odlišných částech souborového balíčku. Původní model — na který se zaměřuje metoda AddComment — ukládá text do souboru xl/comments1.xml (typ obsahu application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml) and pozici bubliny určuje pomocí doprovodné výkresové části VML xl/drawings/vmlDrawing1.vml. Tato dvojice vznikla ještě před zavedením pásu karet. Excel 365 ji sice stále bez potíží načte, ale výsledek zobrazí jako „poznámku“ a nenabídne pro ni rozhraní pro vlákna odpovědí, protože v úložišti není nic, na co by se dalo navázat. Autor je pouze textový řetězec, pozice je tvar VML, a to je celý model
Vláknové komentáře představené v Excelu 365 vrstvu VML zcela ignorují. Každý list obsahující konverzaci nese vlastní část xl/threadedComments/threadedCommentN.xml s typem obsahu application/vnd.openxmlformats-officedocument.spreadsheetml.threadedComments+xml a sešit obsahuje jedinou část xl/person/person.xml (typ obsahu ...spreadsheetml.people+xml), která jednou uvádí každého účastníka. HotXLS zpřístupňuje oba modely na stejném listu: AddComment nadále zapisuje původní dvojici, zatímco AddThreadedComment vytváří nové části. Pokud se váš výstup zobrazuje jako poznámky, volali jste první API, přestože jste chtěli to druhé. Původní model je stále správnou volbou pro určité úlohy (článek o komentářích v buňkách a odkazech ve schvalovacích postupech se mu věnuje podrobně, včetně formátu XLS) — ale nic z něj nelze převést na vlákno konverzace
Co HotXLS zapisuje do balíčku
HotXLS reprezentuje každou odpověď jako objekt TXLSXThreadedComment, který nese odkaz na buňku (Ref), identifikátor ve formátu GUID (Id), volitelný ParentId, AuthorId (který se překládá přes seznam osob), zrcadlené jméno DisplayName, tělo textu, příznak vyřešení Done a čas DateTime ve formátu ISO-8601. Při uložení se každá položka převede na prvek <threadedComment>, jehož atribut t obsahuje identifikátor, atribut dT nese časové razítko a atribut parentT (přítomný pouze u odpovědí) označuje identifikátor nadřazeného komentáře. Excel sestavuje konverzační strom spárováním atributu parentT s t. V XML se nepoužívá žádné vnořování, jde o prostý seznam s odkazy
Část s osobami (person) je prvkem, na který většina ručně psaných implementací zapomíná. Každé authorId ve vláknovém komentáři musí odkazovat na položku <person> v souboru xl/person/person.xml, propojenou ve vztazích sešitu a s vlastním přepsáním typu obsahu — jinak Excel nemá jaké zobrazované jméno vykreslit. HotXLS provádí tuto registraci automaticky: metoda AddThreadedComment vyhledá autora v seznamu Persons sešitu podle zobrazovaného jména a pokud neexistuje, vytvoří novou položku s novým GUID. Komentáře jdoucí po sobě od téhož autora tak sdílejí jednu identitu. Vazby listu obdrží vztah threadedComments, vazby sešitu vztah person a manifest typů obsahu získá obě definice, aniž byste cokoli z toho museli v kódu sami ošetřovat
Vytváření řetězce odpovědí pomocí AddThreadedComment a AddThreadedReply
Metoda AddThreadedComment vytvoří kořen konverzace: její ParentId zůstává prázdné, což ji označuje za začátek vlákna. Metoda AddThreadedReply přijímá parametr ParentRef — odkaz na buňku, kde se kořen nachází —, najde na této pozici počátek konverzace a do ParentId nové odpovědi zapíše Id kořene. Obě metody vracejí nový objekt TXLSXThreadedComment, takže u nově vytvořeného objektu můžete ihned nastavit časové razítko nebo stav vyřešení:
var
Book: TXLSXWorkbook;
Sheet: TXLSXWorksheet;
Root: TXLSXThreadedComment;
begin
Book := TXLSXWorkbook.Create;
try
Book.Open('forecast.xlsx');
Sheet := Book.Sheets[0];
// Conversation root; ParentId stays empty
Root := Sheet.AddThreadedComment(8, 3,
'Q3 figure looks low against the pipeline export', 'Maria Ortiz');
Root.DateTime := '2026-07-06T09:12:00Z';
// Replies anchor at the same cell; ParentRef names the root cell
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;
V tomto kódu stojí za pozornost dva detaily. Zaprvé se předává Root.Ref namísto ručně sestavovaného řetězce: odkaz vygenerovaný knihovnou zaručeně odpovídá tomu, co bude AddThreadedReply vyhledávat, což eliminuje celou třídu chyb s chybným ukotvením o jednu buňku vedle. Zadruhé, oba autoři byli předáni jako prostá zobrazovaná jména — registr osob, identity GUID i propojení authorId se provedly na pozadí volání. Otevřete uložený soubor v Excelu 365 a ukotvení buňky, pořadí odpovědí i oba odlišní účastníci budou funkční: klikněte na Odpovědět a Excel připojí novou zprávu do stejného vlákna, které začal váš kód
Zpětné načítání konverzace: chování při round-tripu
HotXLS podporuje obousměrný přenos (round-trip) vláknových komentářů od verze 2.122.0: opětovné otevření uloženého balíčku sestaví seznam konverzací každého listu i seznam účastníků sešitu přímo z jeho částí, takže identifikátory, odkazy na odpovědi i zobrazovaná jména přežijí kompletní cyklus načtení a zápisu. Čtečka analyzuje soubor person.xml ještě před načtením obsahu samotného listu, což umožňuje přeložit každé authorId na zobrazované jméno hned při načtení. Zpracované identifikátory osob jsou zachovány v původní podobě a neregenerují se, takže sešit přenášený mezi vaším kódem a Excelem si zachovává stabilní identitu autorů napříč libovolným počtem cyklů
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('Root at ', Cmt.Ref, ' by ', Cmt.DisplayName, ': ', Cmt.Text)
else
Writeln(' reply by ', Cmt.DisplayName, ': ', Cmt.Text);
end;
Writeln('Participants: ', Book.Persons.Count);
end;
Úložiště postavené na plochém seznamu s odkazy se zde projevuje záměrně: kolekce ThreadedComments vypisuje odpovědi v pořadí, v jakém jsou uloženy, a prázdný ParentId identifikuje každý kořen vlákna. Pokud potřebujete stromovou strukturu — například pro export schvalovacího protokolu —, seskupte nejprve položky podle Ref a poté v rámci skupiny buňky propojte ParentId s Id. Toto chování zachování načtených dat je jedním z příkladů širší koncepce knihovny; článek o bezztrátovém round-tripu motivů, seznamů rozšíření a výpočetního řetězce popisuje, jak se stejný princip aplikuje na zbytek balíčku
Stav vyřešení, časová razítka a identita autora
Tři atributy nesou sémantiku schvalování a všechny tři jsou u vrácených objektů zapisovatelné. Done odpovídá atributu done — Excel zobrazuje vyřešené vlákno sbalené s odkazem Znovu otevřít. DateTime představuje čas vytvoření v UTC podle ISO-8601 (atribut dT). HotXLS při jeho nevyplnění vloží pevný zástupný znak, aby část prošla validací, ale reálné časové razítko činí historii vlákna čitelnou, proto se doporučuje jej vyplnit. Na straně identity pak každý objekt TXLSXPerson zpřístupňuje ProviderId — obvykle None pro lokálně vytvořené položky — a UserId, které můžete vyplnit UPN nebo e-mailem, pokud je vaše aplikace zná:
var
Root: TXLSXThreadedComment;
Person: TXLSXPerson;
begin
Root := Sheet.ThreadedComments.FindAt('D9');
if Root <> nil then
Root.Done := True; // saved as done="1"; Excel shows the thread resolved
Person := Book.Persons.FindByDisplayName('Maria Ortiz');
if Person <> nil then
Person.UserId := 'maria.ortiz@example.com';
end;
Jeden detail ohledně zmínek: HotXLS zapisuje prvek <mentions> prázdný. Záznamy zmínek se symbolem @ — mechanismus, který zvýrazní jméno kolegy v textu komentáře a vyvolá oznámení v Microsoftu 365 — nejsou modelovány, takže text obsahující znak @ se ukládá jako prostý text. U generovaných sešitů to málokdy představuje problém, ale pokud váš schvalovací proces na těchto oznámeních závisí, je třeba počítat s tím, že je uživatel musí přidat ručně v Excelu. Identita autora v části person se přirozeně páruje s poli původu na úrovni sešitu, která popisuje článek o metadatech sešitu a vlastnostech dokumentu, kde se nachází zbytek auditní stopy generovaného souboru
Co dělají starší verze Excelu s vláknovými komentáři?
Verze Excel 2016 a starší vznikly před zavedením vláknového modelu a části, kterým nerozumějí, jednoduše ignorují. Když samotný Excel 365 ukládá vláknovou konverzaci, zapisuje také stínový původní komentář — zástupnou poznámku s textem „[Vláknový komentář]…“ —, aby starší verze zobrazily alespoň nějaký obsah u dané buňky. HotXLS generuje pouze vláknové části bez původního stínového komentáře, takže soubor zapsaný vaším kódem neukáže v Excelu 2016 vůbec žádný indikátor komentáře. Pokud vaše cílová skupina zahrnuje instalace starší než Office 365 a poznámka tam musí být viditelná, původní API AddComment zůstává kompatibilním kanálem; just avoid stacking both models on the same cell without testing every Excel version you ship to, because how a reader reconciles a note and a thread on one cell is the reader's decision, not yours
Dalším pevným omezením je samotný formát souboru. Vláknové komentáře jsou strukturou OOXML, která nemá žádný ekvivalent v BIFF8, takže formát .xls v HotXLS nepodporuje API pro vlákna — sešit, který musí zůstat v původním binárním formátu, je omezen na klasické poznámky. Rozhodovací schéma je v praxi jednoduché: pokud zapisujete .xlsx pro Excel 365 nebo webové/mobilní čtečky Excelu, použijte AddThreadedComment a získáte reálné konverzace; pokud cílíte na Excel 2016 nebo formát .xls, použijte AddComment a akceptujte model poznámek; při auditu doručeného souboru zkontrolujte jak ThreadedComments, tak Comments, protože sešit, který prošel oběma světy, může legitimně obsahovat obojí. Kompletní rozhraní API pro obě generace je popsáno na produktové stránce HotXLS Delphi Excel Component