Olet rakentanut yhden taulukon täydelliseksi. Ylätunnisteen alue on yhdistetty, sarakkeiden leveydet sopivat tietoon, kaksi ylintä riviä on kiinnitetty (frozen), tulostusalue ja marginaalit on asetettu siistiä A4-vientiä varten, ja välilehti on väritetty, jotta talousosasto löytää sen helposti. Nyt raporttiin tarvitaan kaksitoista tällaista taulukkoa, yksi kullekin alueelle, jokainen alkaen samasta asettelusta. Tämän taulukon rakentaminen koodissa kaksitoista kertaa uudelleen on tapa, jolla hienovaraiset erot hiipivät mukaan: alue 7 saa pisteen verran kapeamman sarakkeen, alue 11 menettää rivien kiinnityksen, eikä kukaan huomaa sitä ennen kuin PDF laskeutuu esimiehen työpöydälle. Se mitä todella haluat, on ohjelmallinen versio Excelin oikean klikkauksen "Siirrä tai kopioi, Luo kopio" -toiminnosta: ota valmis taulukko ja monista siitä riippumattomia kopioita
HotXLS:n XLSX-moottori, joka on alkuperäinen Delphi- ja C++Builder-kirjasto Excel-tiedostojen lukemiseen ja kirjoittamiseen ilman itse Excelin automatisointia, osasi jo siirtää taulukoita, poistaa niitä ja kopioida solualueita taulukosta toiseen. Se, mitä se ei pystynyt tekemään ennen versiota v2.91.0, oli koko laskentataulukon kloonaaminen yhdellä kutsulla. Tämä julkaisu lisää kaksi sisääntulopistettä: TXLSXWorksheet.CopyFrom, joka kopioi taulukkotason tilan laskentataulukosta toiseen, ja TXLSXSheets.Duplicate, joka lisää uuden taulukon ja suorittaa CopyFrom-metodin puolestasi. Mielenkiintoista ei ole se, että se kopioi asioita. Se on se tietoinen raja, joka on vedetty syväkopioitavan ja matalakopioitavan välille, ja miksi tuo raja on siinä missä se on
Yksi kutsu valmiin taulukon kloonaamiseksi
Korkean tason operaatio on Duplicate. Anna sille lähdetaulukon 1-pohjainen indeksi, ja se palauttaa upouuden laskentataulukon, joka peilaa alkuperäisen asettelua ja tietoja. Indeksikäytäntö vastaa XLSX-puolen Items[]-kokoelmaa, joten ensimmäinen taulukko on indeksi 1, ei 0; välitä alueen ulkopuolella oleva indeksi, ja saat tulokseksi arvon nil poikkeuksen sijaan. Tämä on sama epäonnistumissopimus, jota loputkin XLSX-taulukkokokoelmasta noudattavat
var
Book: TXLSXWorkbook;
Template, Copy: TXLSXWorksheet;
begin
Book := TXLSXWorkbook.Create;
try
Template := Book.Sheets.Add('Template');
Template.Cells[1, 1].Value := 'Quarterly Statement';
Template.Range['A1:C1'].Merge;
Template.ColWidth[1] := 18;
Template.FreezePanes(2, 1); // freeze top row + first column
Template.TabColorIsAuto := False;
Template.TabColor := $FF1F4E79;
// Clone with an explicit name...
Copy := Book.Sheets.Duplicate(1, 'Region-North');
// ...or let it pick the Excel-style default name.
Copy := Book.Sheets.Duplicate(1); // -> "Template (2)"
Book.SaveAs('regions.xlsx');
finally
Book.Free;
end;
end;
Tässä koodinpätkässä on kaksi huomionarvoista seikkaa. Ensinnäkin FreezePanes ottaa argumenttinsa rivi ensin -järjestyksessä, FreezePanes(ARow, ACol), jotta se vastaa Cells[Row, Col]-indeksointia; moniste perii tarkan kiinnitysrajauksen. Toiseksi metodin nimi on Duplicate eikä ilmeisempi Copy, mikä ei johdu tyylillisistä mieltymyksistä. Copy on System-yksikön standardi rutiini, jota käytetään jatkuvasti merkkijonoille ja dynaamisille taulukoille. Luokan Copy-metodi varjostaisi sitä metodien rungoissa ja loisi juuri sellaisen tulkinnanvaraisuuden, joka aiheuttaa ongelmia myöhemmin. Duplicate ohittaa tämän ongelman kokonaan ja näyttää selkeältä kutsupaikassa
Oletusnimi noudattaa Excelin omaa sääntöä
Kun kutsut yhden argumentin ylikuormitusta tai välität tyhjän nimimerkkijonon, uusi taulukko nimetään lähteen mukaan (2)-päätteellä, ja pääte kasvaa, kunnes nimi on yksilöllinen. Monista Template-taulukko kerran ja saat nimen Template (2); monista se uudelleen ja saat nimen Template (3), koska Template (2) on jo varattu. Tämä peilaa nimiä, joita Excel itse luo "Luo kopio" -komennollaan, joten koodisi tuottama työkirja näyttää siltä, mitä käyttäjä odottaisi käsin monistetulta taulukolta. Yksilöllisyystarkistus ajetaan reaaliaikaista taulukkokokoelmaa vasten, mikä tarkoittaa, että se huomioi myös käsin luomasi nimet, ei vain aiemmista monistuksista tulleita
Jos olet luomassa yhden taulukon alueelle tai kuukaudelle, käytä sen sijaan nimenomaista nimen ylikuormitusta. Ennalta arvattava Region-North- ja Region-South-kaava on helpompi käsitellä myöhemmin kuin jono (2)- ja (3)-päätteitä, ja se pitää määritellyt nimet sekä taulukoiden väliset kaavat luettavina
Mitä CopyFrom syväkopioi
Konepellin alla Duplicate lisää taulukon ja kutsuu sitten CopyFrom(ASource)-metodia, jota voit myös kutsua suoraan, kun haluat kloonata taulukon jo aiemmin luomasi taulukon päälle. CopyFrom suojautuu kahdelta degeneroituneelta tapaukselta heti alussa: kopiointi nil-arvosta tai taulukon kopiointi itseensä palauttavat heti tekemättä mitään. Kaikki tämän jälkeen on itse kopiointia, ja se on tarkoituksellisen laajaa
Solutieto tulee ensin. CopyFrom pyytää lähteeltä sen UsedRange-alueen eli solujen ja yhdistettyjen alueiden tiukan rajoituslaatikon, ja käyttää olemassa olevaa CopyRangeTo-koneistoa viedäkseen jokaisen arvon, kaavan ja solukohtaisen tyyli-indeksin kohteeseen alkaen solusta A1. Solujen lisäksi se toistaa koko taulukkotason tilan kerroksen, joka tekee pohjasta valmiin näköisen:
- Yhdistetyt alueet, jotka luodaan uudelleen koordinaattien mukaan, jotta otsikkoalue kattaa saman suorakulmion
- Sarakkeiden leveydet ja rivien korkeudet, sekä piilotettujen, suljettujen ja jäsennystason (outline-level) luettelot, jotka kopioidaan sellaisenaan niin, että ei-oletusrivit ja -sarakkeet linjautuvat täsmälleen
- Kiinnitetyt ruudut ja näkymätila: zoomaustaso, ruudukon ja nolla-arvojen näyttö, oikealta vasemmalle -suunta ja näkymätyyppi
- Suojaustila sen sarakkeilla ja solujen käyttöoikeuksilla, jotta lukittu pohja pysyy lukittuna samalla tavalla
- Koko sivunasetusten lohko: marginaalit, suunta, paperikoko, skaalaus ja sivulle sovittaminen, tulostusalue, tulostusotsikot, ylä- ja alatunnisteet sekä tulostusruudukko- ja tulostusotsikkoliput
- AutoFilter-alue, välilehden väri ja taulukon näkyvyys
Tulos on taulukko, joka tulostuu, suodattaa ja esittäytyy identtisesti lähteensä kanssa. Ja koska solut, yhdistykset ja mittaluettelot luodaan fyysisesti uudelleen uudelle sivulle sen sijaan, että ne olisivat aliaksia, moniste on täysin itsenäinen. Kirjoita arvo 999 kopion soluun, ja lähde säilyttää alkuperäisen arvonsa. Tämä itsenäisyys on kloonin tärkein ominaisuus rinnakkaisia alueraportteja varten, ja mukana toimitettu SheetCopy-demo vahvistaa tämän nimenomaisesti
Mitä se jättää matalaksi (shallow) ja miksi
Sitten se rehellinen osuus. Kaavioita, upotettuja kuvia, XLSX-taulukoita, tiedon oikeellisuustarkistuksia (data validations) ja ehdollisen muotoilun sääntöjä ei kopioida. Tämä on dokumentoitu, tietoinen raja eikä unohdus, ja syy on hyvä ymmärtää, jotta voit suunnitella asiat sen ympärille sen sijaan, että yllättyisit siitä
Jokainen näistä kokoelmista sisältää identiteettejä ja viitteitä, jotka eivät selviä yksinkertaisesta kenttien kopioinnista. Kaavio osoittaa lähdetietoalueeseen ja omistaa piirustusyhteyden (drawing relationship) OOXML-paketissa; objektin kloonaaminen ilman yhteyden ja sarjaviitteiden uudelleenkartoitusta tuottaa kaavion, joka renderöityy väärää tietoa vasten, tai paketin, jonka Excel ilmoittaa vaativan korjausta. Taulukolla on nimi, jonka on oltava yksilöllinen työkirjassa, tiettyihin sarakkeisiin sidottu otsikkorivi ja oma automaattisesti luotu yhteys. Ehdolliset muotoilut ja oikeellisuustarkistukset kiinnittyvät koordinaattialueisiin ja voivat oikeellisuustarkistuksen tapauksessa viitata muihin alueisiin kaavalla. Minkä tahansa näistä syväkopiointi oikein tarkoittaa viitteiden uudelleenkirjoittamista ja uusien identiteettien luomista, mikä on todellista työtä todellisilla virhemahdollisuuksilla. Sen tekeminen puolitiessä, kopioimalla objekti mutta ei sen viitteitä, on huonompi vaihtoehto kuin kopioimatta jättäminen: se tuottaa tiedoston, joka avautuu korjauskehotteella ja kadottaa hiljaisesti sisältöä. Siksi moottori kopioi asiat, jotka se voi kopioida siististi, ja jättää viitteitä sisältävät kokoelmat kutsujalle, joka tietää, mihin kohteen tulisi osoittaa
Käytännössä tämä tarkoittaa sitä, että monipuolisemman pohjan työnkulku on seuraava: monista taulukko solujen, asettelun ja tulostusasetusten saamiseksi, ja rakenna sitten kaavio, taulukko, tarkistukset tai ehdolliset muotoilut uudelleen kopioon samalla API:lla, jolla loit ne ensimmäisen kerran. Koska luot ne uudelleen kopion omia alueita vasten, viitteet muodostuvat rakenteellisesti oikein. Jos kaavio lukee aluetta A1:C10, lisää kopioon uusi kaavio, joka osoittaa kopion alueeseen A1:C10; jos haluat suodattimen (AutoFilter) olevan toiminnassa, huomaa että suodattimen alue siirtyy kopioinnissa, joten sinun tarvitsee vain soveltaa sarakekriteerit uudelleen. Ehdollisen muotoilun ja tiedon oikeellisuustarkistuksen säännöt lisäisit uudelleen samoilla kutsulla, jotka on kuvattu artikkelissa yhdistetyistä soluista ja raporttipohjien asettelusta, joka käy läpi yhdistelmätaulukon ja aluemallin, jonka kopio perii
Mihin monistaminen sopii raportointiputkessa
Laskentataulukon monistaminen on luonnollinen kumppani paikkamerkkipohjaiselle (placeholder-driven) luonnille. Tunnusankkuroitu lähestymistapa oppaassa mallipohjaisesta raporttien luonnista Delphissä ratkaisee ongelman tietojen kirjoittamisesta asetteluun, jota muut muokkaavat; monistaminen ratkaisee ongelman saman asettelun tarvitsemisesta useita kertoja yhdessä työkirjassa. Yhdistä ne, niin kaava on siisti: säilytä yksi koskematon Template-taulukko tunnuksineen, yhdistyksineen ja sivunasetuksineen, ja kutsu sitten jokaiselle alueelle tai ajanjaksolle Duplicate-metodia, täytä kloonin tunnukset kyseisellä data-siivulla ja jatka eteenpäin. Alkuperäinen malli ei koskaan muutu, joten se säilyy luotettavana lähteenä seuraavalle kloonille, ja jokainen tulostetaulukko alkaa tavuittain identtisestä asettelusta
Yksi järjestystä koskeva huomautus säästää monilta sekaannuksilta. Monista taulukko ennen kuin kaadat tietoja siihen, älä sen jälkeen. Mallipohjan tulisi sisältää rakenne ja muotoilu, ei viime neljänneksen lukuja, ja tyhjän muotoillun taulukon kloonaaminen tarkoittaa, että jokainen moniste alkaa puhtaalta pöydältä. Jos monistat taulukon, joka jo sisältää tietoja, kyseiset tiedot tulevat mukana, koska CopyFrom kopioi käytetyn alueen uskollisesti. Tämä on toisinaan sitä mitä halutaan, mutta jakeluraportille (fan-out report) se ei yleensä sovi
Nopea varmistustapa
Koska syvä- ja matalakopion välinen ero on näkymätön, ellet etsi sitä, rakenna viisirivinen tarkistus työhön sen sijaan, että luottaisit kaiken siirtyneen. Monistamisen jälkeen lue takaisin rakenteelliset signaalit, jotka kloonin pitäisi periä, ja varmista niiden täsmäävän lähteen kanssa
Copy := Book.Sheets.Duplicate(1, 'Region-North');
WriteLn(Format('merged=%d colA=%.1f freezeRow=%d tabAuto=%d',
[Copy.MergedCells.Count, Copy.ColWidth[1],
Copy.FreezeRow, Integer(Copy.TabColorIsAuto)]));
// Prove independence: mutate the copy, confirm the source is untouched.
Copy.Cells[2, 2].Value := 999;
// Template.Cells[2, 2].Value is still whatever it was.
Yhdistelmien määrä, sarakkeen leveys, kiinnitetty rivi ja välilehden värilippu kertovat, että kopioitava kerros todella siirtyi. Erikseen missä tahansa taulukossa, joka sisälsi kaavion, taulukon, tarkistuksia tai ehdollisia muotoiluja, käsittele näitä uudelleenrakennettavien asioiden listana kopiossa: niiden puuttuminen on suunniteltua, ja korjaus vaatii muutaman kutsun, ei virheraporttia. Tämä ajatusmalli – syvä siellä missä se on turvallista, ja matala siellä missä viitteet rikkoutuisivat – on koko tarina siitä, miten tätä ominaisuutta käytetään hyvin
Laskentataulukon monistaminen ja tässä kuvattu CopyFrom-sivutilan kopiointi toimitetaan alkuperäisen HotXLS-komponentti-tuotteen versiossa v2.91.0 yhdessä ajettavan SheetCopy-esimerkin kanssa, joka testaa kloonaa-ja-muuta-syklin alusta loppuun