Technical Article

„Excel“ langelių komentarai ir nuorodos „Delphi“ programoje su „HotXLS“

Pakeiskite darbalapio pavadinimą iš „Summary“ į „Overview“ sugeneruotoje knygoje, ir kiekviena vidinė nuoroda, rodanti į Summary!A1, nustos veikti. Nėra jokių klaidų pranešimų nei išsaugant failą, nei jį atidarant. Nuoroda vis tiek bus matoma, atrodys spustelėjama, tačiau tyliai niekur neves. Panašus sugadinimas atsiranda po konvertavimo į kitą formatą arba XLS/XLSX perkėlimo procesų, kai komentaras pasislenka stulpeliu į šalį arba santykinė nuoroda praranda savo tikslinį adresą. Abi šios funkcijos atlieka svarbų vaidmenį dokumentų peržiūros procese, kuriuo remiasi realūs žmonės, todėl jų sugadinimas lieka nepastebimas iki to momento, kol kas nors spustelėja nuorodą ir nieko neįvyksta.

Tai yra praktinė priežastis, kodėl komentarams ir nuorodoms reikėtų skirti daugiau dėmesio, nei reikalauja jų vizualinė išvaizda. „HotXLS“ suteikia „Delphi“ ir „C++Builder“ kūrėjams tiesioginę rašymo prieigą prie abiejų elementų tiek XLS, tiek XLSX formatuose be jokio „Excel“ automatizavimo (COM objektų). Šios kontrolės kita pusė yra atsakomybė: biblioteka įrašo tiksliai tuos adresus, kuriuos jai pateikiate, ir jų netikrina. Todėl peržiūros proceso vientisumo išsaugojimas yra jūsų kodo užduotis, o ne „Excel“.

Langelių komentarai kaip automatiškai įrašomi peržiūros įrašai

XLSX klasių modelyje komentaras yra darbalapio lygio objektas: jis turi savo eilutę, stulpelį, autorių ir teksto turinį. Autoriaus laukelis yra labai svarbus. Kai jūsų kodo sugeneruota knyga keliauja per peržiūros grandinę, pirmasis auditoriaus klausimas yra, kas parašė konkrečią pastabą. O pastaba be autoriaus palieka šį klausimą be atsakymo. Pažymėkite sugeneruotus komentarus paslaugos identiškumu, kad kilmė niekada nebūtų dviprasmiška.

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;

Metodas FindAt atlieka svarbesnį darbą nei atrodo iš pirmo žvilgsnio. Automatizuota užduotis, kuri paleidžiama iš naujo po laikino gedimo, vėl iškvies AddComment tam pačiam langeliui, kurį jau buvo pažymėjusi. Dėl to langelyje atsiras du vienas ant kito sukrauti komentarai, kurių niekas neprašė. Pirmiausia atlikite patikrą su FindAt ir atnaujinkite grąžintą objektą. Comments kolekcija taip pat palaiko DeleteAt ir DeleteInRange funkcijas. Diapazono trynimo variantas naudingas prieš išsiunčiant darbalapį iš įmonės: vidinių pastabų išvalymas iš viso regiono atliekamas vienu iškvietimu, užuot sukant rankinį ciklą per langelius.

Išorinės nuorodos ir vidiniai šuoliai yra skirtingi API

OOXML laiko šiuos du nuorodų tipus skirtingose vietose. Išorinis URL tampa sąryšio įrašu (angl. relationship entry) darbalapio „.rels“ dalyje, o langelis rodo į šį sąryšį pagal ID. Vidinė nuoroda niekada neliečia sąryšių sluoksnio, ji yra saugoma tiesiogiai kaip teksto eilutė (pavyzdžiui, Summary!A1) pačioje nuorodoje. „HotXLS“ išlaiko šį skirtumą API lygmenyje, užuot perkrovusi vieną metodą. Tai reiškia, kad pasirenkate tinkamą iškvietimą žinodami, kur yra jūsų taikinys:

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');

Gautame TXLSXHyperlink objekte savybės Url ir Location yra tarpusavyje nesuderinamos (užpildoma tik viena), o savybė IsInternal parodo, kuri iš jų yra aktyvi. Šią vėliavėlę tikrinate kurdami nuorodų sąrašą atidarytoje knygoje, kai reikia skirtingai apdoroti vidines ir išorines nuorodas. Išoriniams adresams gali būti taikomas patikimų svetainių sąrašas, o vidiniams – tik reikalavimas nurodyti egzistuojantį lapą. Vidinės nuorodos neturi sąryšio elementų fone, todėl jas galima greičiau ir pigiau perrašyti dideliais kiekiais.

Pradžioje minėtas sugadinimas vyksta tik vidinėje pusėje ir kyla iš vieno fakto: vietos eilutė nėra automatiškai atnaujinama nuoroda. „HotXLS“ įrašo tikslų tekstą, kurį jai nurodote, ir joks mechanizmas neatnaujins šios vietos eilutės vėliau pakeitus lapo pavadinimą. Praktiškai padeda dvi apsaugos priemonės. Pirmoji – griežta procesų tvarka: pakeiskite visų lapų pavadinimus prieš sukurdami bet kokią nuorodą, o po to laikykite juos nekintamais. Antroji apsauga yra patikimesnė ir išlieka po pavadinimų keitimo: nukreipkite nuorodą į knygos lygio pavadintą sritį (angl. defined name), o ne į konkretų Sheet!Cell adresą. Kadangi „Excel“ pati atnaujina pavadintos srities apibrėžimą pakeitus lapo pavadinimą, nuoroda bus nukreipta teisingai automatiškai. Šis metodas aprašytas straipsnyje pavadintos sritys ir tarpusavio darbalapių formulės su HotXLS.

XLS pusė: tos pačios sąvokos, senesnė struktūra

BIFF8 formatu komentarai yra susieti su langelių rėžiais (angl. ranges), o ne su darbalapio lygio kolekcija. Iškviečiate AddComment objektui IXLSRange ir gaunate TXLSComment. Šio rėžio savybė Comment nuskaito esamą pastabą, o ClearComments jas ištrina. Sunkumas čia yra pozicinis. TXLSComment objektas viešai neparodo savo eilutės ir stulpelio, todėl ciklas „pereiti visus komentarus ir pranešti, kur jie yra“ neveikia tiesiogiai. Turite pradėti nuo pačių langelių. Vykdykite auditą pagal adresų sąrašą, kurį patys pažymėjote, arba registruokite pozicijas rašymo metu, nes pats komentaro objektas vėliau nepasakys, kur jis yra įterptas.

var
  Book: IXLSWorkbook;
  Sheet: IXLSWorksheet;
  Remark: TXLSComment;
begin
  Book := IXLSWorkbook.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;

Savybės Visible nustatymas į True yra senasis būdas užtikrinti, kad pastaba nebūtų praleista: geltonas laukelis lieka atidarytas, užuot laukęs, kol vartotojas užves pelę virš jo. TXLSComment eina dar toliau nei jo XLSX atitikmuo ir leidžia naudoti TextRuns. Tai reiškia, kad viena pastaba gali turėti paryškintą perspėjimą šalia paprasto paaiškinimo – šio formato XLSX komentaro API nepalaiko tokiu pačiu būdu. Nuorodos šioje pusėje pateikiamos per tris skirtingus metodus (tik adresas, su rodomu tekstu, su ekrano paaiškinimu) ir skaitomos per darbalapio HyperLinks kolekciją, kur kiekviena nuoroda pateikia Address, SubAddress, DisplayText ir ScreenTip.

Peržiūros nuorodų lapas yra geriau nei išmėtyti komentarai

Kai komentarų skaičius viršija keliolika, jų skaitymas užvedant pelę tampa nepatogus. Pastabos gali likti lapuose, kurių vartotojas niekada neatidarys, o svarbiausios pastabos bus lengviausiai praleidžiamos. Geriausia praktika pasirodė esantis sugeneruotas nuorodų lapas (angl. index sheet): viena eilutė kiekvienam komentarui su lapo pavadinimu, langelio adresu, autoriumi ir trumpa pastabos santrauka. Paskutinis stulpelis turi vidinę nuorodą, sukurtą per AddHyperlinkToCell, kuri leidžia pereiti tiesiai į komentarą turintį langelį. Dabar vartotojas gali skaityti visą sąrašą vienoje vietoje, užuot ieškojęs komentarų visame faile.

Tokį sąrašą sukurti yra labai paprasta, nes jūsų programa jau žino kiekvieną vietą, kurią ji pažymėjo. Rašydami kiekvieną komentarą, pridėkite informaciją (lapas, eilutė, stulpelis, autorius, santrauka) į sąrašą, o peržiūros lapą sugeneruokite pačioje pabaigoje prieš išsaugant failą. Du patarimai: surūšiuokite sąrašą pagal svarbą arba darbalapį, o ne pagal įrašymo tvarką, ir įdėkite grįžimo nuorodą peržiūros lapo pradžioje, kad vartotojas galėtų lengvai sugrįžti atgal. Kadangi vidinės nuorodos yra tik paprasti tekstiniai adresai, toks lapas beveik nepadidina failo dydžio ar išsaugojimo laiko.

Tas pats lapas praverčia ir atgaliniam procesui. Kai patikrintas failas sugrįžta, jūsų kodas nuskaito būsenas, įrašytas šalia peržiūros eilučių, užuot iš naujo skenavęs visus lapus ieškant komentarų pakeitimų. Stulpelis su struktūrizuotomis būsenomis nuskaitomas lengvai, o laisvų komentarų tekstas nėra.

Patikros procesas prieš failo išsiuntimą

Nė vienas iš šių API neatlieka tikslinio adreso tikrinimo. Nuoroda į ištrintą lapą, klaidingas svetainės adresas ar neveikiantis vidinio tinklo kelias – visi jie bus išsaugoti be jokių perspėjimų. ECMA-376 specifikacija nurodo tik tai, kaip nuoroda turi būti saugoma, o ne tai, ar ji veikia. Tačiau ataskaita su peržiūros metaduomenimis reikalauja papildomo patikros etapo prieš iškviečiant SaveAs:

  • Surinkite visus vidinius adresus ir patikrinkite, ar lapas prieš šauktuko ženklą vis dar egzistuoja knygos lapų kolekcijoje.
  • Patikrinkite išorines nuorodas pagal patikimų svetainių sąrašą. Paprasti file:// ir UNC keliai gali atskleisti vidinio tinklo struktūrą ir nustos veikti failui iškeliavus už jūsų tinklo ribų.
  • Palyginkite komentarų skaičių darbalapyje su planuotu kiekiu. Pakartotinis užduoties paleidimas, sukūręs dvigubus komentarus, bus pastebėtas čia.
  • Pašalinkite vidinius komentarus naudodami DeleteInRange, jei dokumentas siunčiamas išoriniam gavėjui.

Kūrėjai, kurie ataskaitas kuria tiesiai iš duomenų sluoksnio, gali lengvai įtraukti šį etapą į tą patį kodo žingsnį, kuris tikrina duomenų teisingumą. Šie metodai aprašyti straipsnyje duomenų bazės užklausų rezultatų eksportavimas į „Excel“ ataskaitas, pritaikant juos nuorodoms ir komentarams.

Viena kabučių naudojimo detalė gali sukelti problemų kuriant adresus rankiniu būdu. Lapo pavadinimas, kuriame yra tarpas, nuorodoje turi būti apgaubtas viengubomis kabutėmis, tiksliai taip pat, kaip formulėse: 'Quarterly Totals'!A1, o ne Quarterly Totals!A1. „HotXLS“ naudoja tas pačias taisykles kaip ir formulių variklis, todėl jei nuoroda veikia darbalapio formulėje, ji veiks ir čia. Perdavus pavadinimą su tarpu be kabučių gausite neveikiančią nuorodą, apie kurią įspėjome pradžioje.

Komentarai ir nuorodos yra tie elementai, kuriais vartotojai naudojasi negalvodami, nes neveikianti nuoroda daro realią žalą dar prieš ją pastebint. Sukurkite patikros žingsnį vieną kartą, paleiskite jį kiekvienai knygai prieš išsiunčiant, ir peržiūros procesas išliks stabilus po visų pakeitimų ir konvertavimų. Pilną XLS ir XLSX sąsajų API aprašymą rasite „HotXLS Component“ produkto puslapyje HotXLS Component.