Technical Article

Excelovi komentarji celic in hipertekstne povezave v Delphiju s HotXLS

Preimenujte delovni list iz "Summary" v "Overview" v ustvarjenem delovnem zvezku in vsaka notranja povezava, ki je kazala na Summary!A1, bo prenehala delovati. Brez sprožitve izjeme ob shranjevanju, brez napak ob odpiranju. Povezava se še vedno izriše, je videti klikljiva, a tiho ne vodi nikamor. Enaka vrsta napake se pojavi po pretvorbi "Shrani kot" ali prehodu med formatoma .xls in .xlsx, ko se komentar zamakne za en stolpec ali ko relativna povezava izgubi svoj cilj. Obe funkciji nosita podatke o pregledu, na podlagi katerih ljudje dejansko ukrepajo, zato je ob njuni okvari napaka nevidna, dokler ocenjevalec ne klikne nanjo in se nič ne zgodi.

To je praktičen razlog, zakaj si komentarji in povezave zaslužijo več pozornosti, kom bi sklepali po njihovem zunanjem izgledu. HotXLS omogoča kodi za Delphi in C++Builder neposreden pisni dostop do obeh v formatu XLS in XLSX brez uporabe avtomatizacije Excela. Druga stran tega nadzora pa je odgovornost: knjižnica zapiše natanko tiste cilje, ki ji jih posredujete, in ne preverja njihove veljavnosti, zato je ohranjanje poteka pregleda delo vaše kode in ne Excela.

Komentarji celic kot strojno zapisani zapisi o pregledu

V razrednem modelu XLSX je komentar objekt na ravni delovnega lista: pozna svojo vrstico, stolpec, avtorja in telo besedila. Polje za avtorja ima pomembno vlogo. Ko delovni zvezek, ki ga je ustvarila vaša koda, potuje skozi revizijsko verigo, je prvo vprašanje revizorja, kdo je zapisal določeno opombo; opomba brez avtorja pa na to vprašanje odgovori s praznino. Označite ustvarjene komentarje z identiteto storitve, da izvor nikoli ne bo dvomljiv.

var
  Book: TXLSXWorkbook;
  Sheet: TXLSXWorksheet;
  Note: TXLSXComment;
begin
  Book := TXLSXWorkbook.Create;
  try
    Book.Open('reconciliation.xlsx');
    Sheet := Book.Sheets[0];

    // Authored note on the adjusted figure
    Sheet.AddComment(14, 4, 'Manual adjustment: late FX rate, see ticket FIN-2214',
      'recon-service');

    // Update an existing note instead of stacking a second one
    Note := Sheet.Comments.FindAt(14, 4);
    if Note <> nil then
      Note.Text := Note.Text + ' [verified 2026-06-11]';

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

Iskanje s pomočjo FindAt ima večji pomen, kot se zdi na prvi pogled. Paketno opravilo, ki se ponovno zažene po prehodni napaki, bo brez težav znova poklicalo AddComment na celici, ki jo je že označilo, rezultat pa bosta dve naloženi opombi na isti celici. Najprej preverite z metodo FindAt in posodobite vrnjeni objekt. Zbirka Comments izpostavlja tudi metodi DeleteAt in DeleteInRange. Različica z obsegom (range) je idealna, ko želite očistiti delovni zvezek pred pošiljanjem iz podjetja: odstranjevanje notranjih opomb QA iz celotnega območja se izvede z enim klicem namesto z ročno napisano zanko čez celice.

Zunanje povezave URL in notranji skoki v delovnem zvezku so različni API-ji

OOXML hrani obe vrsti povezav na različnih mestih. Zunanji URL postane vnos relacije v delu .rels delovnega lista, celica pa kaže na to relacijo prek ID-ja. Notranji skok se sploh ne dotakne relacijske plasti; gre za preprost niz lokacije, kot je Summary!A1, shranjen neposredno v povezavi. HotXLS ohranja to razlikovanje vidno v API-ju, namesto da bi preobremenil eno samo metodo, kar pomeni, da izberete pravi klic tako, da veste, kje se cilj nahaja:

Sheet.Cells[2, 1].Value := 'Source record';
Sheet.AddHyperlink(2, 1, 'https://intranet.example.com/records/2214',
  'Open record 2214', 'ERP source entry');

Sheet.Cells[3, 1].Value := 'Totals';
Sheet.AddHyperlinkToCell(3, 1, 'Overview!B12', 'Jump to totals');

Na ustvarjenem objektu TXLSXHyperlink sta lastnosti Url in Location medsebojno izključujoči, IsInternal pa pove, katera od njiju je izpolnjena. To zastavico preverite, ko popisujete povezave v odprtem delovnem zvezku in morate "zunanje" ter "notranje" povezave obravnavati po različnih pravilih: zunanji gostitelj je lahko predmet dovoljenega seznama (allowlist) shem in gostiteljev, medtem ko mora notranji cilj le poimenovati obstoječi list. Notranje povezave nimajo relacijskih delov v ozadju, zato je tudi njihovo množično prepisovanje enostavnejše.

Okvara iz uvoda se v celoti nanaša na notranjo stran in izhaja iz dejstva, da niz lokacije ni razčlenjen sklic. HotXLS zapiše natanko tisto besedilo, ki mu ga posredujete, in nič ne spremeni tega besedila, če je list pozneje preimenovan. V praksi delujeta dve zaščiti. Prva je disciplina pri vrstnem redu: preimenujte vsak list pred generiranjem prve povezave, nato pa obravnavajte imena listov kot zamrznjene identifikatorje. Druga zaščita je zanesljivejša in preživi naknadna preimenovanja: povezavo usmerite na poimenovano območje (defined name) na ravni delovnega zvezka namesto na naslov Sheet!Cell, saj Excel posodobi definicijo poimenovanega območja ob spremembi delovnega lista, tako da se povezava posodobi samodejno. Ta drugi pristop se odlično dopolnjuje s tehnikami v članku poimenovana območja in medlistne formule v HotXLS.

Stran XLS: enaki koncepti, starejši mehanizmi

Vmesnik BIFF8 pripenja komentarje na obsege (ranges) namesto na zbirko na ravni delovnega lista. Funkcijo AddComment pokličete na vmesniku IXLSRange in prejmete TXLSComment; lastnost Comment obsega prebere obstoječo opombo, ClearComments pa jih izbriše. Ostra meja tukaj je položajna. TXLSComment ne izpostavlja javno svoje vrstice in stolpca, zato običajna zanka "pregled vsakega komentarja in poročanje o njegovem mestu" deluje v nasprotni smeri API-ja. Začeti morate pri celicah. Revizijo vodite na podlagi seznama naslovov, ki ste jih označili, ali pa med pisanjem vodite lasten dnevnik položajev, saj vam objekt komentarja pozneje ne bo povedal, kje se nahaja.

var
  Book: IXLSWorkbook;
  Sheet: IXLSWorksheet;
  Remark: TXLSComment;
begin
  Book := TXLSWorkbook.Create;
  Sheet := Book.Sheets.Add;
  Sheet.Name := 'Review';
  Sheet.Cells.Item[5, 2].Value := 4821.50;

  Remark := Sheet.Cells.Item[5, 2].AddComment('Awaiting sign-off from controller');
  Remark.Visible := True;   // pop the note open on first view

  Sheet.AddHyperlink(7, 2, 'https://intranet.example.com/signoff/4821',
    'Sign-off form', 'Opens the controller queue');
  Book.SaveAs('review.xls');
end;

Nastavitev lastnosti Visible na True je klasičen način, da opombe ni mogoče spregledati: rumeno polje ostane odprto na listu in ne čaka na usmeritev kazalca miške. TXLSComment gre korak dlje od različice XLSX, saj izpostavlja TextRuns, kar pomeni, da lahko ena opomba vsebuje krepko opozorilo poleg navadnega pojasnila, česar API za XLSX ne ponuja na enak način. Hipertekstne povezave na tej strani potekajo prek treh zaporednih preobremenitev (le naslov, nato z besedilom za prikaz, nato še z namigom zaslona) in se berejo prek zbirke HyperLinks delovnega lista, kjer vsaka povezava ponuja Address, SubAddress, DisplayText in ScreenTip.

Kazalni list za pregled je boljši od razpršenih opomb

Ko število opomb preseže ducat, branje ob prehodu z miško postane neobvladljivo. Opombe se kopičijo na listih, ki jih ocenjevalec morda nikoli ne odpre, tiste najpomembnejše pa so pogosto spregledane. Struktura, ki se je v praksi izkazala za najboljšo, je ustvarjen kazalni list (index sheet): ena vrstica za vsako označeno mesto, ki navaja ime lista, naslov celice, avtorja in kratek izvleček opombe. Zadnji stolpec vsebuje notranjo povezavo, zgrajeno s funkcijo AddHyperlinkToCell, ki skoči neposredno na označeno celico. Tako ocenjevalec pregleduje urejen seznam, namesto da bi iskal po mrežah, število vrstic v kazalu pa služi kot popis komentarjev za revizijski korak.

Gradnja kazala je enostavna, saj vaš generator že pozna vsak položaj, ki ga je spremenil. Med pisanjem vsakega komentarja dodajte nabor (list, vrstica, stolpec, avtor, povzetek) na seznam, nato pa kazalni list ustvarite na koncu, da je število vrstic pred shranjevanjem dokončno. Dve izboljšavi sta še posebej koristni: uredite kazalo po pomembnosti ali po listu in ne po vrstnem redu vstavljanja, v glavo kazala pa dodajte povratno povezavo, da se ocenjevalec po pregledu posameznega elementa lahko vrne na vrh. Ker so notranje povezave navadni nizi lokacij brez relacijske plasti v ozadju, celo kazalo z tisoč vrsticami skoraj ne vpliva na velikost datoteke ali čas shranjevanja.

Isti list se obrestuje tudi ob povratku dokumenta. Ko prejmete pregledan delovni zvezek nazaj, lahko vaša koda prebere vrednosti stanja, vpisane v celice poleg vrstic kazala, namesto da bi ponovno pregledovala vsak list za spremenjenimi komentarji. Stolpec strukturiranih celic stanja se razčleni čisto; razpršeni komentarji z prostim besedilom pa ne.

Revizijski prehod pred dostavo, ki dejansko zazna napake

Nobeden od teh API-jev ne preverja cilja. Povezava na list, ki ste ga izbrisali, napačno zapisano ime intranetnega strežnika ali ukinjena skupna raba datotek: vse to se shrani brez opozorila. Standard ECMA-376 določa le, kako se povezava shranjuje, ne pa, ali deluje. Delovni zvezek, ki vsebuje metapodatke o pregledu, si zato zasluži kratek lasten revizijski korak pred klicem SaveAs:

  • Zberite vsako notranjo lokacijo, zapisano med generiranjem, in preverite, ali ime delovnega lista pred klicajem še vedno obstaja v zbirki listov delovnega zvezka.
  • Preverite zunanje URL-je glede na dovoljeni seznam (allowlist) shem in gostiteljev. Goli naslovi file:// in poti UNC lahko razkrijejo podrobnosti o okolju ter prenehajo delovati, takoj ko datoteka zapusti vaše omrežje.
  • Preštejte komentarje na posameznem listu in jih primerjajte s tem, kar je nameraval zapisati vaš generator. Ponovni poskus, ki je podvojil opombe, se bo pokazal tukaj in ne v mapi prejemnika.
  • Odstranite opombe, ki so namenjene le interni uporabi, s pomočjo DeleteInRange, kadar prejemnik ni član vaše organizacije.

Ekipe, ki gradijo svoje delovne zvezke iz podatkovne plasti, lahko ta korak vključijo v isti del cevovoda, ki už validira podatke, tako da se pregled metapodatkov izvede brezplačno. Postopek je enak tistemu, ki je opisan v članku izvoz rezultatov poizvedb podatkovne baze v Excelova poročila, le da je usmerjen na povezave in komentarje namesto na same vrstice.

Ena podrobnost pri navednicah pogosto povzroča težave pri ročnem sestavljanju nizov lokacij. List, katerega ime vsebuje presledek, mora biti znotraj lokacije zapisan v enojnih navednicah, natanko tako, kot se to izvede v vrstici za formule: 'Quarterly Totals'!A1 in ne Quarterly Totals!A1. HotXLS uveljavlja enaka pravila, kot jih uporablja mehanizem formul za medlistne sklice; če torej povezava deluje v formuli delovnega lista, bodo navednice delovale tudi tukaj. Če posredujete necitirano ime s presledkom, boste dobili enako tiho nedelujočo povezavo, na katero opozarja uvod.

Komentarji in povezave so deli ustvarjenega delovnega zvezka, po katerih ocenjevalci brskajo brez oklevanja, zato povezava, ki ne kaže nikamor, povzroči škodo, še preden jo kdo opazi. Enkrat zgradite korak za validacijo, ga zaženite na vsakem delovnem zvezku pred odpremo in potek pregleda bo ostal nemoten kljub preimenovanjem in pretvorbam. Celotna površina API-ja za XLS in XLSX je dokumentirana na strani izdelka HotXLS Component.