Tekninen artikkeli

Excel-solujen kommentit ja hyperlinkit Delphissä HotXLS:n avulla

Kun luodussa työkirjassa nimetään välilehti "Summary" uudelleen nimellä "Overview", jokainen sisäinen hyperlinkki, joka osoitti kohteeseen Summary!A1, lakkaa johtamasta minnekään. Tallennuksessa tai avauksessa ei tule poikkeusta. Linkki näkyy yhä, näyttää edelleen napsautettavalta ja ratkeaa hiljaa tyhjyyteen. Samanlainen rikkoutuminen ilmenee tallenna nimellä -muunnoksen tai .xls/.xlsx-tallennuskierroksen jälkeen, kun kommentti päätyy sarakkeen verran sivuun tai suhteellinen linkki menettää kohteensa. Molemmat ominaisuudet kuljettavat tarkistustilaa, jonka perusteella oikeat ihmiset toimivat, joten niiden rikkoutuminen jää näkymättömäksi, kunnes tarkastaja napsauttaa linkkiä eikä mitään tapahdu

Tästä käytännön syystä kommentit ja hyperlinkit ansaitsevat enemmän huomiota kuin niiden kosmeettinen ulkoasu antaa ymmärtää. HotXLS antaa Delphi- ja C++Builder-koodille suoran kirjoitusoikeuden kumpaankin XLS- ja XLSX-muodossa ilman Excel-automaatiota. Hallinnan kääntöpuoli on vastuu: kirjasto kirjoittaa täsmälleen ne kohteet, jotka sille annetaan, eikä vahvista niistä yhtäkään. Tarkistustyönkulun säilyttäminen ehjänä on siis koodisi tehtävä, ei Excelin

Solukommentit koneella kirjoitettuina tarkistusmerkintöinä

XLSX-luokkamallissa kommentti on laskentataulukkotason objekti: se tietää rivinsä, sarakkeensa, kirjoittajansa ja tekstirunkonsa. Kirjoittajakenttä ansaitsee paikkansa. Kun koodisi luoma työkirja kulkee tarkistusketjun läpi, ensimmäinen tarkastajan esittämä kysymys on, kuka tietyn merkinnän kirjoitti. Kommentti ilman kirjoittajaa vastaa tähän kysymykseen tyhjällä arvolla. Merkitse luodut kommentit palvelutunnisteella, jotta alkuperä ei jää koskaan epäselväksi

Kaavio Delphi HotXLS -kommentin uudelleenyrityksestä, jossa FindAt-kysely päivittää olemassa olevan soluhuomautuksen, kun taas sokea AddComment-yritys pinoaa kaksoiskappaleen
Uudelleenyritys, joka kutsuu AddComment-sokeasti, pinoaa toisen muistiinpanon samalle solulle, kun taas FindAt-koe muokkaa sitä muistiinpanoa, joka on jo siellä
var
  Book: TXLSXWorkbook;
  Sheet: TXLSXWorksheet;
  Note: TXLSXComment;
begin
  Book := TXLSXWorkbook.Create;
  try
    Book.Open('reconciliation.xlsx');
    Sheet := Book.Sheets[0];

    // Laadittu huomautus oikaistusta luvusta
    Sheet.AddComment(14, 4, 'Manual adjustment: late FX rate, see ticket FIN-2214',
      'recon-service');

    // Päivitä olemassa oleva huomautus toisen lisäämisen sijaan
    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-tarkistus on painavampi kuin miltä se näyttää. Eräajo, joka yrittää uudelleen tilapäisen virheen jälkeen, kutsuu mielellään AddComment-metodia toisen kerran solulle, johon se on jo lisännyt merkinnän. Soluun päätyy kaksi päällekkäistä kommenttia, joita kukaan ei pyytänyt. Tarkista ensin FindAt-metodilla ja päivitä sen palauttama objekti. Comments-kokoelma tarjoaa myös DeleteAt- ja DeleteInRange-metodit. Alueversio on oikea valinta, kun puhdistat työkirjan ennen kuin se lähtee organisaatiosta: sisäisten QA-merkintöjen poistaminen kokonaiselta alueelta on yksi kutsu käsin kirjoitetun solusilmukan sijaan

Ulkoiset URL-osoitteet ja työkirjan sisäiset siirtymät ovat eri API:t

OOXML säilyttää kahdenlaiset linkit eri paikoissa. Ulkoisesta URL-osoitteesta tulee yhteysmerkintä laskentataulukon .rels-osaan, ja solu osoittaa yhteyteen tunnuksella. Sisäinen siirtymä ei koske yhteystasoa lainkaan, vaan se on pelkkä linkkiin suoraan tallennettu sijaintimerkkijono, kuten Summary!A1. HotXLS pitää tämän eron näkyvissä API:ssa sen sijaan, että se ylikuormittaisi yhden metodin. Valitset oikean kutsun tietämällä, missä kohde sijaitsee:

Kaavio vertailee miten HotXLS tallentaa ulkoisen URL:n suhteena rels-osaan ja sisäisen hypyn pelkistettynä sijaintimerkkijonona Delphillä tuotetuissa työkirjoissa
Ulkoinen URL matkustaa suhdekerroksen kautta, kun taas sisäinen hyppy on pelkkää tekstiä, joten kumpikin laji epäonnistuu omalla tavallaan ja tarvitsee oman auditointisäännön
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');

Luodussa TXLSXHyperlink-oliossa Url ja Location sulkevat toisensa pois, ja IsInternal kertoo, kumpi niistä on täytetty. Tarkista tämä lippu, kun luetteloit avatussa työkirjassa olevia linkkejä ja sinun on käsiteltävä eri säännöillä tiedostosta poistuvaa ja tiedoston sisällä pysyvää linkkiä: ulkoinen isäntä voi olla sallittujen luettelossa, kun taas sisäisen kohteen tarvitsee vain nimetä olemassa oleva välilehti. Sisäisillä linkeillä ei ole taustallaan yhteysosia, joten niiden massamuokkaus on myös kevyempää

Alussa kuvattu rikkoutuminen on kokonaan sisäisten linkkien ongelma ja seuraa yhdestä tosiasiasta: sijaintimerkkijono ei ole jäsennetty viittaus. HotXLS kirjoittaa sille annetun tekstin täsmälleen sellaisenaan, eikä mikään kohdista tekstiä uudelleen, kun välilehti nimetään myöhemmin uudelleen. Käytännössä kaksi suojausta toimivat hyvin. Ensimmäinen on järjestyksen kurinalaisuus: nimeä jokainen välilehti uudelleen ennen kuin luot yhtäkään linkkiä ja käsittele välilehtien nimiä muuttumattomina tunnisteina. Toinen on vahvempi ja selviää jälkikäteen tehdyistä uudelleennimeämisistä. Kohdista linkki työkirjatason määritettyyn nimeen raa'an Sheet!Cell-osoitteen sijaan, koska Excel kirjoittaa nimen määritelmän uudelleen, kun taustalla oleva välilehti muuttuu, jolloin linkki seuraa mukana automaattisesti. Tämä toinen tapa sopii luontevasti yhteen artikkelissa määritetyt nimet ja taulukkojen väliset kaavat HotXLS:ssä kuvattujen tekniikoiden kanssa

XLS-puoli: samat käsitteet, vanhempi putkisto

BIFF8-julkisivu liittää kommentit alueisiin laskentataulukkotason kokoelman sijaan. Kutsut AddComment-metodia IXLSRange-alueella ja saat takaisin TXLSComment-olion. Alueen Comment-ominaisuus lukee olemassa olevan merkinnän ja ClearComments poistaa ne. Hankala kohta on sijainti. TXLSComment ei tarjoa julkisesti omaa riviään ja sarakettaan, joten luonteva silmukka, "käy jokainen kommentti läpi ja ilmoita sen sijainti", toimii API:n suuntaa vastaan. On lähdettävä soluista. Ohjaa tarkistusta joko merkitsemiesi osoitteiden luettelosta tai pidä omaa sijaintilokia kirjoittaessasi, koska kommenttiolio ei kerro jälkikäteen, missä se sijaitsee

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;   // avaa huomautus ensimmäisellä katselukerralla

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

Visible-arvon asettaminen arvoon True on vanha tapa tehdä merkinnästä mahdoton ohittaa: keltainen laatikko pysyy avoinna laskentataulukossa odottamatta osoittimen viemistä sen päälle. TXLSComment menee XLSX-vastinettaan pidemmälle tarjoamalla TextRuns-ominaisuuden, joten yhdessä merkinnässä voi olla lihavoitu varoitus tavallisen selityksen vieressä, kun taas XLSX-kommenttien API ei tarjoa muotoilua samalla tavalla. Tämän puolen hyperlinkit syntyvät kolmella asteittain laajenevalla ylikuormituksella (vain osoite, sitten näyttöteksti ja lopuksi työkaluvihje), ja ne luetaan takaisin laskentataulukon HyperLinks-kokoelmasta, jossa jokainen linkki tarjoaa Address-, SubAddress-, DisplayText- ja ScreenTip-ominaisuudet

Tarkistushakemistovälilehti on parempi kuin hajallaan olevat merkinnät

Kun merkintöjä on yli tusinan verran, osoittamalla lukeminen lakkaa hiljaisesti skaalautumasta. Merkintöjä kasautuu välilehdille, joita tarkastaja ei koskaan avaa, ja tärkeimmät niistä ovat juuri niitä, jotka on helpointa ohittaa. Parhaiten kestänyt rakenne on luotu hakemistovälilehti: yksi rivi jokaista merkittyä sijaintia kohden, jossa luetellaan välilehden nimi, solun osoite, kirjoittaja ja merkinnän lyhyt ote. Viimeinen sarake sisältää AddHyperlinkToCell-kutsulla luodun sisäisen hyperlinkin, joka siirtyy suoraan merkittyyn soluun. Tarkastaja lukee nyt luetteloa ruudukossa etsimisen sijaan, ja hakemiston rivimäärä toimii samalla tarkistuskierroksen kommenttiluettelona

Hakemiston luominen on edullista, koska generaattorisi tietää jo jokaisen koskettamansa sijainnin. Lisää luetteloon (välilehti, rivi, sarake, kirjoittaja, yhteenveto) -monikko jokaisen kommentin kirjoituksen yhteydessä ja luo hakemistovälilehti viimeisenä, jotta sen rivimäärä on lopullinen ennen tallennusta. Kaksi parannusta kannattaa: järjestä hakemisto vakavuuden tai välilehden mukaan lisäysjärjestyksen sijaan ja lisää hakemiston otsikkoon paluulinkki, jotta tarkastaja voi palata ylös jokaisen kohteen jälkeen. Koska sisäiset linkit ovat pelkkiä sijaintimerkkijonoja ilman taustalla olevia yhteysosia, jopa tuhannen rivin hakemisto lisää lähes olemattomasti tiedostokokoa tai tallennusaikaa

Sama välilehti tuottaa hyötyä myös paluumatkalla. Kun tarkistettu työkirja palaa, koodisi lukee hakemistorivien viereisiin soluihin kirjoitetut tilaarvot sen sijaan, että se tutkisi kaikki välilehdet uudelleen mahdollisesti muuttuneiden kommenttien varalta. Jäsenneltyjen tilasolujen sarake jäsentyy siististi, hajallaan oleva vapaamuotoisten merkintöjen joukko ei

Ennen toimitusta tehtävä tarkistus, joka todella havaitsee rikkoutumisen

Mikään näistä API:sta ei vahvista kohdetta. Linkki poistettuun välilehteen, väärin kirjoitettu intranet-isäntä tai viime vuosineljänneksellä käytöstä poistettu tiedostojako: ne kaikki tallentuvat ilman minkäänlaista huomautusta. ECMA-376 määrittää, miten linkki tallennetaan, ei sitä, ratkeaako se mihinkään. Tarkistusmetatietoja sisältävä työkirja ansaitsee siis oman lyhyen tarkistusvaiheen juuri ennen SaveAs-kutsua:

Kaavio HotXLS:n toimitusta edeltävästä auditointikierroksesta, joka tarkistaa sisäiset kohteet, URL-sallimistolistan, kommenttien määrät ja vastaanottajien siivouksen ennen SaveAsia Delphissä
Neljä tarkistusta ajetaan juuri ennen SaveAs:ia, ja jokainen niistä havaitsee epäonnistumisen, jota kirjasto itse ei koskaan nosta
  • Kerää jokainen luonnin aikana kirjoitettu sisäinen sijainti ja varmista, että huutomerkin edellä oleva välilehden nimi on edelleen työkirjan välilehtikokoelmassa
  • Tarkista ulkoiset URL-osoitteet sallittujen mallien ja isäntien luetteloa vasten. Pelkät file://- ja UNC-polut vuotavat ympäristön yksityiskohtia ja rikkoutuvat heti, kun tiedosto poistuu verkostasi
  • Laske kommentit laskentataulukkoa kohden ja vertaa määrää siihen, mitä generaattorisi oli tarkoitus kirjoittaa. Merkinnät kaksinkertaistanut uudelleenyritys näkyy tässä, ei tarkastajan postilaatikossa
  • Poista vain sisäiseen käyttöön tarkoitetut merkinnät DeleteInRange-metodilla aina, kun vastaanottaja on organisaation ulkopuolella

Tiimit, jotka rakentavat työkirjansa tietokerroksesta, voivat liittää tämän vaiheen samaan putkivaiheeseen, joka jo tarkistaa tiedot, jolloin metatietojen tarkistus tulee mukana käytännössä ilmaiseksi. Mekaniikka on sama kuin artikkelissa tietokantakyselyjen tulosten vienti Excel-raporteiksi, mutta kohteena ovat rivien sijaan linkit ja kommentit

Yksi lainausmerkkien yksityiskohta aiheuttaa ongelmia, kun sijaintimerkkijonoja muodostetaan käsin. Välilehden nimi, jossa on välilyönti, on lainausmerkeissä sijainnin sisällä aivan kuten kaavapalkki lainaa sen: 'Quarterly Totals'!A1, ei Quarterly Totals!A1. HotXLS soveltaa samoja sääntöjä kuin kaavamoottori taulukoiden välisiin viittauksiin. Jos linkin lainaus toimii laskentataulukkokaavassa, se toimii täälläkin. Kun annat sille lainaamattoman, välilyönnin sisältävän nimen, saat saman hiljaisen kuolleen linkin, josta alussa varoitettiin

Kommentit ja hyperlinkit ovat luodun työkirjan osia, joiden perusteella tarkastajat toimivat ajattelematta asiaa kahdesti. Siksi tyhjyyteen osoittava kohde aiheuttaa todellista vahinkoa ennen kuin kukaan huomaa sitä. Rakenna tarkistusvaihe kerran, suorita se jokaiselle työkirjalle ennen toimitusta, ja tarkistustyönkulku säilyy ehjänä uudelleennimeämisten ja muunnosten läpi. Molempien, XLS- ja XLSX-julkisivujen, täydellinen API-pinta on dokumentoitu HotXLS Delphi Component -tuotesivulla