Teknisk artikkel

Excel-cellekommentarer og hyperkoblinger i Delphi med HotXLS

Gi et ark nytt navn fra «Summary» til «Overview» i en generert arbeidsbok, og hver interne hyperlenke som pekte på Summary!A1 slutter å føre noe sted. Ingen unntak ved lagring, ingen ved åpning. Lenken vises fortsatt, ser fortsatt klikkbar ut, og løser seg stille til ingenting. Samme type sammenbrudd dukker opp etter en lagre-som-konvertering eller en tur-retur mellom .xls og .xlsx, når en kommentar havner en kolonne feil eller en relativ lenke mister målet sitt. Begge funksjonene bærer gjennomgangstilstand som virkelige mennesker handler ut fra, så når de går i stykker er feilen usynlig helt til en gjennomgår klikker og ingenting skjer

Det er den praktiske grunnen til at kommentarer og hyperlenker fortjener mer omtanke enn det kosmetiske utseendet deres skulle tilsi. HotXLS gir Delphi- og C++Builder-kode direkte skrivetilgang til begge, i XLS og XLSX, uten Excel-automatisering i løkken. Baksiden av denne kontrollen er ansvar: biblioteket skriver nøyaktig de målene du gir det og validerer ingen av dem, så det å holde en gjennomgangsflyt intakt er koden din sin jobb, ikke Excels

Cellekommentarer som maskinskrevne gjennomgangsposter

I XLSX-klassemodellen er en kommentar et objekt på arknivå: den kjenner sin rad, sin kolonne, en forfatter og en tekstkropp. Forfatterfeltet fortjener sin plass. Når en arbeidsbok koden din genererte, vandrer gjennom en gjennomgangskjede, er det første spørsmålet en revisor stiller hvem som skrev en gitt note, og en note uten forfatter besvarer det spørsmålet med et tomrom. Merk genererte kommentarer med en tjenesteidentitet slik at opphavet aldri er tvetydig

Diagram over et Delphi HotXLS kommentarforsøk på nytt der en FindAt-sonde oppdaterer det eksisterende cellenotatet, mens et blint AddComment-forsøk stabler en duplikat
Et nytt forsøk som kaller AddComment blindt stabler en andre notis på samme celle, mens FindAt-proben redigerer notisen som allerede er der
var
  Book: TXLSXWorkbook;
  Sheet: TXLSXWorksheet;
  Note: TXLSXComment;
begin
  Book := TXLSXWorkbook.Create;
  try
    Book.Open('reconciliation.xlsx');
    Sheet := Book.Sheets[0];

    // Signert note på det justerte tallet
    Sheet.AddComment(14, 4, 'Manual adjustment: late FX rate, see ticket FIN-2214',
      'recon-service');

    // Oppdater en eksisterende note i stedet for å stable en til
    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;

FindAt-sondringen veier tyngre enn den ser ut til. En batchjobb som prøver på nytt etter en forbigående feil, vil uten videre kalle AddComment en gang til på en celle den allerede har notert, og cellen ender opp med to stablede notater som ingen ba om. Sond med FindAt først, og oppdater objektet den returnerer. Comments-samlingen eksponerer også DeleteAt og DeleteInRange. Den områdevarianten er den du griper til når du renser en arbeidsbok før den forlater bygningen: å fjerne interne QA-annotasjoner fra et helt område er ett enkelt kall i stedet for en håndskrevet løkke over celler

Eksterne URL-er og interne hopp i arbeidsboken er forskjellige API-er

OOXML holder de to lenketypene på forskjellige steder. En ekstern URL blir en relasjonsoppføring i arkets .rels-del, med cellen som peker på relasjonen via en id. Et internt hopp berører aldri relasjonslaget i det hele tatt; det er en ren posisjonsstreng som Summary!A1 lagret direkte på lenken. HotXLS holder det skillet synlig i API-et i stedet for å overbelaste én enkelt metode, noe som betyr at du velger riktig kall ved å vite hvor målet befinner seg:

Diagram som setter hvordan HotXLS lagrer en ekstern URL som en relasjon i rels-delen, mot et internt hopp som en enkel plasseringsstreng i Delphi-genererte arbeidsbøker
En ekstern URL reiser gjennom relasjonslaget mens et internt hopp er ren tekst, så hver slags feiler på sin egen måte og trenger sin egen kontrollregel
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');

På det resulterende TXLSXHyperlink-objektet er Url og Location gjensidig utelukkende, og IsInternal forteller deg hvilken av de to som er fylt ut. Det flagget er det du sjekker når du inventarerer lenkene i en åpnet arbeidsbok og må behandle «forlater filen» og «blir i filen» etter forskjellige regler: en ekstern vert kan møte en tillatelsesliste mens et internt mål bare må navngi et ark som finnes. Interne lenker har ingen relasjonsdeler bak seg, noe som også gjør dem billigere å skrive om i bulk

Sammenbruddet fra innledningen ligger helt på den interne siden, og det følger av ett faktum: en posisjonsstreng er ikke en analysert referanse. HotXLS skriver nøyaktig den teksten du gir den, og ingenting peker teksten om når et ark får nytt navn senere. To forsvar holder i praksis. Det første er disiplin rundt rekkefølge: gi alle ark nytt navn før du genererer en eneste lenke, og behandle deretter arknavn som fastfrosne identifikatorer. Det andre er sterkere og overlever navnebytter gjort i etterkant. Pek lenken mot et definert navn på arbeidsboknivå i stedet for en rå Sheet!Cell-adresse, fordi Excel skriver om definisjonen til et navn når det underliggende arket endres, slik at lenken automatisk følger med. Den andre tilnærmingen passer naturlig sammen med teknikkene i definerte navn og arkkryssende formler i HotXLS

XLS-siden: samme konsepter, eldre rørsystem

BIFF8-fasaden henger kommentarer på områder i stedet for en samling på arknivå. Du kaller AddComment på et IXLSRange og får tilbake et TXLSComment; områdets Comment-egenskap leser en eksisterende note, og ClearComments fjerner dem. Den skarpe kanten her er posisjonell. Et TXLSComment eksponerer ikke offentlig sin egen rad og kolonne, så den naturlige løkken, «gå gjennom hver kommentar og rapporter hvor den sitter», går baklengs mot API-et. Du må starte fra cellene. Enten kjører du revisjonen fra listen over adresser du har notert, eller så fører du din egen posisjonslogg mens du skriver, fordi kommentarobjektet ikke vil fortelle deg i ettertid hvor det befinner seg

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;   // sprett opp noten ved første visning

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

Å sette Visible til True er den gamle måten å gjøre en note umulig å overse på: den gule boksen blir stående åpen på arket i stedet for å vente på en hover. TXLSComment går et skritt lenger enn sin XLSX-motpart ved å eksponere TextRuns, slik at en enkelt note kan bære en uthevet advarsel ved siden av en vanlig forklaring, formatering XLSX-kommentar-API-et ikke eksponerer på samme måte. Hyperlenker på denne siden kommer gjennom tre gradvise overbelastninger (bare adresse, deretter med visningstekst, deretter med et skjermtips) og leses tilbake gjennom arkets HyperLinks-samling, der hver lenke viser Address, SubAddress, DisplayText og ScreenTip

Et gjennomgangsindeksark slår spredte notater

Forbi et titalls annotasjoner slutter hover-og-les stille å skalere. Notater hoper seg opp på ark en gjennomgår aldri åpner, og de som betyr mest, er nettopp de som er lettest å overse. Strukturen som har holdt seg best, er et generert indeksark: én rad per annotert plassering, som lister arknavn, celleadresse, forfatter og et kort utdrag av noten. Den siste kolonnen bærer en intern hyperlenke bygget med AddHyperlinkToCell som hopper rett til den annoterte cellen. Nå leser gjennomgåeren nedover en liste i stedet for å lete over et rutenett, og radantallet i den indeksen fungerer samtidig som kommentarinventaret ditt for revisjonsrunden nedenfor

Indeksen er billig å bygge fordi generatoren din allerede kjenner hver posisjon den har berørt. Legg til en (ark, rad, kolonne, forfatter, sammendrag)-tuppel i en liste mens du skriver hver kommentar, og send deretter ut indeksarket sist slik at radantallet er endelig før du lagrer. To forbedringer lønner seg: sorter indeksen etter alvorlighetsgrad eller etter ark i stedet for etter innsettingsrekkefølge, og legg en returlenke i indeksens topptekst slik at en gjennomgår kan hoppe tilbake til toppen etter hvert punkt. Fordi interne lenker er rene posisjonsstrenger uten noe i relasjonslaget bak seg, legger selv en indeks på tusen rader nesten ingenting til filstørrelse eller lagringstid

Det samme arket lønner seg igjen på returen. Når den gjennomgåtte arbeidsboken kommer tilbake, leser koden din statusverdier skrevet inn i celler ved siden av indeksradene i stedet for å skanne hvert ark på nytt etter kommentarer som kan ha endret seg. En kolonne med strukturerte statusceller parses rent; en spredning av fritekstnotater gjør det ikke

En revisjonsrunde før levering som faktisk fanger sammenbruddet

Ingen av disse API-ene validerer et mål. En lenke til et ark du slettet, en feilstavet intranettvert, en fildeling som ble avviklet forrige kvartal: alle lagrer uten en lyd. ECMA-376 spesifiserer hvordan en lenke lagres, ikke at den løser seg til noe. En arbeidsbok som bærer gjennomgangsmetadata, fortjener derfor et kort eget revisjonstrinn, kjørt rett før SaveAs:

Diagram over HotXLS forhåndsleverings-revisjonspass som sjekker interne mål, URL tillatelseslister, kommentarantall og mottakerskrubbing før SaveAs i Delphi
Fire kontroller kjøres like før SaveAs, og hver eneste av dem fanger en feil biblioteket selv aldri vil utløse
  • Samle inn hver interne posisjon skrevet under generering og bekreft at arknavnet foran utropstegnet fortsatt finnes i arbeidsbokens arksamling
  • Sjekk eksterne URL-er mot en tillatelsesliste for skjemaer og verter. Rene file://- og UNC-baner lekker miljødetaljer og brytes i det øyeblikket filen forlater nettverket ditt
  • Tell kommentarer per ark og sammenlign med det generatoren din hadde til hensikt å skrive. Et nytt forsøk som doblet notatene, dukker opp her i stedet for i gjennomgåerens innboks
  • Fjern rent interne annotasjoner med DeleteInRange når mottakeren befinner seg utenfor organisasjonen

Team som bygger arbeidsbøkene sine fra et datalag, kan folde dette trinnet inn i det samme pipeline-steget som allerede validerer dataene, slik at metadatasjekken følger med gratis. Mekanikken er den samme som beskrives i eksport av databasespørringsresultater til Excel-rapporter, bare vendt mot lenker og kommentarer i stedet for rader

Én detalj om anførselstegn snubler folk når de bygger posisjonsstrenger for hånd. Et ark hvis navn inneholder et mellomrom, må stå i anførselstegn inne i posisjonen, akkurat slik formellinjen setter det i anførselstegn: 'Quarterly Totals'!A1, ikke Quarterly Totals!A1. HotXLS bruker de samme reglene som formelmotoren bruker for arkkryssende referanser, så hvis en lenke fungerer i en arkformel, vil anførselen fungere her også. Gi den et navn med mellomrom uten anførselstegn, og du får den samme stille døde lenken innledningen advarte om

Kommentarer og hyperlenker er delene av en generert arbeidsbok som gjennomgåere handler ut fra uten et sekund blikk, og det er nettopp derfor et mål som peker på ingenting, gjør reell skade før noen merker det. Bygg valideringsrunden én gang, kjør den på hver arbeidsbok før den sendes, og gjennomgangsflyten forblir intakt gjennom navnebytter og konverteringer. Hele API-overflaten for både XLS- og XLSX-fasadene er dokumentert på produktsiden for HotXLS Delphi Component